Cocoa: Fix spelling errors in comments.
[profile/ivi/qtbase.git] / src / plugins / platforms / cocoa / qmultitouch_mac.mm
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 "qmultitouch_mac_p.h"
43 #include "qcocoahelpers.h"
44
45 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
46
47 QT_BEGIN_NAMESPACE
48
49 QHash<qint64, QCocoaTouch*> QCocoaTouch::_currentTouches;
50 QPointF QCocoaTouch::_screenReferencePos;
51 QPointF QCocoaTouch::_trackpadReferencePos;
52 int QCocoaTouch::_idAssignmentCount = 0;
53 int QCocoaTouch::_touchCount = 0;
54 bool QCocoaTouch::_updateInternalStateOnly = true;
55
56 QCocoaTouch::QCocoaTouch(NSTouch *nstouch)
57 {
58     if (_currentTouches.size() == 0)
59         _idAssignmentCount = 0;
60
61     _touchPoint.id = _idAssignmentCount++;
62     _touchPoint.pressure = 1.0;
63     _identity = qint64([nstouch identity]);
64     _currentTouches.insert(_identity, this);
65     updateTouchData(nstouch, NSTouchPhaseBegan);
66 }
67
68 QCocoaTouch::~QCocoaTouch()
69 {
70     _currentTouches.remove(_identity);
71 }
72
73 void QCocoaTouch::updateTouchData(NSTouch *nstouch, NSTouchPhase phase)
74 {
75     _touchPoint.state = toTouchPointState(phase);
76     _touchPoint.isPrimary = (_touchCount == 1);
77
78     // From the normalized position on the trackpad, calculate
79     // where on screen the touchpoint should be according to the
80     // reference position:
81     NSPoint npos = [nstouch normalizedPosition];
82     QPointF qnpos = QPointF(npos.x, 1 - npos.y);
83     _touchPoint.normalPosition = qnpos;
84
85     if (_touchPoint.id == 0 && phase == NSTouchPhaseBegan) {
86         _trackpadReferencePos = qnpos;
87         _screenReferencePos = qt_mac_flipPoint([NSEvent mouseLocation]);
88     }
89
90     QPointF screenPos = _screenReferencePos;
91
92     NSSize dsize = [nstouch deviceSize];
93     float ppiX = (qnpos.x() - _trackpadReferencePos.x()) * dsize.width;
94     float ppiY = (qnpos.y() - _trackpadReferencePos.y()) * dsize.height;
95     QPointF relativePos = _trackpadReferencePos - QPointF(ppiX, ppiY);
96     screenPos -= relativePos;
97     // Mac does not support area touch, only points, hence set width/height to 1.
98     // The touch point is supposed to be in the center of '_touchPoint.area', and
99     // since width/height is 1 it means we must subtract 0.5 from x and y.
100     screenPos.rx() -= 0.5;
101     screenPos.ry() -= 0.5;
102     _touchPoint.area = QRectF(screenPos, QSize(1, 1));
103 }
104
105 QCocoaTouch *QCocoaTouch::findQCocoaTouch(NSTouch *nstouch)
106 {
107     qint64 identity = qint64([nstouch identity]);
108     if (_currentTouches.contains(identity))
109         return _currentTouches.value(identity);
110     return 0;
111 }
112
113 Qt::TouchPointState QCocoaTouch::toTouchPointState(NSTouchPhase nsState)
114 {
115     Qt::TouchPointState qtState = Qt::TouchPointReleased;
116     switch (nsState) {
117         case NSTouchPhaseBegan:
118             qtState = Qt::TouchPointPressed;
119             break;
120         case NSTouchPhaseMoved:
121             qtState = Qt::TouchPointMoved;
122             break;
123         case NSTouchPhaseStationary:
124             qtState = Qt::TouchPointStationary;
125             break;
126         case NSTouchPhaseEnded:
127         case NSTouchPhaseCancelled:
128             qtState = Qt::TouchPointReleased;
129             break;
130         default:
131             break;
132     }
133     return qtState;
134 }
135
136 QList<QWindowSystemInterface::TouchPoint>
137 QCocoaTouch::getCurrentTouchPointList(NSEvent *event, bool acceptSingleTouch)
138 {
139     QMap<int, QWindowSystemInterface::TouchPoint> touchPoints;
140     NSSet *ended = [event touchesMatchingPhase:NSTouchPhaseEnded | NSTouchPhaseCancelled inView:nil];
141     NSSet *active = [event
142         touchesMatchingPhase:NSTouchPhaseBegan | NSTouchPhaseMoved | NSTouchPhaseStationary
143         inView:nil];
144     _touchCount = [active count];
145
146     // First: remove touches that were ended by the user. If we are
147     // currently not accepting single touches, a corresponding 'begin'
148     // has never been send to the app for these events.
149     // So should therefore not send the following removes either.
150
151     for (int i=0; i<int([ended count]); ++i) {
152         NSTouch *touch = [[ended allObjects] objectAtIndex:i];
153         QCocoaTouch *qcocoaTouch = findQCocoaTouch(touch);
154         if (qcocoaTouch) {
155             qcocoaTouch->updateTouchData(touch, [touch phase]);
156             if (!_updateInternalStateOnly)
157                 touchPoints.insert(qcocoaTouch->_touchPoint.id, qcocoaTouch->_touchPoint);
158             delete qcocoaTouch;
159         }
160     }
161
162     bool wasUpdateInternalStateOnly = _updateInternalStateOnly;
163     _updateInternalStateOnly = !acceptSingleTouch && _touchCount < 2;
164
165     // Next: update, or create, existing touches.
166     // We always keep track of all touch points, even
167     // when not accepting single touches.
168
169     for (int i=0; i<int([active count]); ++i) {
170         NSTouch *touch = [[active allObjects] objectAtIndex:i];
171         QCocoaTouch *qcocoaTouch = findQCocoaTouch(touch);
172         if (!qcocoaTouch)
173             qcocoaTouch = new QCocoaTouch(touch);
174         else
175             qcocoaTouch->updateTouchData(touch, wasUpdateInternalStateOnly ? NSTouchPhaseBegan : [touch phase]);
176         if (!_updateInternalStateOnly)
177             touchPoints.insert(qcocoaTouch->_touchPoint.id, qcocoaTouch->_touchPoint);
178     }
179
180     // Next: sadly, we need to check that our touch hash is in
181     // sync with cocoa. This is typically not the case after a system
182     // gesture happend (like a four-finger-swipe to show expose).
183
184     if (_touchCount != _currentTouches.size()) {
185         // Remove all instances, and basically start from scratch:
186         touchPoints.clear();
187         foreach (QCocoaTouch *qcocoaTouch, _currentTouches.values()) {
188             if (!_updateInternalStateOnly) {
189                 qcocoaTouch->_touchPoint.state = Qt::TouchPointReleased;
190                 touchPoints.insert(qcocoaTouch->_touchPoint.id, qcocoaTouch->_touchPoint);
191             }
192             delete qcocoaTouch;
193         }
194         _currentTouches.clear();
195         _updateInternalStateOnly = !acceptSingleTouch;
196         return touchPoints.values();
197     }
198
199     // Finally: If this call _started_ to reject single
200     // touches, we need to fake a release for the remaining
201     // touch now (and refake a begin for it later, if needed).
202
203     if (_updateInternalStateOnly && !wasUpdateInternalStateOnly && !_currentTouches.isEmpty()) {
204         QCocoaTouch *qcocoaTouch = _currentTouches.values().first();
205         qcocoaTouch->_touchPoint.state = Qt::TouchPointReleased;
206         touchPoints.insert(qcocoaTouch->_touchPoint.id, qcocoaTouch->_touchPoint);
207         // Since this last touch also will end up being the first
208         // touch (if the user adds a second finger without lifting
209         // the first), we promote it to be the primary touch:
210         qcocoaTouch->_touchPoint.id = 0;
211         _idAssignmentCount = 1;
212     }
213
214     return touchPoints.values();
215 }
216
217 QT_END_NAMESPACE
218
219 #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
220