~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: 2011-12-06 22:44:56 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20111206224456-qc7250z3ya1vi8s9
Tags: 1.7.0-0ubuntu1
* New upstream release (LP: #899183)
* Remove patches 0002-libav-0.7.patch, 0003-fglrx-segfault-on-startup.patch
  now merged to upstream
* Remove unnecessary .la files
* Update debian/watch file
* Fix debian/copyright dep-5 compliancy
* Update standards to version 3.9.2
* Add man pages for avg_checktouch, avg_checkvsync, avg_showsvg
* Minor debian/rules enhancement
* Add librsvg2-dev, libgdk-pixbuf2.0-dev to Build-Depends
* Proper transition to dh_python2

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
}