Prevented crash due to dangling pointer in QWaylandInputDevice.
[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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
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 <QWindowSystemInterface>
49
50 #include <QtGui/private/qpixmap_raster_p.h>
51 #include <QtGui/QPlatformWindow>
52
53 #include <unistd.h>
54 #include <fcntl.h>
55
56 #ifndef QT_NO_WAYLAND_XKB
57 #include <X11/extensions/XKBcommon.h>
58 #include <X11/keysym.h>
59 #endif
60
61 QWaylandInputDevice::QWaylandInputDevice(struct wl_display *display,
62                                          uint32_t id)
63     : mDisplay(display)
64     , mInputDevice(wl_input_device_create(display, id))
65     , mPointerFocus(NULL)
66     , mKeyboardFocus(NULL)
67     , mButtons(0)
68 {
69     wl_input_device_add_listener(mInputDevice,
70                                  &inputDeviceListener,
71                                  this);
72     wl_input_device_set_user_data(mInputDevice, this);
73
74 #ifndef QT_NO_WAYLAND_XKB
75     struct xkb_rule_names names;
76     names.rules = "evdev";
77     names.model = "pc105";
78     names.layout = "us";
79     names.variant = "";
80     names.options = "";
81
82     mXkb = xkb_compile_keymap_from_rules(&names);
83 #endif
84 }
85
86 void QWaylandInputDevice::handleWindowDestroyed(QWaylandWindow *window)
87 {
88     if (window == mPointerFocus)
89         mPointerFocus = 0;
90     if (window == mKeyboardFocus)
91         mKeyboardFocus = 0;
92 }
93
94 void QWaylandInputDevice::inputHandleMotion(void *data,
95                                             struct wl_input_device *input_device,
96                                             uint32_t time,
97                                             int32_t x, int32_t y,
98                                             int32_t surface_x, int32_t surface_y)
99 {
100     Q_UNUSED(input_device);
101     QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
102     QWaylandWindow *window = inputDevice->mPointerFocus;
103
104     inputDevice->mSurfacePos = QPoint(surface_x, surface_y);
105     inputDevice->mGlobalPos = QPoint(x, y);
106     inputDevice->mTime = time;
107     QWindowSystemInterface::handleMouseEvent(window->widget(),
108                                              time,
109                                              inputDevice->mSurfacePos,
110                                              inputDevice->mGlobalPos,
111                                              inputDevice->mButtons);
112 }
113
114 void QWaylandInputDevice::inputHandleButton(void *data,
115                                             struct wl_input_device *input_device,
116                                             uint32_t time, uint32_t button, uint32_t state)
117 {
118     Q_UNUSED(input_device);
119     QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
120     QWaylandWindow *window = inputDevice->mPointerFocus;
121     Qt::MouseButton qt_button;
122
123     switch (button) {
124     case 272:
125         qt_button = Qt::LeftButton;
126         break;
127     case 273:
128         qt_button = Qt::RightButton;
129         break;
130     case 274:
131         qt_button = Qt::MiddleButton;
132         break;
133     default:
134         return;
135     }
136
137     if (state)
138         inputDevice->mButtons |= qt_button;
139     else
140         inputDevice->mButtons &= ~qt_button;
141
142     inputDevice->mTime = time;
143     QWindowSystemInterface::handleMouseEvent(window->widget(),
144                                              time,
145                                              inputDevice->mSurfacePos,
146                                              inputDevice->mGlobalPos,
147                                              inputDevice->mButtons);
148 }
149
150 #ifndef QT_NO_WAYLAND_XKB
151 static Qt::KeyboardModifiers translateModifiers(int s)
152 {
153     const uchar qt_alt_mask = XKB_COMMON_MOD1_MASK;
154     const uchar qt_meta_mask = XKB_COMMON_MOD4_MASK;
155
156     Qt::KeyboardModifiers ret = 0;
157     if (s & XKB_COMMON_SHIFT_MASK)
158         ret |= Qt::ShiftModifier;
159     if (s & XKB_COMMON_CONTROL_MASK)
160         ret |= Qt::ControlModifier;
161     if (s & qt_alt_mask)
162         ret |= Qt::AltModifier;
163     if (s & qt_meta_mask)
164         ret |= Qt::MetaModifier;
165
166     return ret;
167 }
168
169 static uint32_t translateKey(uint32_t sym, char *string, size_t size)
170 {
171     Q_UNUSED(size);
172     string[0] = '\0';
173
174     switch (sym) {
175     case XK_Escape:             return Qt::Key_Escape;
176     case XK_Tab:                return Qt::Key_Tab;
177     case XK_ISO_Left_Tab:       return Qt::Key_Backtab;
178     case XK_BackSpace:          return Qt::Key_Backspace;
179     case XK_Return:             return Qt::Key_Return;
180     case XK_Insert:             return Qt::Key_Insert;
181     case XK_Delete:             return Qt::Key_Delete;
182     case XK_Clear:              return Qt::Key_Delete;
183     case XK_Pause:              return Qt::Key_Pause;
184     case XK_Print:              return Qt::Key_Print;
185
186     case XK_Home:               return Qt::Key_Home;
187     case XK_End:                return Qt::Key_End;
188     case XK_Left:               return Qt::Key_Left;
189     case XK_Up:                 return Qt::Key_Up;
190     case XK_Right:              return Qt::Key_Right;
191     case XK_Down:               return Qt::Key_Down;
192     case XK_Prior:              return Qt::Key_PageUp;
193     case XK_Next:               return Qt::Key_PageDown;
194
195     case XK_Shift_L:            return Qt::Key_Shift;
196     case XK_Shift_R:            return Qt::Key_Shift;
197     case XK_Shift_Lock:         return Qt::Key_Shift;
198     case XK_Control_L:          return Qt::Key_Control;
199     case XK_Control_R:          return Qt::Key_Control;
200     case XK_Meta_L:             return Qt::Key_Meta;
201     case XK_Meta_R:             return Qt::Key_Meta;
202     case XK_Alt_L:              return Qt::Key_Alt;
203     case XK_Alt_R:              return Qt::Key_Alt;
204     case XK_Caps_Lock:          return Qt::Key_CapsLock;
205     case XK_Num_Lock:           return Qt::Key_NumLock;
206     case XK_Scroll_Lock:        return Qt::Key_ScrollLock;
207     case XK_Super_L:            return Qt::Key_Super_L;
208     case XK_Super_R:            return Qt::Key_Super_R;
209     case XK_Menu:               return Qt::Key_Menu;
210
211     default:
212         string[0] = sym;
213         string[1] = '\0';
214         return toupper(sym);
215     }
216 }
217 #endif
218
219 void QWaylandInputDevice::inputHandleKey(void *data,
220                                          struct wl_input_device *input_device,
221                                          uint32_t time, uint32_t key, uint32_t state)
222 {
223 #ifndef QT_NO_WAYLAND_XKB
224     Q_UNUSED(input_device);
225     QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
226     QWaylandWindow *window = inputDevice->mKeyboardFocus;
227     uint32_t code, sym, level;
228     Qt::KeyboardModifiers modifiers;
229     QEvent::Type type;
230     char s[2];
231
232     code = key + inputDevice->mXkb->min_key_code;
233
234     level = 0;
235     if (inputDevice->mModifiers & Qt::ShiftModifier &&
236         XkbKeyGroupWidth(inputDevice->mXkb, code, 0) > 1)
237         level = 1;
238
239     sym = XkbKeySymEntry(inputDevice->mXkb, code, level, 0);
240
241     modifiers = translateModifiers(inputDevice->mXkb->map->modmap[code]);
242
243     if (state) {
244         inputDevice->mModifiers |= modifiers;
245         type = QEvent::KeyPress;
246     } else {
247         inputDevice->mModifiers &= ~modifiers;
248         type = QEvent::KeyRelease;
249     }
250
251     sym = translateKey(sym, s, sizeof s);
252
253     qWarning("keycode %d, sym %d, string %d, modifiers 0x%x",
254              code, sym, s[0], (int) inputDevice->mModifiers);
255
256     if (window) {
257         QWindowSystemInterface::handleKeyEvent(window->widget(),
258                                                time, type, sym,
259                                                inputDevice->mModifiers,
260                                                QString::fromLatin1(s));
261     }
262 #endif
263 }
264
265 void QWaylandInputDevice::inputHandlePointerFocus(void *data,
266                                                   struct wl_input_device *input_device,
267                                                   uint32_t time, struct wl_surface *surface,
268                                                   int32_t x, int32_t y, int32_t sx, int32_t sy)
269 {
270     Q_UNUSED(input_device);
271     Q_UNUSED(x);
272     Q_UNUSED(y);
273     Q_UNUSED(sx);
274     Q_UNUSED(sy);
275     QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
276     QWaylandWindow *window;
277
278     if (inputDevice->mPointerFocus) {
279         window = inputDevice->mPointerFocus;
280         QWindowSystemInterface::handleLeaveEvent(window->widget());
281         inputDevice->mPointerFocus = NULL;
282     }
283
284     if (surface) {
285         window = (QWaylandWindow *) wl_surface_get_user_data(surface);
286         QWindowSystemInterface::handleEnterEvent(window->widget());
287         inputDevice->mPointerFocus = window;
288     }
289
290     inputDevice->mTime = time;
291 }
292
293 void QWaylandInputDevice::inputHandleKeyboardFocus(void *data,
294                                                    struct wl_input_device *input_device,
295                                                    uint32_t time,
296                                                    struct wl_surface *surface,
297                                                    struct wl_array *keys)
298 {
299 #ifndef QT_NO_WAYLAND_XKB
300     Q_UNUSED(input_device);
301     Q_UNUSED(time);
302     QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
303     QWaylandWindow *window;
304     uint32_t *k, *end;
305     uint32_t code;
306
307     end = (uint32_t *) ((char *) keys->data + keys->size);
308     inputDevice->mModifiers = 0;
309     for (k = (uint32_t *) keys->data; k < end; k++) {
310         code = *k + inputDevice->mXkb->min_key_code;
311         inputDevice->mModifiers |=
312             translateModifiers(inputDevice->mXkb->map->modmap[code]);
313     }
314
315     if (surface) {
316         window = (QWaylandWindow *) wl_surface_get_user_data(surface);
317         inputDevice->mKeyboardFocus = window;
318         QWindowSystemInterface::handleWindowActivated(window->widget());
319     } else {
320         inputDevice->mKeyboardFocus = NULL;
321         QWindowSystemInterface::handleWindowActivated(0);
322     }
323 #endif
324 }
325
326 const struct wl_input_device_listener QWaylandInputDevice::inputDeviceListener = {
327     QWaylandInputDevice::inputHandleMotion,
328     QWaylandInputDevice::inputHandleButton,
329     QWaylandInputDevice::inputHandleKey,
330     QWaylandInputDevice::inputHandlePointerFocus,
331     QWaylandInputDevice::inputHandleKeyboardFocus,
332 };
333
334 void QWaylandInputDevice::attach(QWaylandBuffer *buffer, int x, int y)
335 {
336     wl_input_device_attach(mInputDevice, mTime, buffer->buffer(), x, y);
337 }