~ubuntu-branches/ubuntu/trusty/libavg/trusty-proposed

« back to all changes in this revision

Viewing changes to src/player/XInput21MTInputDevice.cpp

  • Committer: Package Import Robot
  • Author(s): OXullo Intersecans
  • Date: 2012-01-29 19:26:37 UTC
  • mfrom: (1.1.7)
  • Revision ID: package-import@ubuntu.com-20120129192637-ck9os7t5x3adl92x
Tags: 1.7.1-0ubuntu1
New upstream release (LP: #923302)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//
2
 
//  libavg - Media Playback Engine. 
3
 
//  Copyright (C) 2003-2011 Ulrich von Zadow
4
 
//
5
 
//  This library is free software; you can redistribute it and/or
6
 
//  modify it under the terms of the GNU Lesser General Public
7
 
//  License as published by the Free Software Foundation; either
8
 
//  version 2 of the License, or (at your option) any later version.
9
 
//
10
 
//  This library is distributed in the hope that it will be useful,
11
 
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 
//  Lesser General Public License for more details.
14
 
//
15
 
//  You should have received a copy of the GNU Lesser General Public
16
 
//  License along with this library; if not, write to the Free Software
17
 
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
//
19
 
//  Current versions can be found at www.libavg.de
20
 
//
21
 
 
22
 
#include "XInput21MTInputDevice.h"
23
 
 
24
 
#include "TouchEvent.h"
25
 
#include "Player.h"
26
 
#include "AVGNode.h"
27
 
#include "TouchStatus.h"
28
 
#include "SDLDisplayEngine.h"
29
 
 
30
 
#include "../base/Logger.h"
31
 
#include "../base/Point.h"
32
 
#include "../base/ObjectCounter.h"
33
 
#include "../base/Exception.h"
34
 
#include "../base/OSHelper.h"
35
 
#include "../base/StringHelper.h"
36
 
 
37
 
#include <SDL/SDL_syswm.h>
38
 
#include <SDL/SDL.h>
39
 
 
40
 
#include <X11/extensions/XInput.h>
41
 
#include <X11/extensions/XInput2.h>
42
 
 
43
 
#ifndef XI_TouchUpdate
44
 
    // Working with a preliminary spec. Update names to the current spec.
45
 
    #define XI_TouchUpdate XI_TouchMotion
46
 
    #define XI_TouchUpdateUnowned XI_TouchMotionUnowned
47
 
#endif
48
 
 
49
 
using namespace std;
50
 
 
51
 
namespace avg {
52
 
 
53
 
Display* XInput21MTInputDevice::s_pDisplay = 0;
54
 
 
55
 
const char* cookieTypeToName(int evtype);
56
 
string xEventTypeToName(int evtype);
57
 
 
58
 
XInput21MTInputDevice::XInput21MTInputDevice()
59
 
    : m_LastID(0),
60
 
      m_DeviceID(-1)
61
 
{
62
 
}
63
 
 
64
 
XInput21MTInputDevice::~XInput21MTInputDevice()
65
 
{
66
 
    if (m_DeviceID != -1 && m_OldMasterDeviceID != -1) {
67
 
        XIAttachSlaveInfo atInfo;
68
 
        atInfo.type = XIAttachSlave;
69
 
        atInfo.deviceid = m_DeviceID;
70
 
        atInfo.new_master = m_OldMasterDeviceID;
71
 
        XIChangeHierarchy(s_pDisplay, (XIAnyHierarchyChangeInfo *)&atInfo, 1);
72
 
    }
73
 
}
74
 
 
75
 
void XInput21MTInputDevice::start()
76
 
{
77
 
    Status status;
78
 
    SDLDisplayEngine * pEngine = Player::get()->getDisplayEngine();
79
 
 
80
 
    SDL_SysWMinfo info;
81
 
    SDL_VERSION(&info.version);
82
 
    int rc = SDL_GetWMInfo(&info);
83
 
    AVG_ASSERT(rc != -1);
84
 
    s_pDisplay = info.info.x11.display;
85
 
    m_SDLLockFunc = info.info.x11.lock_func;
86
 
    m_SDLUnlockFunc = info.info.x11.unlock_func;
87
 
 
88
 
    m_SDLLockFunc();
89
 
    // XInput Extension available?
90
 
    int event, error;
91
 
    bool bOk = XQueryExtension(s_pDisplay, "XInputExtension", &m_XIOpcode, 
92
 
            &event, &error);
93
 
    if (!bOk) {
94
 
        throw Exception(AVG_ERR_MT_INIT, 
95
 
                "XInput 2.1 multitouch event source: X Input extension not available.");
96
 
    }
97
 
 
98
 
    // Which version of XI2? We need 2.1. 
99
 
    int major = 2, minor = 1;
100
 
    status = XIQueryVersion(s_pDisplay, &major, &minor);
101
 
    if (status == BadRequest) {
102
 
        throw Exception(AVG_ERR_MT_INIT, 
103
 
                "XInput 2.1 multitouch event source: Server does not support XI2");
104
 
    }
105
 
    if (major < 2 || minor < 1) {
106
 
        throw Exception(AVG_ERR_MT_INIT, 
107
 
                "XInput 2.1 multitouch event source: Supported version is "
108
 
                +toString(major)+"."+toString(minor)+". 2.1 is needed.");
109
 
    }
110
 
 
111
 
    findMTDevice();
112
 
 
113
 
    // SDL grabs the pointer in full screen mode. This breaks touchscreen usage.
114
 
    // Can't use SDL_WM_GrabInput(SDL_GRAB_OFF) because it doesn't work in full
115
 
    // screen mode. Get the display connection and do it manually.
116
 
    XUngrabPointer(info.info.x11.display, CurrentTime);
117
 
 
118
 
    XIEventMask mask;
119
 
    mask.deviceid = m_DeviceID;
120
 
    mask.mask_len = XIMaskLen(XI_LASTEVENT);
121
 
    mask.mask = (unsigned char *)calloc(mask.mask_len, sizeof(char));
122
 
    memset(mask.mask, 0, mask.mask_len);
123
 
    XISetMask(mask.mask, XI_TouchBegin);
124
 
    XISetMask(mask.mask, XI_TouchUpdate);
125
 
    XISetMask(mask.mask, XI_TouchEnd);
126
 
 
127
 
    status = XISelectEvents(s_pDisplay, info.info.x11.window, &mask, 1);
128
 
    AVG_ASSERT(status == Success);
129
 
 
130
 
    m_SDLUnlockFunc();
131
 
 
132
 
    SDL_SetEventFilter(XInput21MTInputDevice::filterEvent);
133
 
  
134
 
    
135
 
    XIDetachSlaveInfo detInfo;
136
 
    detInfo.type = XIDetachSlave;
137
 
    detInfo.deviceid = m_DeviceID;
138
 
    XIChangeHierarchy(s_pDisplay, (XIAnyHierarchyChangeInfo *)&detInfo, 1);
139
 
 
140
 
    pEngine->setXIMTInputDevice(this);
141
 
    MultitouchInputDevice::start();
142
 
    AVG_TRACE(Logger::CONFIG, "XInput 2.1 Multitouch event source created.");
143
 
}
144
 
 
145
 
void XInput21MTInputDevice::handleXIEvent(const XEvent& xEvent)
146
 
{
147
 
    m_SDLLockFunc();
148
 
    XGenericEventCookie* pCookie = (XGenericEventCookie*)&xEvent.xcookie;
149
 
    if (pCookie->type == GenericEvent && pCookie->extension == m_XIOpcode) {
150
 
        XIDeviceEvent* pDevEvent = (XIDeviceEvent*)(pCookie->data);
151
 
        IntPoint pos(pDevEvent->event_x, pDevEvent->event_y);
152
 
        int xid = pDevEvent->detail;
153
 
        switch (pCookie->evtype) {
154
 
            case XI_TouchBegin:
155
 
                {
156
 
//                    cerr << "TouchBegin " << xid << ", " << pos << endl;
157
 
                    m_LastID++;
158
 
                    TouchEventPtr pEvent = createEvent(m_LastID, Event::CURSORDOWN, pos); 
159
 
                    addTouchStatus(xid, pEvent);
160
 
                }
161
 
                break;
162
 
            case XI_TouchUpdate:
163
 
                {
164
 
//                    cerr << "TouchUpdate " << xid << ", " << pos << endl;
165
 
                    TouchEventPtr pEvent = createEvent(0, Event::CURSORMOTION, pos); 
166
 
                    TouchStatusPtr pTouchStatus = getTouchStatus(xid);
167
 
                    AVG_ASSERT(pTouchStatus);
168
 
                    pTouchStatus->pushEvent(pEvent);
169
 
                }
170
 
                break;
171
 
            case XI_TouchEnd:
172
 
                {
173
 
//                    cerr << "TouchEnd " << xid << ", " << pos << endl;
174
 
                    TouchStatusPtr pTouchStatus = getTouchStatus(xid);
175
 
                    AVG_ASSERT(pTouchStatus);
176
 
                    TouchEventPtr pEvent = createEvent(0, Event::CURSORUP, pos); 
177
 
                    pTouchStatus->pushEvent(pEvent);
178
 
                }
179
 
                break;
180
 
            default:
181
 
                ;
182
 
//                cerr << "Unhandled XInput event, type: " 
183
 
//                        << cookieTypeToName(pCookie->evtype) << endl;
184
 
        }
185
 
    } else {
186
 
//        cerr << "Unhandled X11 Event: " << xEvent.type << endl;
187
 
    }
188
 
 
189
 
    XFreeEventData(s_pDisplay, pCookie);
190
 
    m_SDLUnlockFunc();
191
 
}
192
 
 
193
 
std::vector<EventPtr> XInput21MTInputDevice::pollEvents()
194
 
{
195
 
 
196
 
    return MultitouchInputDevice::pollEvents();
197
 
}
198
 
 
199
 
void XInput21MTInputDevice::findMTDevice()
200
 
{
201
 
    int ndevices;
202
 
    XIDeviceInfo* pDevices;
203
 
    XIDeviceInfo* pDevice;
204
 
 
205
 
    pDevices = XIQueryDevice(s_pDisplay, XIAllDevices, &ndevices);
206
 
 
207
 
    XITouchClassInfo* pTouchClass = 0;
208
 
    int maxTouches;
209
 
    for (int i = 0; i < ndevices && !pTouchClass; ++i) {
210
 
        pDevice = &pDevices[i];
211
 
//        cerr << "Device " << pDevice->name << "(id: " << pDevice->deviceid << ")."
212
 
//                << endl;
213
 
        if (pDevice->use == XISlavePointer || pDevice->use == XIFloatingSlave) {
214
 
            for (int j = 0; j < pDevice->num_classes; ++j) {
215
 
                XIAnyClassInfo * pClass = pDevice->classes[j];
216
 
                if (pClass->type == XITouchClass) {
217
 
                    XITouchClassInfo* pTempTouchClass = (XITouchClassInfo *)pClass;
218
 
                    if (pTempTouchClass->mode == XIDirectTouch) {
219
 
                        pTouchClass = pTempTouchClass;
220
 
                        m_sDeviceName = pDevice->name;
221
 
                        m_DeviceID = pDevice->deviceid;
222
 
                        if (pDevice->use == XISlavePointer) {
223
 
                            m_OldMasterDeviceID = pDevice->attachment;
224
 
                        } else {
225
 
                            m_OldMasterDeviceID = -1;
226
 
                        }
227
 
                        maxTouches = pTouchClass->num_touches;
228
 
                        break;
229
 
                    }
230
 
                }
231
 
            }
232
 
        }
233
 
    }
234
 
    if (pTouchClass) {
235
 
        AVG_TRACE(Logger::CONFIG, "Using multitouch input device " << m_sDeviceName 
236
 
                << ", max touches: " << maxTouches);
237
 
    } else {
238
 
        throw Exception(AVG_ERR_MT_INIT, 
239
 
                "XInput 2.1 multitouch event source: No multitouch device found.");
240
 
    }
241
 
    XIFreeDeviceInfo(pDevices);
242
 
}
243
 
 
244
 
TouchEventPtr XInput21MTInputDevice::createEvent(int id, Event::Type type, IntPoint pos)
245
 
{
246
 
    return TouchEventPtr(new TouchEvent(id, type, pos, Event::TOUCH));
247
 
}
248
 
 
249
 
int XInput21MTInputDevice::filterEvent(const SDL_Event * pEvent)
250
 
{
251
 
    // This is a hook into libsdl event processing. Since libsdl doesn't know about
252
 
    // XInput 2, it doesn't call XGetEventData either. By the time the event arrives
253
 
    // in handleXIEvent(), other events may have arrived and XGetEventData can't be 
254
 
    // called anymore. Hence this function, which calls XGetEventData for each event
255
 
    // that has a cookie.
256
 
    if (pEvent->type == SDL_SYSWMEVENT) {
257
 
        SDL_SysWMmsg* pMsg = pEvent->syswm.msg;
258
 
        AVG_ASSERT(pMsg->subsystem == SDL_SYSWM_X11);
259
 
        XEvent* pXEvent = &pMsg->event.xevent;
260
 
        XGenericEventCookie* pCookie = (XGenericEventCookie*)&(pXEvent->xcookie);
261
 
//        cerr << "---- filter xinput event: " << xEventTypeToName(pXEvent->type) << ", "
262
 
//                << cookieTypeToName(pCookie->evtype) << endl;
263
 
        XGetEventData(s_pDisplay, pCookie);
264
 
    } else {
265
 
//        cerr << "---- filter: " << int(pEvent->type) << endl;
266
 
    }
267
 
    return 1;
268
 
}
269
 
          
270
 
// From xinput/test_xi2.c
271
 
const char* cookieTypeToName(int evtype)
272
 
{
273
 
    const char *name;
274
 
    switch(evtype) {
275
 
        case XI_DeviceChanged:    name = "DeviceChanged";        break;
276
 
        case XI_KeyPress:         name = "KeyPress";             break;
277
 
        case XI_KeyRelease:       name = "KeyRelease";           break;
278
 
        case XI_ButtonPress:      name = "ButtonPress";          break;
279
 
        case XI_ButtonRelease:    name = "ButtonRelease";        break;
280
 
        case XI_Motion:           name = "Motion";               break;
281
 
        case XI_Enter:            name = "Enter";                break;
282
 
        case XI_Leave:            name = "Leave";                break;
283
 
        case XI_FocusIn:          name = "FocusIn";              break;
284
 
        case XI_FocusOut:         name = "FocusOut";             break;
285
 
        case XI_HierarchyChanged: name = "HierarchyChanged";     break;
286
 
        case XI_PropertyEvent:    name = "PropertyEvent";        break;
287
 
        case XI_RawKeyPress:      name = "RawKeyPress";          break;
288
 
        case XI_RawKeyRelease:    name = "RawKeyRelease";        break;
289
 
        case XI_RawButtonPress:   name = "RawButtonPress";       break;
290
 
        case XI_RawButtonRelease: name = "RawButtonRelease";     break;
291
 
        case XI_RawMotion:        name = "RawMotion";            break;
292
 
        case XI_TouchBegin:       name = "TouchBegin";           break;
293
 
        case XI_TouchEnd:         name = "TouchEnd";             break;
294
 
        case XI_TouchUpdate:      name = "TouchUpdate";          break;
295
 
        case XI_TouchUpdateUnowned: name = "TouchUpdateUnowned"; break;
296
 
        default:                  name = "unknown event type";   break;
297
 
    }
298
 
    return name;
299
 
}
300
 
 
301
 
string xEventTypeToName(int evtype)
302
 
{
303
 
    switch(evtype) {
304
 
        case KeyPress:
305
 
            return "KeyPress";
306
 
        case KeyRelease:
307
 
            return "KeyRelease";
308
 
        case ButtonPress:
309
 
            return "ButtonPress";
310
 
        case ButtonRelease:
311
 
            return "ButtonRelease";
312
 
        case MotionNotify:
313
 
            return "MotionNotify";
314
 
        case EnterNotify:
315
 
            return "EnterNotify";
316
 
        case LeaveNotify:
317
 
            return "LeaveNotify";
318
 
        case FocusIn:
319
 
            return "FocusIn";
320
 
        case FocusOut:
321
 
            return "FocusOut";
322
 
        case KeymapNotify:
323
 
            return "KeymapNotify";
324
 
        case Expose:
325
 
            return "Expose";
326
 
        case GraphicsExpose:
327
 
            return "GraphicsExpose";
328
 
        case NoExpose:
329
 
            return "NoExpose";
330
 
        case VisibilityNotify:
331
 
            return "VisibilityNotify";
332
 
        case CreateNotify:
333
 
            return "CreateNotify";
334
 
        case DestroyNotify:
335
 
            return "DestroyNotify";
336
 
        case UnmapNotify:
337
 
            return "UnmapNotify";
338
 
        case MapNotify:
339
 
            return "MapNotify";
340
 
        case MapRequest:
341
 
            return "MapRequest";
342
 
        case ReparentNotify:
343
 
            return "ReparentNotify";
344
 
        case ConfigureNotify:
345
 
            return "ConfigureNotify";
346
 
        case ConfigureRequest:
347
 
            return "ConfigureRequest";
348
 
        case GravityNotify:
349
 
            return "GravityNotify";
350
 
        case ResizeRequest:
351
 
            return "ResizeRequest";
352
 
        case CirculateNotify:
353
 
            return "CirculateNotify";
354
 
        case CirculateRequest:
355
 
            return "CirculateRequest";
356
 
        case PropertyNotify:
357
 
            return "PropertyNotify";
358
 
        case SelectionClear:
359
 
            return "SelectionClear";
360
 
        case SelectionRequest:
361
 
            return "SelectionRequest";
362
 
        case SelectionNotify:
363
 
            return "SelectionNotify";
364
 
        case ColormapNotify:
365
 
            return "ColormapNotify";
366
 
        case ClientMessage:
367
 
            return "ClientMessage";
368
 
        case MappingNotify:
369
 
            return "MappingNotify";
370
 
        case GenericEvent:
371
 
            return "GenericEvent";
372
 
        default:
373
 
            return "Unknown event type";
374
 
    }
375
 
}
376
 
 
377
 
}