Add touch event support to wayland plugin.
[profile/ivi/qtwayland.git] / src / plugins / platforms / wayland / qwaylandinputdevice.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the plugins of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qwaylandinputdevice.h"
43
44 #include "qwaylandintegration.h"
45 #include "qwaylandwindow.h"
46 #include "qwaylandbuffer.h"
47
48 #include <QtGui/private/qpixmap_raster_p.h>
49 #include <QtGui/QPlatformWindow>
50 #include <QDebug>
51
52 #include <unistd.h>
53 #include <fcntl.h>
54
55 #ifndef QT_NO_WAYLAND_XKB
56 #include <X11/extensions/XKBcommon.h>
57 #include <X11/keysym.h>
58 #endif
59
60 //#define POINT_DEBUG
61
62 QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display,
63                                          uint32_t id)
64     : mQDisplay(display)
65     , mDisplay(display->wl_display())
66     , mInputDevice(wl_input_device_create(mDisplay, id, 1))
67     , mPointerFocus(NULL)
68     , mKeyboardFocus(NULL)
69     , mButtons(0)
70     , mTouchState(QEvent::TouchBegin)
71 {
72     wl_input_device_add_listener(mInputDevice,
73                                  &inputDeviceListener,
74                                  this);
75     wl_input_device_set_user_data(mInputDevice, this);
76
77 #ifndef QT_NO_WAYLAND_XKB
78     struct xkb_rule_names names;
79     names.rules = "evdev";
80     names.model = "pc105";
81     names.layout = "us";
82     names.variant = "";
83     names.options = "";
84
85     mXkb = xkb_compile_keymap_from_rules(&names);
86 #endif
87 }
88
89 void QWaylandInputDevice::handleWindowDestroyed(QWaylandWindow *window)
90 {
91     if (window == mPointerFocus)
92         mPointerFocus = 0;
93     if (window == mKeyboardFocus)
94         mKeyboardFocus = 0;
95 }
96
97 void QWaylandInputDevice::inputHandleMotion(void *data,
98                                             struct wl_input_device *input_device,
99                                             uint32_t time,
100                                             int32_t x, int32_t y,
101                                             int32_t surface_x, int32_t surface_y)
102 {
103     Q_UNUSED(input_device);
104     QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
105     QWaylandWindow *window = inputDevice->mPointerFocus;
106
107     if (window == NULL) {
108         /* We destroyed the pointer focus surface, but the server
109          * didn't get the message yet. */
110         return;
111     }
112
113     inputDevice->mSurfacePos = QPoint(surface_x, surface_y);
114     inputDevice->mGlobalPos = QPoint(x, y);
115     inputDevice->mTime = time;
116     QWindowSystemInterface::handleMouseEvent(window->widget(),
117                                              time,
118                                              inputDevice->mSurfacePos,
119                                              inputDevice->mGlobalPos,
120                                              inputDevice->mButtons);
121 }
122
123 void QWaylandInputDevice::inputHandleButton(void *data,
124                                             struct wl_input_device *input_device,
125                                             uint32_t time, uint32_t button, uint32_t state)
126 {
127     Q_UNUSED(input_device);
128     QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
129     QWaylandWindow *window = inputDevice->mPointerFocus;
130     Qt::MouseButton qt_button;
131
132     if (window == NULL) {
133         /* We destroyed the pointer focus surface, but the server
134          * didn't get the message yet. */
135         return;
136     }
137
138     switch (button) {
139     case 272:
140         qt_button = Qt::LeftButton;
141         break;
142     case 273:
143         qt_button = Qt::RightButton;
144         break;
145     case 274:
146         qt_button = Qt::MiddleButton;
147         break;
148     default:
149         return;
150     }
151
152     if (state)
153         inputDevice->mButtons |= qt_button;
154     else
155         inputDevice->mButtons &= ~qt_button;
156
157     inputDevice->mTime = time;
158     QWindowSystemInterface::handleMouseEvent(window->widget(),
159                                              time,
160                                              inputDevice->mSurfacePos,
161                                              inputDevice->mGlobalPos,
162                                              inputDevice->mButtons);
163 }
164
165 #ifndef QT_NO_WAYLAND_XKB
166 static Qt::KeyboardModifiers translateModifiers(int s)
167 {
168     const uchar qt_alt_mask = XKB_COMMON_MOD1_MASK;
169     const uchar qt_meta_mask = XKB_COMMON_MOD4_MASK;
170
171     Qt::KeyboardModifiers ret = 0;
172     if (s & XKB_COMMON_SHIFT_MASK)
173         ret |= Qt::ShiftModifier;
174     if (s & XKB_COMMON_CONTROL_MASK)
175         ret |= Qt::ControlModifier;
176     if (s & qt_alt_mask)
177         ret |= Qt::AltModifier;
178     if (s & qt_meta_mask)
179         ret |= Qt::MetaModifier;
180
181     return ret;
182 }
183
184 static uint32_t translateKey(uint32_t sym, char *string, size_t size)
185 {
186     Q_UNUSED(size);
187     string[0] = '\0';
188
189     switch (sym) {
190     case XK_Escape:             return Qt::Key_Escape;
191     case XK_Tab:                return Qt::Key_Tab;
192     case XK_ISO_Left_Tab:       return Qt::Key_Backtab;
193     case XK_BackSpace:          return Qt::Key_Backspace;
194     case XK_Return:             return Qt::Key_Return;
195     case XK_Insert:             return Qt::Key_Insert;
196     case XK_Delete:             return Qt::Key_Delete;
197     case XK_Clear:              return Qt::Key_Delete;
198     case XK_Pause:              return Qt::Key_Pause;
199     case XK_Print:              return Qt::Key_Print;
200
201     case XK_Home:               return Qt::Key_Home;
202     case XK_End:                return Qt::Key_End;
203     case XK_Left:               return Qt::Key_Left;
204     case XK_Up:                 return Qt::Key_Up;
205     case XK_Right:              return Qt::Key_Right;
206     case XK_Down:               return Qt::Key_Down;
207     case XK_Prior:              return Qt::Key_PageUp;
208     case XK_Next:               return Qt::Key_PageDown;
209
210     case XK_Shift_L:            return Qt::Key_Shift;
211     case XK_Shift_R:            return Qt::Key_Shift;
212     case XK_Shift_Lock:         return Qt::Key_Shift;
213     case XK_Control_L:          return Qt::Key_Control;
214     case XK_Control_R:          return Qt::Key_Control;
215     case XK_Meta_L:             return Qt::Key_Meta;
216     case XK_Meta_R:             return Qt::Key_Meta;
217     case XK_Alt_L:              return Qt::Key_Alt;
218     case XK_Alt_R:              return Qt::Key_Alt;
219     case XK_Caps_Lock:          return Qt::Key_CapsLock;
220     case XK_Num_Lock:           return Qt::Key_NumLock;
221     case XK_Scroll_Lock:        return Qt::Key_ScrollLock;
222     case XK_Super_L:            return Qt::Key_Super_L;
223     case XK_Super_R:            return Qt::Key_Super_R;
224     case XK_Menu:               return Qt::Key_Menu;
225
226     default:
227         string[0] = sym;
228         string[1] = '\0';
229         return toupper(sym);
230     }
231 }
232 #endif
233
234 void QWaylandInputDevice::inputHandleKey(void *data,
235                                          struct wl_input_device *input_device,
236                                          uint32_t time, uint32_t key, uint32_t state)
237 {
238 #ifndef QT_NO_WAYLAND_XKB
239     Q_UNUSED(input_device);
240     QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
241     QWaylandWindow *window = inputDevice->mKeyboardFocus;
242     uint32_t code, sym, level;
243     Qt::KeyboardModifiers modifiers;
244     QEvent::Type type;
245     char s[2];
246
247     if (window == NULL) {
248         /* We destroyed the keyboard focus surface, but the server
249          * didn't get the message yet. */
250         return;
251     }
252
253     code = key + inputDevice->mXkb->min_key_code;
254
255     level = 0;
256     if (inputDevice->mModifiers & Qt::ShiftModifier &&
257         XkbKeyGroupWidth(inputDevice->mXkb, code, 0) > 1)
258         level = 1;
259
260     sym = XkbKeySymEntry(inputDevice->mXkb, code, level, 0);
261
262     modifiers = translateModifiers(inputDevice->mXkb->map->modmap[code]);
263
264     if (state) {
265         inputDevice->mModifiers |= modifiers;
266         type = QEvent::KeyPress;
267     } else {
268         inputDevice->mModifiers &= ~modifiers;
269         type = QEvent::KeyRelease;
270     }
271
272     sym = translateKey(sym, s, sizeof s);
273
274     if (window) {
275         QWindowSystemInterface::handleKeyEvent(window->widget(),
276                                                time, type, sym,
277                                                inputDevice->mModifiers,
278                                                QString::fromLatin1(s));
279     }
280 #endif
281 }
282
283 void QWaylandInputDevice::inputHandlePointerFocus(void *data,
284                                                   struct wl_input_device *input_device,
285                                                   uint32_t time, struct wl_surface *surface,
286                                                   int32_t x, int32_t y, int32_t sx, int32_t sy)
287 {
288     Q_UNUSED(input_device);
289     Q_UNUSED(x);
290     Q_UNUSED(y);
291     Q_UNUSED(sx);
292     Q_UNUSED(sy);
293     QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
294     QWaylandWindow *window;
295
296     if (inputDevice->mPointerFocus) {
297         window = inputDevice->mPointerFocus;
298         QWindowSystemInterface::handleLeaveEvent(window->widget());
299         inputDevice->mPointerFocus = NULL;
300     }
301
302     if (surface) {
303         window = (QWaylandWindow *) wl_surface_get_user_data(surface);
304         QWindowSystemInterface::handleEnterEvent(window->widget());
305         inputDevice->mPointerFocus = window;
306     }
307
308     inputDevice->mTime = time;
309 }
310
311 void QWaylandInputDevice::inputHandleKeyboardFocus(void *data,
312                                                    struct wl_input_device *input_device,
313                                                    uint32_t time,
314                                                    struct wl_surface *surface,
315                                                    struct wl_array *keys)
316 {
317 #ifndef QT_NO_WAYLAND_XKB
318     Q_UNUSED(input_device);
319     Q_UNUSED(time);
320     QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
321     QWaylandWindow *window;
322     uint32_t *k, *end;
323     uint32_t code;
324
325     end = (uint32_t *) ((char *) keys->data + keys->size);
326     inputDevice->mModifiers = 0;
327     for (k = (uint32_t *) keys->data; k < end; k++) {
328         code = *k + inputDevice->mXkb->min_key_code;
329         inputDevice->mModifiers |=
330             translateModifiers(inputDevice->mXkb->map->modmap[code]);
331     }
332
333     if (surface) {
334         window = (QWaylandWindow *) wl_surface_get_user_data(surface);
335         inputDevice->mKeyboardFocus = window;
336         QWindowSystemInterface::handleWindowActivated(window->widget());
337     } else {
338         inputDevice->mKeyboardFocus = NULL;
339         QWindowSystemInterface::handleWindowActivated(0);
340     }
341 #endif
342 }
343
344 void QWaylandInputDevice::inputHandleTouchDown(void *data,
345                                                struct wl_input_device *wl_input_device,
346                                                uint32_t time,
347                                                int id,
348                                                int x,
349                                                int y)
350 {
351     QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
352     inputDevice->handleTouchPoint(id, x, y, Qt::TouchPointPressed);
353 }
354
355 void QWaylandInputDevice::inputHandleTouchUp(void *data,
356                                              struct wl_input_device *wl_input_device,
357                                              uint32_t time,
358                                              int id)
359 {
360     QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
361     inputDevice->handleTouchPoint(id, 0, 0, Qt::TouchPointReleased);
362 }
363
364 void QWaylandInputDevice::inputHandleTouchMotion(void *data,
365                                                  struct wl_input_device *wl_input_device,
366                                                  uint32_t time,
367                                                  int id,
368                                                  int x,
369                                                  int y)
370 {
371     QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
372     inputDevice->handleTouchPoint(id, x, y, Qt::TouchPointMoved);
373 }
374
375 void QWaylandInputDevice::handleTouchPoint(int id, int x, int y, Qt::TouchPointState state)
376 {
377     QWindowSystemInterface::TouchPoint tp;
378
379     // Find out the coordinates for Released events.
380     bool coordsOk = false;
381     if (state == Qt::TouchPointReleased)
382         for (int i = 0; i < mPrevTouchPoints.count(); ++i)
383             if (mPrevTouchPoints.at(i).id == id) {
384                 tp.area = mPrevTouchPoints.at(i).area;
385                 coordsOk = true;
386                 break;
387             }
388
389     if (!coordsOk) {
390         // x and y are surface relative.
391         // We need a global (screen) position.
392
393         QWaylandWindow *win = mPointerFocus;
394         if (!win)
395             win = mKeyboardFocus;
396 #ifdef POINT_DEBUG
397         qDebug() << "surface relative coords" << x << y << "using window" << win;
398 #endif
399         if (!win)
400             return;
401
402         QRect winRect = win->geometry();
403
404         // Get a normalized position (0..1).
405         const qreal nx = x / qreal(winRect.width());
406         const qreal ny = y / qreal(winRect.height());
407         tp.normalPosition = QPointF(nx, ny);
408
409         // Map to screen.
410         QPlatformScreen *screen = mQDisplay->screens().at(0);
411         QRect screenRect = screen->geometry();
412         x = int(nx * screenRect.width());
413         y = int(ny * screenRect.height());
414
415 #ifdef POINT_DEBUG
416         qDebug() << "normalized position" << nx << ny
417                  << "win rect" << winRect << "screen rect" << screenRect;
418         qDebug() << "mapped to screen position" << x << y;
419 #endif
420
421         tp.area = QRectF(x, y, 1, 1);
422     }
423
424     tp.state = state;
425     tp.id = id;
426     tp.isPrimary = mTouchPoints.isEmpty();
427     tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1;
428     mTouchPoints.append(tp);
429 }
430
431 void QWaylandInputDevice::inputHandleTouchFrame(void *data, struct wl_input_device *wl_input_device)
432 {
433     QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
434     inputDevice->handleTouchFrame();
435 }
436
437 void QWaylandInputDevice::handleTouchFrame()
438 {
439     // Copy all points, that are in the previous but not in the current list, as stationary.
440     for (int i = 0; i < mPrevTouchPoints.count(); ++i) {
441         const QWindowSystemInterface::TouchPoint &prevPoint(mPrevTouchPoints.at(i));
442         if (prevPoint.state == Qt::TouchPointReleased)
443             continue;
444         bool found = false;
445         for (int j = 0; j < mTouchPoints.count(); ++j)
446             if (mTouchPoints.at(j).id == prevPoint.id) {
447                 found = true;
448                 break;
449             }
450         if (!found) {
451             QWindowSystemInterface::TouchPoint p = prevPoint;
452             p.state = Qt::TouchPointStationary;
453             mTouchPoints.append(p);
454         }
455     }
456
457     if (mTouchPoints.isEmpty()) {
458         mPrevTouchPoints.clear();
459         return;
460     }
461
462 #ifdef POINT_DEBUG
463         qDebug() << mTouchPoints.count() << "touchpoints, event type" << mTouchState;
464         for (int i = 0; i < mTouchPoints.count(); ++i)
465             qDebug() << "    " << mTouchPoints[i].id << mTouchPoints[i].state << mTouchPoints[i].area;
466 #endif
467
468     QWindowSystemInterface::handleTouchEvent(0, mTouchState, QTouchEvent::TouchScreen, mTouchPoints);
469
470     bool allReleased = true;
471     for (int i = 0; i < mTouchPoints.count(); ++i)
472         if (mTouchPoints.at(i).state != Qt::TouchPointReleased) {
473             allReleased = false;
474             break;
475         }
476
477     mPrevTouchPoints = mTouchPoints;
478     mTouchPoints.clear();
479
480     if (allReleased) {
481 #ifdef POINT_DEBUG
482         qDebug() << mTouchPoints.count() << "touchpoints, event type" << QEvent::TouchEnd;
483 #endif
484         QWindowSystemInterface::handleTouchEvent(0, QEvent::TouchEnd, QTouchEvent::TouchScreen, mTouchPoints);
485         mTouchState = QEvent::TouchBegin;
486         mPrevTouchPoints.clear();
487     } else if (mTouchState == QEvent::TouchBegin)
488         mTouchState = QEvent::TouchUpdate;
489 }
490
491 void QWaylandInputDevice::inputHandleTouchCancel(void *data, struct wl_input_device *wl_input_device)
492 {
493 }
494
495 const struct wl_input_device_listener QWaylandInputDevice::inputDeviceListener = {
496     QWaylandInputDevice::inputHandleMotion,
497     QWaylandInputDevice::inputHandleButton,
498     QWaylandInputDevice::inputHandleKey,
499     QWaylandInputDevice::inputHandlePointerFocus,
500     QWaylandInputDevice::inputHandleKeyboardFocus,
501     QWaylandInputDevice::inputHandleTouchDown,
502     QWaylandInputDevice::inputHandleTouchUp,
503     QWaylandInputDevice::inputHandleTouchMotion,
504     QWaylandInputDevice::inputHandleTouchFrame,
505     QWaylandInputDevice::inputHandleTouchCancel
506 };
507
508 void QWaylandInputDevice::attach(QWaylandBuffer *buffer, int x, int y)
509 {
510     wl_input_device_attach(mInputDevice, mTime, buffer->buffer(), x, y);
511 }