Fix for uninitialized member in QWaylandCursor
[profile/ivi/qtwayland.git] / src / plugins / platforms / wayland / qwaylandintegration.cpp
1 #include "qfontconfigdatabase.h"
2
3 #include <QImageReader>
4 #include <QWindowSystemInterface>
5 #include <QPlatformCursor>
6 #include <QPaintEngine>
7
8 #include <QtGui/QPlatformWindowFormat>
9
10 #include <QtGui/private/qpixmap_raster_p.h>
11 #include <QtGui/QPlatformWindow>
12
13 #include "qwaylandintegration.h"
14 #include "qwaylandwindowsurface.h"
15
16 #include <unistd.h>
17 #include <fcntl.h>
18
19 extern "C" {
20 #include <xf86drm.h>
21 }
22
23 class QWaylandCursor : QPlatformCursor {
24 public:
25     QWaylandCursor(QWaylandDisplay *display,
26                    QPlatformScreen *screen)
27         : QPlatformCursor(screen)
28         , mBuffer(0), mDisplay(display) { }
29
30     void changeCursor(QCursor *cursor, QWidget *widget);
31     QWaylandShmBuffer *mBuffer;
32     QWaylandDisplay *mDisplay;
33 };
34
35 #define DATADIR "/usr/share"
36
37 static const struct pointer_image {
38     const char *filename;
39     int hotspot_x, hotspot_y;
40 } pointer_images[] = {
41     /* FIXME: Half of these are wrong... */
42     /* Qt::ArrowCursor */
43     { DATADIR "/wayland/left_ptr.png",                  10,  5 },
44     /* Qt::UpArrowCursor */
45     { DATADIR "/wayland/top_side.png",                  18,  8 },
46     /* Qt::CrossCursor */
47     { DATADIR "/wayland/top_side.png",                  18,  8 },
48     /* Qt::WaitCursor */
49     { DATADIR "/wayland/top_side.png",                  18,  8 },
50     /* Qt::IBeamCursor */
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 },
62     /* Qt::BlankCursor */
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 },
74     /* Qt::BusyCursor */
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 },
86 };
87
88 void QWaylandCursor::changeCursor(QCursor *cursor, QWidget *widget)
89 {
90     const struct pointer_image *p;
91
92     if (widget == NULL)
93         return;
94
95     p = NULL;
96
97     switch (cursor->shape()) {
98     case Qt::ArrowCursor:
99         p = &pointer_images[cursor->shape()];
100         break;
101     case Qt::UpArrowCursor:
102     case Qt::CrossCursor:
103     case Qt::WaitCursor:
104         break;
105     case Qt::IBeamCursor:
106         p = &pointer_images[cursor->shape()];
107         break;
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 */
114         break;
115     case Qt::SplitVCursor:
116     case Qt::SplitHCursor:
117     case Qt::PointingHandCursor:
118         p = &pointer_images[cursor->shape()];
119         break;
120     case Qt::ForbiddenCursor:
121     case Qt::WhatsThisCursor:   /* 15 */
122     case Qt::BusyCursor:
123         break;
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()];
130         break;
131
132     default:
133     case Qt::BitmapCursor:
134         break;
135     }
136
137     if (!p) {
138         p = &pointer_images[0];
139         qWarning("unhandled cursor %d", cursor->shape());
140     }
141
142     QImageReader reader(p->filename);
143
144     if (mBuffer == NULL || mBuffer->mImage.size() != reader.size()) {
145         if (mBuffer)
146             delete mBuffer;
147
148         mBuffer = new QWaylandShmBuffer(mDisplay, reader.size(),
149                                         QImage::Format_ARGB32);
150     }
151
152     reader.read(&mBuffer->mImage);
153
154     mDisplay->setCursor(mBuffer, p->hotspot_x, p->hotspot_y);
155 }
156
157 void QWaylandDisplay::setCursor(QWaylandBuffer *buffer, int32_t x, int32_t y)
158 {
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);
164     }
165 }
166
167 struct wl_surface *QWaylandDisplay::createSurface()
168 {
169     return wl_compositor_create_surface(mCompositor);
170 }
171
172 struct wl_buffer *QWaylandDisplay::createShmBuffer(int fd,
173                                                    int width, int height,
174                                                    uint32_t stride,
175                                                    struct wl_visual *visual)
176 {
177     return wl_shm_create_buffer(mShm, fd, width, height, stride, visual);
178 }
179
180 struct wl_buffer *QWaylandDisplay::createDrmBuffer(int name,
181                                                    int width, int height,
182                                                    uint32_t stride,
183                                                    struct wl_visual *visual)
184 {
185     return wl_drm_create_buffer(mDrm, name, width, height, stride, visual);
186 }
187
188 struct wl_visual *QWaylandDisplay::rgbVisual()
189 {
190     return wl_display_get_rgb_visual(mDisplay);
191 }
192
193 struct wl_visual *QWaylandDisplay::argbVisual()
194 {
195     return wl_display_get_argb_visual(mDisplay);
196 }
197
198 struct wl_visual *QWaylandDisplay::argbPremultipliedVisual()
199 {
200     return wl_display_get_premultiplied_argb_visual(mDisplay);
201 }
202
203 void QWaylandDisplay::drmHandleDevice(void *data,
204                                       struct wl_drm *drm, const char *device)
205 {
206     Q_UNUSED(drm);
207     QWaylandDisplay *qwd = (QWaylandDisplay *) data;
208     drm_magic_t magic;
209
210     qwd->mDeviceName = strdup(device);
211
212     qwd->mFd = open(qwd->mDeviceName, O_RDWR);
213     if (qwd->mFd < 0) {
214         qWarning("drm open failed: %m");
215         return;
216     }
217
218     if (drmGetMagic(qwd->mFd, &magic)) {
219         qWarning("DRI2: failed to get drm magic");
220         return;
221     }
222
223     wl_drm_authenticate(qwd->mDrm, magic);
224 }
225
226 void QWaylandDisplay::drmHandleAuthenticated(void *data, struct wl_drm *drm)
227 {
228     Q_UNUSED(drm);
229     QWaylandDisplay *qwd = (QWaylandDisplay *) data;
230     EGLint major, minor;
231     const char *extensions;
232
233     qwd->mEglDisplay = eglGetDRMDisplayMESA(qwd->mFd);
234     if (qwd->mEglDisplay == NULL) {
235         qWarning("failed to create display");
236         return;
237     }
238
239     if (!eglInitialize(qwd->mEglDisplay, &major, &minor)) {
240         qWarning("failed to initialize display");
241         qwd->mEglDisplay = NULL;
242         return;
243     }
244
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;
250         return;
251     }
252 }
253
254 const struct wl_drm_listener QWaylandDisplay::drmListener = {
255     QWaylandDisplay::drmHandleDevice,
256     QWaylandDisplay::drmHandleAuthenticated
257 };
258
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)
264 {
265     Q_UNUSED(data);
266     Q_UNUSED(shell);
267     Q_UNUSED(time);
268     Q_UNUSED(edges);
269     QWaylandWindow *ww = (QWaylandWindow *) wl_surface_get_user_data(surface);
270
271     ww->configure(time, edges, x, y, width, height);
272 }
273
274 const struct wl_shell_listener QWaylandDisplay::shellListener = {
275     QWaylandDisplay::shellHandleConfigure,
276 };
277
278 void QWaylandDisplay::outputHandleGeometry(void *data,
279                                            struct wl_output *output,
280                                            int32_t width, int32_t height)
281 {
282     Q_UNUSED(output);
283     QWaylandDisplay *qwd = (QWaylandDisplay *) data;
284     QWaylandScreen *screen;
285
286     screen = new QWaylandScreen();
287     screen->mGeometry = QRect(0, 0, width, height);
288     screen->mDepth = 32;
289     screen->mFormat = QImage::Format_ARGB32_Premultiplied;
290     screen->mOutput = output;
291
292     new QWaylandCursor(qwd, screen);
293
294     qwd->mScreens.append(screen);
295 }
296
297 const struct wl_output_listener QWaylandDisplay::outputListener = {
298     QWaylandDisplay::outputHandleGeometry
299 };
300
301 void QWaylandDisplay::displayHandleGlobal(struct wl_display *display,
302                                           uint32_t id,
303                                           const char *interface,
304                                           uint32_t version, void *data)
305 {
306     Q_UNUSED(version);
307     QWaylandDisplay *qwd = (QWaylandDisplay *) data;
308
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);
326     }
327 }
328
329 static void roundtripCallback(void *data)
330 {
331     bool *done = (bool *) data;
332
333     *done = true;
334 }
335
336 static void forceRoundtrip(struct wl_display *display)
337 {
338     bool done;
339
340     wl_display_sync_callback(display, roundtripCallback, &done);
341     wl_display_iterate(display, WL_DISPLAY_WRITABLE);
342     done = false;
343     while (!done)
344         wl_display_iterate(display, WL_DISPLAY_READABLE);
345 }
346
347 static const char socket_name[] = "\0wayland";
348
349 void QWaylandDisplay::eventDispatcher(void)
350 {
351     wl_display_iterate(mDisplay, WL_DISPLAY_READABLE);
352 }
353
354 int
355 QWaylandDisplay::sourceUpdate(uint32_t mask, void *data)
356 {
357     QWaylandDisplay *qwd = (QWaylandDisplay *) data;
358
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)
364         return 0;
365
366     qwd->mWriteNotifier->setEnabled(mask & WL_DISPLAY_WRITABLE);
367
368     return 0;
369 }
370
371 void QWaylandDisplay::flushRequests(void)
372 {
373     wl_display_iterate(mDisplay, WL_DISPLAY_WRITABLE);
374 }
375
376 QWaylandDisplay::QWaylandDisplay(void)
377     : mWriteNotifier(0)
378 {
379     mDisplay = wl_display_create(socket_name, sizeof socket_name);
380     if (mDisplay == NULL) {
381         fprintf(stderr, "failed to create display: %m\n");
382         return;
383     }
384
385     wl_display_add_global_listener(mDisplay,
386                                    QWaylandDisplay::displayHandleGlobal, this);
387
388     /* Process connection events. */
389     wl_display_iterate(mDisplay, WL_DISPLAY_READABLE);
390     if (!mShm || !mDeviceName)
391         forceRoundtrip(mDisplay);
392
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");
398     else
399         qDebug("EGL initialized");
400
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()));
405
406     mWriteNotifier = new QSocketNotifier(fd, QSocketNotifier::Write, this);
407     connect(mWriteNotifier,
408             SIGNAL(activated(int)), this, SLOT(flushRequests()));
409     mWriteNotifier->setEnabled(false);
410 }
411
412 QWaylandDisplay::~QWaylandDisplay(void)
413 {
414     close(mFd);
415     wl_display_destroy(mDisplay);
416 }
417
418 QWaylandIntegration::QWaylandIntegration(bool useOpenGL)
419     : mFontDb(new QFontconfigDatabase())
420     , mDisplay(new QWaylandDisplay())
421     , mUseOpenGL(useOpenGL)
422 {
423 }
424
425 QList<QPlatformScreen *>
426 QWaylandIntegration::screens() const
427 {
428     return mDisplay->screens();
429 }
430
431 QPixmapData *QWaylandIntegration::createPixmapData(QPixmapData::PixelType type) const
432 {
433     if (mUseOpenGL)
434         return new QGLPixmapData(type);
435     return new QRasterPixmapData(type);
436 }
437
438 QWaylandWindow::QWaylandWindow(QWidget *window, QWaylandDisplay *display)
439     : QPlatformWindow(window)
440     , mSurface(0)
441     , mDisplay(display)
442     , mGLContext(0)
443     , mBuffer(0)
444 {
445     static WId id = 1;
446
447     mWindowId = id++;
448 }
449
450 QWaylandWindow::~QWaylandWindow()
451 {
452     if (mGLContext)
453         delete mGLContext;
454 }
455
456 WId QWaylandWindow::winId() const
457 {
458     return mWindowId;
459 }
460
461 void QWaylandWindow::setParent(const QPlatformWindow *parent)
462 {
463     QWaylandWindow *wParent = (QWaylandWindow *)parent;
464
465     mParentWindow = wParent;
466 }
467
468 void QWaylandWindow::setVisible(bool visible)
469 {
470     if (visible) {
471         mSurface = mDisplay->createSurface();
472         wl_surface_set_user_data(mSurface, this);
473         attach(mBuffer);
474     } else {
475         wl_surface_destroy(mSurface);
476         mSurface = NULL;
477     }
478 }
479
480 void QWaylandWindow::attach(QWaylandBuffer *buffer)
481 {
482     QRect geometry = widget()->geometry();
483
484     mBuffer = buffer;
485     if (mSurface) {
486         wl_surface_attach(mSurface, mBuffer->mBuffer);
487         wl_surface_map(mSurface, geometry.x(), geometry.y(),
488                        geometry.width(), geometry.height());
489     }
490 }
491
492 void QWaylandWindow::configure(uint32_t time, uint32_t edges,
493                                int32_t x, int32_t y,
494                                int32_t width, int32_t height)
495 {
496     Q_UNUSED(time);
497     Q_UNUSED(edges);
498     QRect geometry = QRect(x, y, width, height);
499
500     QWindowSystemInterface::handleGeometryChange(widget(), geometry);
501 }
502
503 QPlatformWindow *QWaylandIntegration::createPlatformWindow(QWidget *widget, WId winId) const
504 {
505     Q_UNUSED(winId);
506     return new QWaylandWindow(widget, mDisplay);
507 }
508
509 QWindowSurface *QWaylandIntegration::createWindowSurface(QWidget *widget, WId winId) const
510 {
511     Q_UNUSED(winId);
512     Q_UNUSED(winId);
513
514     if (mUseOpenGL)
515         return new QWaylandDrmWindowSurface(widget, mDisplay);
516     return new QWaylandShmWindowSurface(widget, mDisplay);
517 }
518
519 QPlatformFontDatabase *QWaylandIntegration::fontDatabase() const
520 {
521     return mFontDb;
522 }