summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp25
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h2
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h2
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp166
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h6
-rw-r--r--src/gui/graphicsview/qgraphicssceneevent.cpp338
-rw-r--r--src/gui/graphicsview/qgraphicssceneevent.h64
-rw-r--r--src/gui/graphicsview/qgraphicsview.cpp106
-rw-r--r--src/gui/graphicsview/qgraphicsview_p.h5
-rw-r--r--src/gui/kernel/qapplication.cpp94
-rw-r--r--src/gui/kernel/qapplication_p.h32
-rw-r--r--src/gui/kernel/qapplication_win.cpp188
-rw-r--r--src/gui/kernel/qevent.cpp164
-rw-r--r--src/gui/kernel/qevent.h43
-rw-r--r--src/gui/kernel/qevent_p.h16
-rw-r--r--src/gui/kernel/qwidget_win.cpp4
16 files changed, 1218 insertions, 37 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index c5f5889..b4c8684 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -2064,6 +2064,31 @@ void QGraphicsItem::setAcceptsHoverEvents(bool enabled)
d_ptr->acceptsHover = quint32(enabled);
}
+/*! \since 4.6
+
+ Returns true if an item accepts touch events
+ (QGraphicsSceneTouchEvent); otherwise, returns false. By default,
+ items do not accept touch events.
+
+ \sa setAcceptTouchEvents()
+*/
+bool QGraphicsItem::acceptTouchEvents() const
+{
+ return d_ptr->acceptTouchEvents;
+}
+
+/*!
+ \since 4.6
+
+ If \a enabled is true, this item will accept touch events;
+ otherwise, it will ignore them. By default, items do not accept
+ touch events.
+*/
+void QGraphicsItem::setAcceptTouchEvents(bool enabled)
+{
+ d_ptr->acceptTouchEvents = quint32(enabled);
+}
+
/*!
Returns true if this item handles child events (i.e., all events
intended for any of its children are instead sent to this item);
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index b98882d..ec3373a 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -203,6 +203,8 @@ public:
void setAcceptsHoverEvents(bool enabled); // obsolete
bool acceptHoverEvents() const;
void setAcceptHoverEvents(bool enabled);
+ bool acceptTouchEvents() const;
+ void setAcceptTouchEvents(bool enabled);
bool handlesChildEvents() const;
void setHandlesChildEvents(bool enabled);
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index af0b077..228368c 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -138,6 +138,7 @@ public:
dirty(0),
dirtyChildren(0),
localCollisionHack(0),
+ acceptTouchEvents(0),
globalStackingOrder(-1),
sceneTransformIndex(-1),
q_ptr(0)
@@ -272,6 +273,7 @@ public:
quint32 dirty : 1;
quint32 dirtyChildren : 1;
quint32 localCollisionHack : 1;
+ quint32 acceptTouchEvents : 1;
// Optional stacking order
int globalStackingOrder;
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index a9578f2..2e714cb 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -3609,6 +3609,9 @@ bool QGraphicsScene::event(QEvent *event)
case QEvent::GraphicsSceneHoverEnter:
case QEvent::GraphicsSceneHoverLeave:
case QEvent::GraphicsSceneHoverMove:
+ case QEvent::GraphicsSceneTouchBegin:
+ case QEvent::GraphicsSceneTouchUpdate:
+ case QEvent::GraphicsSceneTouchEnd:
// Reset the under-mouse list to ensure that this event gets fresh
// item-under-mouse data. Be careful about this list; if people delete
// items from inside event handlers, this list can quickly end up
@@ -3760,6 +3763,15 @@ bool QGraphicsScene::event(QEvent *event)
// geometries that do not have an explicit style set.
update();
break;
+ case QEvent::GraphicsSceneTouchBegin:
+ d->touchBeginEvent(static_cast<QGraphicsSceneTouchEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneTouchUpdate:
+ d->touchUpdateEvent(static_cast<QGraphicsSceneTouchEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneTouchEnd:
+ d->touchEndEvent(static_cast<QGraphicsSceneTouchEvent *>(event));
+ break;
case QEvent::Timer:
if (d->indexTimerId && static_cast<QTimerEvent *>(event)->timerId() == d->indexTimerId) {
if (d->restartIndexTimer) {
@@ -5373,6 +5385,160 @@ void QGraphicsScene::setActiveWindow(QGraphicsWidget *widget)
}
}
+// ### FIXME: the code for touch event support is mosly copied from
+// ### QGraphicsScenePrivate::mousePressEventHandler() and friends, need to
+// ### refactor to reduce code duplication
+
+void QGraphicsScenePrivate::sendTouchEvent(QGraphicsSceneTouchEvent *touchEvent)
+{
+ if (touchEvent->type() == QEvent::GraphicsSceneTouchEnd && lastMouseGrabberItemHasImplicitMouseGrab) {
+ clearMouseGrabber();
+ return;
+ }
+
+ QGraphicsItem *item = mouseGrabberItems.last();
+ QList<QGraphicsSceneTouchEvent::TouchPoint *> touchPoints = touchEvent->touchPoints();
+ for (int i = 0; i < touchPoints.count(); ++i) {
+ QGraphicsSceneTouchEvent::TouchPoint *touchPoint = touchPoints.at(i);
+ touchPoint->setPos(item->d_ptr->genericMapFromScene(touchPoint->scenePos(), touchEvent->widget()));
+ touchPoint->setStartPos(item->d_ptr->genericMapFromScene(touchPoint->startScenePos(), touchEvent->widget()));
+ touchPoint->setLastPos(item->d_ptr->genericMapFromScene(touchPoint->lastScenePos(), touchEvent->widget()));
+ }
+ sendEvent(item, touchEvent);
+}
+
+void QGraphicsScenePrivate::touchBeginEvent(QGraphicsSceneTouchEvent *touchEvent)
+{
+ Q_Q(QGraphicsScene);
+
+ // Ignore by default, unless we find a mouse grabber that accepts it.
+ touchEvent->ignore();
+
+ // Deliver to any existing mouse grabber.
+ if (!mouseGrabberItems.isEmpty()) {
+ // The event is ignored by default, but we disregard the event's
+ // accepted state after delivery; the mouse is grabbed, after all.
+ sendTouchEvent(touchEvent);
+ return;
+ }
+
+ // Start by determining the number of items at the current position.
+ // Reuse value from earlier calculations if possible.
+ if (cachedItemsUnderMouse.isEmpty()) {
+ QGraphicsSceneTouchEvent::TouchPoint *touchPoint = touchEvent->touchPoints().first();
+ // ### FIXME: should the itemsAtPosition() function support sub-pixel screenPos?
+ cachedItemsUnderMouse = itemsAtPosition(touchPoint->screenPos().toPoint(),
+ touchPoint->scenePos(),
+ touchEvent->widget());
+ }
+
+ // Update window activation.
+ QGraphicsWidget *newActiveWindow = windowForItem(cachedItemsUnderMouse.value(0));
+ if (newActiveWindow != activeWindow)
+ q->setActiveWindow(newActiveWindow);
+
+ // Set focus on the topmost enabled item that can take focus.
+ bool setFocus = false;
+ foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
+ if (item->isEnabled() && (item->flags() & QGraphicsItem::ItemIsFocusable)) {
+ if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
+ setFocus = true;
+ if (item != q->focusItem())
+ q->setFocusItem(item, Qt::MouseFocusReason);
+ break;
+ }
+ }
+ }
+
+ // If nobody could take focus, clear it.
+ if (!stickyFocus && !setFocus)
+ q->setFocusItem(0, Qt::MouseFocusReason);
+
+ // Find a mouse grabber by sending touch events to all mouse grabber
+ // candidates one at a time, until the event is accepted. It's accepted by
+ // default, so the receiver has to explicitly ignore it for it to pass
+ // through.
+ foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
+ if (!item->acceptTouchEvents()) {
+ // Skip items that don't accept the touch events
+ continue;
+ }
+
+ grabMouse(item, /* implicit = */ true);
+ touchEvent->accept();
+
+ // check if the item we are sending to are disabled (before we send the event)
+ bool disabled = !item->isEnabled();
+ bool isWindow = item->isWindow();
+ sendTouchEvent(touchEvent);
+
+ bool dontSendUngrabEvents = mouseGrabberItems.isEmpty() || mouseGrabberItems.last() != item;
+ if (disabled) {
+ ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
+ break;
+ }
+ if (touchEvent->isAccepted()) {
+ lastMouseGrabberItem = item;
+ return;
+ }
+ ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
+
+ // Don't propagate through windows.
+ if (isWindow)
+ break;
+ }
+
+ // Is the event still ignored? Then the mouse press goes to the scene.
+ // Reset the mouse grabber, clear the selection, clear focus, and leave
+ // the event ignored so that it can propagate through the originating
+ // view.
+ if (!touchEvent->isAccepted()) {
+ clearMouseGrabber();
+
+ QGraphicsView *view = touchEvent->widget() ? qobject_cast<QGraphicsView *>(touchEvent->widget()->parentWidget()) : 0;
+ bool dontClearSelection = view && view->dragMode() == QGraphicsView::ScrollHandDrag;
+ if (!dontClearSelection) {
+ // Clear the selection if the originating view isn't in scroll
+ // hand drag mode. The view will clear the selection if no drag
+ // happened.
+ q->clearSelection();
+ }
+ }
+}
+
+void QGraphicsScenePrivate::touchUpdateEvent(QGraphicsSceneTouchEvent *touchEvent)
+{
+ if (mouseGrabberItems.isEmpty()) {
+ touchEvent->ignore();
+ return;
+ }
+
+ // Forward the event to the mouse grabber
+ sendTouchEvent(touchEvent);
+ touchEvent->accept();
+}
+
+void QGraphicsScenePrivate::touchEndEvent(QGraphicsSceneTouchEvent *touchEvent)
+{
+ if (mouseGrabberItems.isEmpty()) {
+ touchEvent->ignore();
+ return;
+ }
+
+ // Forward the event to the mouse grabber
+ sendTouchEvent(touchEvent);
+ touchEvent->accept();
+
+ // Reset the mouse grabber
+ if (!mouseGrabberItems.isEmpty()) {
+ lastMouseGrabberItem = mouseGrabberItems.last();
+ if (lastMouseGrabberItemHasImplicitMouseGrab)
+ mouseGrabberItems.last()->ungrabMouse();
+ } else {
+ lastMouseGrabberItem = 0;
+ }
+}
+
QT_END_NAMESPACE
#include "moc_qgraphicsscene.cpp"
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index 7f441da..d5e539b 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -73,6 +73,7 @@ QT_BEGIN_NAMESPACE
class QGraphicsView;
class QGraphicsWidget;
+class QGraphicsSceneTouchEvent;
class QGraphicsScenePrivate : public QObjectPrivate
{
@@ -259,6 +260,11 @@ public:
mutable QVector<QTransform> sceneTransformCache;
mutable QBitArray validTransforms;
mutable QVector<int> freeSceneTransformSlots;
+
+ void sendTouchEvent(QGraphicsSceneTouchEvent *touchEvent);
+ void touchBeginEvent(QGraphicsSceneTouchEvent *touchEvent);
+ void touchUpdateEvent(QGraphicsSceneTouchEvent *touchEvent);
+ void touchEndEvent(QGraphicsSceneTouchEvent *touchEvent);
};
QT_END_NAMESPACE
diff --git a/src/gui/graphicsview/qgraphicssceneevent.cpp b/src/gui/graphicsview/qgraphicssceneevent.cpp
index b819c2c..3c9799b 100644
--- a/src/gui/graphicsview/qgraphicssceneevent.cpp
+++ b/src/gui/graphicsview/qgraphicssceneevent.cpp
@@ -76,14 +76,14 @@
received by the view (see
\l{QGraphicsSceneMouseEvent::}{lastScreenPos()},
\l{QGraphicsSceneMouseEvent::}{lastScenePos()}, and
- \l{QGraphicsSceneMouseEvent::}{lastPos()}).
+ \l{QGraphicsSceneMouseEvent::}{lastPos()}).
\sa QEvent
*/
/*!
\class QGraphicsSceneMouseEvent
- \brief The QGraphicsSceneMouseEvent class provides mouse events
+ \brief The QGraphicsSceneMouseEvent class provides mouse events
in the graphics view framework.
\since 4.2
\ingroup multimedia
@@ -106,7 +106,7 @@
/*!
\class QGraphicsSceneWheelEvent
- \brief The QGraphicsSceneWheelEvent class provides wheel events
+ \brief The QGraphicsSceneWheelEvent class provides wheel events
in the graphics view framework.
\brief The QGraphicsSceneWheelEvent class provides wheel events in the
graphics view framework.
@@ -157,7 +157,7 @@
/*!
\class QGraphicsSceneHoverEvent
- \brief The QGraphicsSceneHoverEvent class provides hover events
+ \brief The QGraphicsSceneHoverEvent class provides hover events
in the graphics view framework.
\since 4.2
\ingroup multimedia
@@ -173,7 +173,7 @@
/*!
\class QGraphicsSceneHelpEvent
- \brief The QGraphicsSceneHelpEvent class provides events when a
+ \brief The QGraphicsSceneHelpEvent class provides events when a
tooltip is requested.
\since 4.2
\ingroup multimedia
@@ -199,7 +199,7 @@
/*!
\class QGraphicsSceneDragDropEvent
\brief The QGraphicsSceneDragDropEvent class provides events for
- drag and drop in the graphics view framework.
+ drag and drop in the graphics view framework.
\since 4.2
\ingroup multimedia
\ingroup graphicsview-api
@@ -257,6 +257,37 @@
QGraphicsItem::ItemPositionHasChanged
*/
+/*!
+ \class QGraphicsSceneTouchEvent
+ \brief The QGraphicsSceneTouchEvent class provides touch events in the graphics view framework.
+ \since 4.6
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ When a QGraphicsView receives a QTouchEvent, it translates it to a
+ QGraphicsSceneTouchEvent. The event is then forwarded to the
+ QGraphicsScene associated with the view.
+
+ The touchPoints() function returns a list of touch points for the
+ event. In addition to containing the item, scene, and screen
+ coordinates, each touch point also contains its starting and
+ previous coordinates.
+
+ \sa QTouchEvent
+*/
+
+/*!
+ \class QGraphicsSceneTouchEvent::TouchPoint
+ \brief The QGraphicsSceneTouchEvent::TouchPoint class represents a single touch point in a QGraphicsSceneTouchEvent.
+ \since 4.6
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ Each touch point in a QGraphicsSceneTouchEvent has an id() and
+ state() in addition to current, starting, and previous coordinates
+ for the touch point in item, scene, and screen coordinates.
+*/
+
#include "qgraphicssceneevent.h"
#ifndef QT_NO_GRAPHICSVIEW
@@ -522,7 +553,7 @@ void QGraphicsSceneMouseEvent::setLastPos(const QPointF &pos)
}
/*!
- Returns the last recorded mouse cursor position in scene
+ Returns the last recorded mouse cursor position in scene
coordinates. The last recorded position is the position of
the previous mouse event received by the view that created
the event.
@@ -545,7 +576,7 @@ void QGraphicsSceneMouseEvent::setLastScenePos(const QPointF &pos)
}
/*!
- Returns the last recorded mouse cursor position in screen
+ Returns the last recorded mouse cursor position in screen
coordinates. The last recorded position is the position of
the previous mouse event received by the view that created
the event.
@@ -1275,7 +1306,7 @@ QGraphicsSceneDragDropEvent::~QGraphicsSceneDragDropEvent()
/*!
Returns the mouse position of the event relative to the
view that sent the event.
-
+
\sa QGraphicsView, screenPos(), scenePos()
*/
QPointF QGraphicsSceneDragDropEvent::pos() const
@@ -1373,7 +1404,7 @@ void QGraphicsSceneDragDropEvent::setButtons(Qt::MouseButtons buttons)
/*!
Returns the keyboard modifiers that were pressed when the drag
- and drop event was created.
+ and drop event was created.
\sa Qt::KeyboardModifiers
*/
@@ -1428,7 +1459,7 @@ void QGraphicsSceneDragDropEvent::setPossibleActions(Qt::DropActions actions)
The action must be one of the possible actions as defined by
\c possibleActions().
- \sa Qt::DropAction, possibleActions()
+ \sa Qt::DropAction, possibleActions()
*/
Qt::DropAction QGraphicsSceneDragDropEvent::proposedAction() const
@@ -1673,6 +1704,291 @@ void QGraphicsSceneMoveEvent::setNewPos(const QPointF &pos)
d->newPos = pos;
}
+class QGraphicsSceneTouchEventPrivate : public QGraphicsSceneEventPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsSceneTouchEvent)
+public:
+ inline QGraphicsSceneTouchEventPrivate()
+ : modifiers(Qt::NoModifier)
+ { }
+
+ QList<QGraphicsSceneTouchEvent::TouchPoint *> touchPoints;
+ Qt::KeyboardModifiers modifiers;
+};
+
+/*!
+ \internal
+
+ Constructs a generic QGraphicsSceneTouchEvent of type \a type.
+*/
+QGraphicsSceneTouchEvent::QGraphicsSceneTouchEvent(Type type)
+ : QGraphicsSceneEvent(*new QGraphicsSceneTouchEventPrivate, type)
+{ }
+
+/*!
+ Destroys the QGraphicsSceneTouchEvent.
+*/
+QGraphicsSceneTouchEvent::~QGraphicsSceneTouchEvent()
+{
+ Q_D(QGraphicsSceneTouchEvent);
+ qDeleteAll(d->touchPoints);
+}
+
+/*!
+ Returns the list of touch points for this event.
+
+ \sa QGraphicsSceneTouchEvent::TouchPoint
+*/
+const QList<QGraphicsSceneTouchEvent::TouchPoint *> &QGraphicsSceneTouchEvent::touchPoints() const
+{
+ Q_D(const QGraphicsSceneTouchEvent);
+ return d->touchPoints;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::setTouchPoints(const QList<QGraphicsSceneTouchEvent::TouchPoint *> &touchPoints)
+{
+ Q_D(QGraphicsSceneTouchEvent);
+ d->touchPoints = touchPoints;
+}
+
+/*!
+ Returns the keyboard modifiers in use at the time the event was
+ sent.
+*/
+Qt::KeyboardModifiers QGraphicsSceneTouchEvent::modifiers() const
+{
+ Q_D(const QGraphicsSceneTouchEvent);
+ return d->modifiers;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::setModifiers(Qt::KeyboardModifiers modifiers)
+{
+ Q_D(QGraphicsSceneTouchEvent);
+ d->modifiers = modifiers;
+}
+
+class QGraphicsSceneTouchEventTouchPointPrivate
+{
+public:
+ inline QGraphicsSceneTouchEventTouchPointPrivate()
+ : id(-1), state(Qt::TouchPointReleased), pressure(qreal(0.))
+ { }
+
+ int id;
+ Qt::TouchPointState state;
+ QPointF pos, startPos, lastPos;
+ QPointF scenePos, startScenePos, lastScenePos;
+ QPointF screenPos, startScreenPos, lastScreenPos;
+ qreal pressure;
+};
+
+/*! \internal
+
+ Constructs a new touch point for use in a QGraphicsSceneTouchEvent.
+*/
+QGraphicsSceneTouchEvent::TouchPoint::TouchPoint()
+ : d(new QGraphicsSceneTouchEventTouchPointPrivate)
+{
+}
+
+/*! \internal
+
+ Destroys the QGraphicsSceneTouchEvent::TouchPoint.
+*/
+QGraphicsSceneTouchEvent::TouchPoint::~TouchPoint()
+{
+ delete d;
+}
+
+/*!
+ Returns the identifier for this touch point.
+*/
+int QGraphicsSceneTouchEvent::TouchPoint::id() const
+{
+ return d->id;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setId(int id)
+{
+ d->id = id;
+}
+
+/*!
+ Returns the state of this touch point at the time the
+ QGraphicsSceneTouchEvent occurred.
+*/
+Qt::TouchPointState QGraphicsSceneTouchEvent::TouchPoint::state() const
+{
+ return d->state;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setState(Qt::TouchPointState state)
+{
+ d->state = state;
+}
+
+/*!
+ Returns the current position of this touch point in item coordinates.
+
+ \sa scenePos(), screenPos()
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::pos() const
+{
+ return d->pos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setPos(const QPointF &pos)
+{
+ d->pos = pos;
+}
+
+/*!
+ Returns the starting position of this touch point in item coordinates.
+
+ \sa startScenePos(), startScreenPos()
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::startPos() const
+{
+ return d->startPos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setStartPos(const QPointF &startPos)
+{
+ d->startPos = startPos;
+}
+
+/*!
+ Returns the previous position of this touch point in item coordinates.
+
+ \sa lastScenePos(), lastScreenPos()
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::lastPos() const
+{
+ return d->lastPos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setLastPos(const QPointF &lastPos)
+{
+ d->lastPos = lastPos;
+}
+
+/*!
+ Returns the current position of this touch point in scene coordinates.
+
+ \sa pos(), screenPos()
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::scenePos() const
+{
+ return d->scenePos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setScenePos(const QPointF &scenePos)
+{
+ d->scenePos = scenePos;
+}
+
+/*!
+ Returns the starting position of this touch point in scene coordinates.
+
+ \sa startPos(), startScreenPos()
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::startScenePos() const
+{
+ return d->startScenePos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setStartScenePos(const QPointF &startScenePos)
+{
+ d->startScenePos = startScenePos;
+}
+
+/*!
+ Returns the previous position of this touch point in scene coordinates.
+
+ \sa lastPos(), lastScreenPos()
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::lastScenePos() const
+{
+ return d->lastScenePos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setLastScenePos(const QPointF &lastScenePos)
+{
+ d->lastScenePos = lastScenePos;
+}
+
+/*!
+ Returns the current position of this touch point in screen coordinates.
+
+ \sa pos(), scenePos()
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::screenPos() const
+{
+ return d->screenPos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setScreenPos(const QPointF &screenPos)
+{
+ d->screenPos = screenPos;
+}
+
+/*!
+ Returns the starting position of this touch point in screen coordinates.
+
+ \sa startPos(), startScenePos()
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::startScreenPos() const
+{
+ return d->startScreenPos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setStartScreenPos(const QPointF &startScreenPos)
+{
+ d->startScreenPos = startScreenPos;
+}
+
+/*!
+ Returns the previous position of this touch point in screen coordinates.
+
+ \sa lastPos(), lastScenePos()
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::lastScreenPos() const
+{
+ return d->lastScreenPos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setLastScreenPos(const QPointF &lastScreenPos)
+{
+ d->lastScreenPos = lastScreenPos;
+}
+
+/*!
+ Returns the pressure of this touch point.
+*/
+qreal QGraphicsSceneTouchEvent::TouchPoint::pressure() const
+{
+ return d->pressure;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setPressure(qreal pressure)
+{
+ d->pressure = pressure;
+}
+
QT_END_NAMESPACE
#endif // QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicssceneevent.h b/src/gui/graphicsview/qgraphicssceneevent.h
index be50e96..8ae3a99 100644
--- a/src/gui/graphicsview/qgraphicssceneevent.h
+++ b/src/gui/graphicsview/qgraphicssceneevent.h
@@ -302,6 +302,70 @@ public:
void setNewPos(const QPointF &pos);
};
+class QGraphicsSceneTouchEventPrivate;
+class QGraphicsSceneTouchEventTouchPointPrivate;
+class Q_GUI_EXPORT QGraphicsSceneTouchEvent : public QGraphicsSceneEvent
+{
+public:
+ QGraphicsSceneTouchEvent(Type type = None);
+ ~QGraphicsSceneTouchEvent();
+
+ class Q_GUI_EXPORT TouchPoint
+ {
+ public:
+ TouchPoint();
+ ~TouchPoint();
+
+ int id() const;
+ void setId(int id);
+
+ Qt::TouchPointState state() const;
+ void setState(Qt::TouchPointState state);
+
+ QPointF pos() const;
+ void setPos(const QPointF &pos);
+
+ QPointF startPos() const;
+ void setStartPos(const QPointF &startPos);
+
+ QPointF lastPos() const;
+ void setLastPos(const QPointF &lastPos);
+
+ QPointF scenePos() const;
+ void setScenePos(const QPointF &scenePos);
+
+ QPointF startScenePos() const;
+ void setStartScenePos(const QPointF &startScenePos);
+
+ QPointF lastScenePos() const;
+ void setLastScenePos(const QPointF &lastScenePos);
+
+ QPointF screenPos() const;
+ void setScreenPos(const QPointF &screenPos);
+
+ QPointF startScreenPos() const;
+ void setStartScreenPos(const QPointF &startScreenPos);
+
+ QPointF lastScreenPos() const;
+ void setLastScreenPos(const QPointF &lastScreenPos);
+
+ qreal pressure() const; // 0.0 -> 1.0
+ void setPressure(qreal pressure);
+
+ private:
+ QGraphicsSceneTouchEventTouchPointPrivate *d;
+ };
+
+ const QList<TouchPoint *> &touchPoints() const;
+ void setTouchPoints(const QList<TouchPoint *> &touchPoints);
+
+ Qt::KeyboardModifiers modifiers() const;
+ void setModifiers(Qt::KeyboardModifiers modifiers);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsSceneTouchEvent);
+};
+
#endif // QT_NO_GRAPHICSVIEW
QT_END_NAMESPACE
diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp
index a661441..f95d328 100644
--- a/src/gui/graphicsview/qgraphicsview.cpp
+++ b/src/gui/graphicsview/qgraphicsview.cpp
@@ -2926,6 +2926,28 @@ bool QGraphicsView::viewportEvent(QEvent *event)
d->scene->d_func()->updateAll = false;
}
break;
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ {
+ if (!isEnabled())
+ return false;
+ QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
+ switch (touchEvent->type()) {
+ case QEvent::TouchBegin:
+ d->touchBeginEvent(touchEvent);
+ break;
+ case QEvent::TouchUpdate:
+ d->touchUpdateEvent(touchEvent);
+ break;
+ case QEvent::TouchEnd:
+ d->touchEndEvent(touchEvent);
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
default:
break;
}
@@ -3864,6 +3886,90 @@ void QGraphicsView::resetTransform()
setTransform(QTransform());
}
+static void qt_convertTouchEventToGraphicsSceneTouchEvent(QGraphicsViewPrivate *d, QTouchEvent *originalEvent, QGraphicsSceneTouchEvent *touchEvent)
+{
+ QList<QTouchEvent::TouchPoint *> originalTouchPoints = originalEvent->touchPoints();
+ QList<QGraphicsSceneTouchEvent::TouchPoint *> touchPoints;
+ for (int i = 0; i < originalTouchPoints.count(); ++i) {
+ QTouchEvent::TouchPoint *originalTouchPoint = originalTouchPoints.at(i);
+
+ QGraphicsSceneTouchEvent::TouchPoint *touchPoint = new QGraphicsSceneTouchEvent::TouchPoint();
+ touchPoint->setId(originalTouchPoint->id());
+ touchPoint->setState(originalTouchPoint->state());
+ // the scene will set the pos before delivering to an item
+ touchPoint->setScenePos(d->mapToScene(originalTouchPoint->pos()));
+ touchPoint->setScreenPos(originalTouchPoint->globalPos());
+ // the scene will set the startPos before delivering to an item
+ touchPoint->setStartScenePos(d->mapToScene(originalTouchPoint->startPos()));
+ touchPoint->setStartScreenPos(originalTouchPoint->startGlobalPos());
+ // the scene will set the lastPos before delivering to an item
+ touchPoint->setLastScenePos(d->mapToScene(originalTouchPoint->lastPos()));
+ touchPoint->setLastScreenPos(originalTouchPoint->lastGlobalPos());
+ touchPoint->setPressure(originalTouchPoint->pressure());
+
+ touchPoints.append(touchPoint);
+ }
+
+ touchEvent->setTouchPoints(touchPoints);
+ touchEvent->setModifiers(originalEvent->modifiers());
+}
+
+QPointF QGraphicsViewPrivate::mapToScene(const QPointF &point) const
+{
+ QPointF p = point;
+ p.rx() += horizontalScroll();
+ p.ry() += verticalScroll();
+ return identityMatrix ? p : matrix.inverted().map(p);
+}
+
+void QGraphicsViewPrivate::touchBeginEvent(QTouchEvent *event)
+{
+ Q_Q(QGraphicsView);
+
+ if (!scene || !sceneInteractionAllowed)
+ return;
+
+ // Convert and deliver the touch event to the scene.
+ QGraphicsSceneTouchEvent touchEvent(QEvent::GraphicsSceneTouchBegin);
+ touchEvent.setWidget(q->viewport());
+ qt_convertTouchEventToGraphicsSceneTouchEvent(this, event, &touchEvent);
+ touchEvent.setAccepted(false);
+ QApplication::sendEvent(scene, &touchEvent);
+ event->setAccepted(touchEvent.isAccepted());
+}
+
+void QGraphicsViewPrivate::touchUpdateEvent(QTouchEvent *event)
+{
+ Q_Q(QGraphicsView);
+
+ if (!scene || !sceneInteractionAllowed)
+ return;
+
+ // Convert and deliver the touch event to the scene.
+ QGraphicsSceneTouchEvent touchEvent(QEvent::GraphicsSceneTouchUpdate);
+ touchEvent.setWidget(q->viewport());
+ qt_convertTouchEventToGraphicsSceneTouchEvent(this, event, &touchEvent);
+ touchEvent.setAccepted(false);
+ QApplication::sendEvent(scene, &touchEvent);
+ event->setAccepted(touchEvent.isAccepted());
+}
+
+void QGraphicsViewPrivate::touchEndEvent(QTouchEvent *event)
+{
+ Q_Q(QGraphicsView);
+
+ if (!scene || !sceneInteractionAllowed)
+ return;
+
+ // Convert and deliver the touch event to the scene.
+ QGraphicsSceneTouchEvent touchEvent(QEvent::GraphicsSceneTouchEnd);
+ touchEvent.setWidget(q->viewport());
+ qt_convertTouchEventToGraphicsSceneTouchEvent(this, event, &touchEvent);
+ touchEvent.setAccepted(false);
+ QApplication::sendEvent(scene, &touchEvent);
+ event->setAccepted(touchEvent.isAccepted());
+}
+
QT_END_NAMESPACE
#include "moc_qgraphicsview.cpp"
diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h
index 2109673..e9479f3 100644
--- a/src/gui/graphicsview/qgraphicsview_p.h
+++ b/src/gui/graphicsview/qgraphicsview_p.h
@@ -182,6 +182,11 @@ public:
const QTransform &worldTransform,
bool allItems,
const QRegion &exposedRegion) const;
+
+ QPointF mapToScene(const QPointF &point) const;
+ void touchBeginEvent(QTouchEvent *event);
+ void touchUpdateEvent(QTouchEvent *event);
+ void touchEndEvent(QTouchEvent *event);
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index d5a96bd..52d6a70 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -85,6 +85,7 @@
#include <stdlib.h>
#include "qapplication_p.h"
+#include "qevent_p.h"
#include "qwidget_p.h"
#include "qapplication.h"
@@ -3709,19 +3710,10 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
QPoint relpos = mouse->pos();
if (e->spontaneous()) {
-
if (e->type() == QEvent::MouseButtonPress) {
- QWidget *fw = w;
- while (fw) {
- if (fw->isEnabled()
- && QApplicationPrivate::shouldSetFocus(fw, Qt::ClickFocus)) {
- fw->setFocus(Qt::MouseFocusReason);
- break;
- }
- if (fw->isWindow())
- break;
- fw = fw->parentWidget();
- }
+ QApplicationPrivate::giveFocusAccordingToFocusPolicy(w,
+ Qt::ClickFocus,
+ Qt::MouseFocusReason);
}
if (e->type() == QEvent::MouseMove && mouse->buttons() == 0) {
@@ -3803,17 +3795,9 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
bool eventAccepted = wheel->isAccepted();
if (e->spontaneous()) {
- QWidget *fw = w;
- while (fw) {
- if (fw->isEnabled()
- && QApplicationPrivate::shouldSetFocus(fw, Qt::WheelFocus)) {
- fw->setFocus(Qt::MouseFocusReason);
- break;
- }
- if (fw->isWindow())
- break;
- fw = fw->parentWidget();
- }
+ QApplicationPrivate::giveFocusAccordingToFocusPolicy(w,
+ Qt::WheelFocus,
+ Qt::MouseFocusReason);
}
while (w) {
@@ -4018,7 +4002,41 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
}
break;
#endif
+ case QEvent::TouchBegin:
+ // Note: TouchUpdate and TouchEnd events are sent to d->currentMultitouchWidget and never propagated
+ {
+ QWidget *widget = static_cast<QWidget *>(receiver);
+ QTouchEvent *touchEvent = static_cast<QTouchEvent *>(e);
+ bool eventAccepted = touchEvent->isAccepted();
+
+ if (widget->testAttribute(Qt::WA_AcceptTouchEvents) && e->spontaneous()) {
+ // give the widget focus if the focus policy allows it
+ QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget,
+ Qt::ClickFocus,
+ Qt::MouseFocusReason);
+ }
+
+ while (widget) {
+ // first, try to deliver the touch event
+ touchEvent->ignore();
+ res = widget->testAttribute(Qt::WA_AcceptTouchEvents)
+ && d->notify_helper(widget, touchEvent);
+ eventAccepted = touchEvent->isAccepted();
+ touchEvent->spont = false;
+ if (res && eventAccepted) {
+ // the first widget to accept the TouchBegin gets an implicit grab.
+ d->currentMultitouchWidget = widget;
+ break;
+ } else if (widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) {
+ break;
+ }
+ widget = widget->parentWidget();
+ d->updateTouchPointsForWidget(widget, touchEvent);
+ }
+ touchEvent->setAccepted(eventAccepted);
+ break;
+ }
default:
res = d->notify_helper(receiver, e);
break;
@@ -4985,6 +5003,23 @@ Qt::LayoutDirection QApplication::keyboardInputDirection()
return qt_keymapper_private()->keyboardInputDirection;
}
+void QApplicationPrivate::giveFocusAccordingToFocusPolicy(QWidget *widget,
+ Qt::FocusPolicy focusPolicy,
+ Qt::FocusReason focusReason)
+{
+ QWidget *focusWidget = widget;
+ while (focusWidget) {
+ if (focusWidget->isEnabled()
+ && QApplicationPrivate::shouldSetFocus(focusWidget, focusPolicy)) {
+ focusWidget->setFocus(focusReason);
+ break;
+ }
+ if (focusWidget->isWindow())
+ break;
+ focusWidget = focusWidget->parentWidget();
+ }
+}
+
bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy)
{
QWidget *f = w;
@@ -4998,6 +5033,19 @@ bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy)
return true;
}
+void QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent)
+{
+ for (int i = 0; i < touchEvent->_touchPoints.count(); ++i) {
+ QTouchEvent::TouchPoint *touchPoint = touchEvent->_touchPoints.at(i);
+
+ // preserve the sub-pixel resolution
+ const QPointF delta = touchPoint->d->globalPos - touchPoint->d->globalPos.toPoint();
+ touchPoint->d->pos = widget->mapFromGlobal(touchPoint->d->globalPos.toPoint()) + delta;
+ touchPoint->d->startPos = widget->mapFromGlobal(touchPoint->d->startGlobalPos.toPoint()) + delta;
+ touchPoint->d->lastPos = widget->mapFromGlobal(touchPoint->d->lastGlobalPos.toPoint()) + delta;
+ }
+}
+
QT_END_NAMESPACE
#include "moc_qapplication.cpp"
diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h
index 7487f0a..ce7110d 100644
--- a/src/gui/kernel/qapplication_p.h
+++ b/src/gui/kernel/qapplication_p.h
@@ -55,6 +55,7 @@
//
#include "QtGui/qapplication.h"
+#include "QtGui/qevent.h"
#include "QtGui/qfont.h"
#include "QtGui/qcursor.h"
#include "QtGui/qregion.h"
@@ -77,10 +78,7 @@ class QClipboard;
class QGraphicsScene;
class QGraphicsSystem;
class QInputContext;
-class QKeyEvent;
-class QMouseEvent;
class QObject;
-class QWheelEvent;
class QWidget;
extern bool qt_is_gui_used;
@@ -189,6 +187,12 @@ extern "C" {
}
#endif
+#if defined(Q_WS_WIN)
+typedef BOOL (WINAPI *qt_RegisterTouchWindowPtr)(HWND, ULONG);
+typedef BOOL (WINAPI *qt_GetTouchInputInfoPtr)(HANDLE, UINT, PVOID, int);
+typedef BOOL (WINAPI *qt_CloseTouchInputHandlePtr)(HANDLE);
+#endif
+
class QScopedLoopLevelCounter
{
QThreadData *threadData;
@@ -424,12 +428,34 @@ public:
void sendSyntheticEnterLeave(QWidget *widget);
#endif
+ QPointer<QWidget> currentMultitouchWidget;
+ static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent);
+
+#if defined(Q_WS_WIN)
+ static qt_RegisterTouchWindowPtr RegisterTouchWindow;
+ static qt_GetTouchInputInfoPtr GetTouchInputInfo;
+ static qt_CloseTouchInputHandlePtr CloseTouchInputHandle;
+
+ QMap<DWORD, int> touchInputIDToTouchPointID;
+ QVector<QTouchEvent::TouchPoint *> allTouchPoints;
+ QList<QTouchEvent::TouchPoint *> currentTouchPoints, activeTouchPoints;
+
+ void initializeMultitouch();
+ void insertActiveTouch(QTouchEvent::TouchPoint *touchPoint);
+ void removeActiveTouch(QTouchEvent::TouchPoint *touchPoint);
+ bool translateTouchEvent(const MSG &msg);
+#endif
+
private:
#ifdef Q_WS_QWS
QMap<const QScreen*, QRect> maxWindowRects;
#endif
static QApplicationPrivate *self;
+
+ static void giveFocusAccordingToFocusPolicy(QWidget *w,
+ Qt::FocusPolicy focusPolicy,
+ Qt::FocusReason focusReason);
static bool shouldSetFocus(QWidget *w, Qt::FocusPolicy policy);
};
diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp
index fae0335..cef8cf2 100644
--- a/src/gui/kernel/qapplication_win.cpp
+++ b/src/gui/kernel/qapplication_win.cpp
@@ -88,6 +88,7 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c
#include "qdebug.h"
#include <private/qkeymapper_p.h>
#include <private/qlocale_p.h>
+#include "qevent_p.h"
//#define ALIEN_DEBUG
@@ -112,6 +113,39 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c
# include <winable.h>
#endif
+#ifndef WM_TOUCHMOVE
+
+# define WM_TOUCHMOVE 0x0240
+# define WM_TOUCHDOWN 0x0241
+# define WM_TOUCHUP 0x0242
+
+# define TOUCHEVENTF_MOVE 0x0001
+# define TOUCHEVENTF_DOWN 0x0002
+# define TOUCHEVENTF_UP 0x0004
+# define TOUCHEVENTF_INRANGE 0x0008
+# define TOUCHEVENTF_PRIMARY 0x0010
+# define TOUCHEVENTF_NOCOALESCE 0x0020
+# define TOUCHEVENTF_PEN 0x0040
+
+# define TOUCHINPUTMASKF_TIMEFROMSYSTEM 0x0001
+# define TOUCHINPUTMASKF_EXTRAINFO 0x0002
+# define TOUCHINPUTMASKF_CONTACTAREA 0x0004
+
+typedef struct tagTOUCHINPUT
+{
+ LONG x;
+ LONG y;
+ HANDLE hSource;
+ DWORD dwID;
+ DWORD dwFlags;
+ DWORD dwMask;
+ DWORD dwTime;
+ ULONG_PTR dwExtraInfo;
+ DWORD cxContact;
+ DWORD cyContact;
+} TOUCHINPUT, *PTOUCHINPUT;
+
+#endif
#ifndef FLASHW_STOP
typedef struct {
@@ -856,6 +890,8 @@ void qt_init(QApplicationPrivate *priv, int)
if (ptrUpdateLayeredWindow && !ptrUpdateLayeredWindowIndirect)
ptrUpdateLayeredWindowIndirect = qt_updateLayeredWindowIndirect;
#endif
+
+ priv->initializeMultitouch();
}
/*****************************************************************************
@@ -1726,6 +1762,11 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam
result = widget->translateWheelEvent(msg);
} else {
switch (message) {
+ case WM_TOUCHMOVE:
+ case WM_TOUCHDOWN:
+ case WM_TOUCHUP:
+ result = getQApplicationPrivateInternal()->translateTouchEvent(msg);
+ break;
case WM_KEYDOWN: // keyboard event
case WM_SYSKEYDOWN:
qt_keymapper_private()->updateKeyMap(msg);
@@ -3953,4 +3994,151 @@ void QSessionManager::cancel()
#endif //QT_NO_SESSIONMANAGER
+qt_RegisterTouchWindowPtr QApplicationPrivate::RegisterTouchWindow = 0;
+qt_GetTouchInputInfoPtr QApplicationPrivate::GetTouchInputInfo = 0;
+qt_CloseTouchInputHandlePtr QApplicationPrivate::CloseTouchInputHandle = 0;
+
+void QApplicationPrivate::initializeMultitouch()
+{
+ QLibrary library(QLatin1String("user32"));
+ RegisterTouchWindow = static_cast<qt_RegisterTouchWindowPtr>(library.resolve("RegisterTouchWindow"));
+ GetTouchInputInfo = static_cast<qt_GetTouchInputInfoPtr>(library.resolve("GetTouchInputInfo"));
+ CloseTouchInputHandle = static_cast<qt_CloseTouchInputHandlePtr>(library.resolve("CloseTouchInputHandle"));
+
+ currentMultitouchWidget = 0;
+ touchInputIDToTouchPointID.clear();
+ allTouchPoints.clear();
+ currentTouchPoints.clear();
+ activeTouchPoints.clear();
+}
+
+void QApplicationPrivate::insertActiveTouch(QTouchEvent::TouchPoint *touchPoint)
+{
+ // insort deviceNumber
+ int at = 0;
+ for (; at < currentTouchPoints.count(); ++at) {
+ if (currentTouchPoints.at(at)->id() > touchPoint->id())
+ break;
+ }
+ currentTouchPoints.insert(at, touchPoint);
+ activeTouchPoints = currentTouchPoints;
+
+ if (currentTouchPoints.count() > allTouchPoints.count()) {
+ qFatal("Qt: INTERNAL ERROR: currentTouchPoints.count() (%d) > allTouchPoints.count() (%d)",
+ currentTouchPoints.count(),
+ allTouchPoints.count());
+ }
+}
+
+void QApplicationPrivate::removeActiveTouch(QTouchEvent::TouchPoint *touchPoint)
+{
+ for (int i = qMin(currentTouchPoints.count() - 1, touchPoint->id()); i >= 0; --i) {
+ if (currentTouchPoints.at(i) == touchPoint) {
+ currentTouchPoints.removeAt(i);
+ break;
+ }
+ }
+
+ // leave activeTouchPoints unchanged, since we need to make sure
+ // that the Release for deviceNumber is sent
+}
+
+bool QApplicationPrivate::translateTouchEvent(const MSG &msg)
+{
+ Q_Q(QApplication);
+
+ bool sendTouchBegin = currentTouchPoints.isEmpty();
+ activeTouchPoints = currentTouchPoints;
+
+ QVector<TOUCHINPUT> winTouchInputs(msg.wParam);
+ memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * winTouchInputs.count());
+ QApplicationPrivate::GetTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT));
+ for (int i = 0; i < winTouchInputs.count(); ++i) {
+ const TOUCHINPUT &touchInput = winTouchInputs.at(i);
+
+ int touchPointID = touchInputIDToTouchPointID.value(touchInput.dwID, -1);
+ if (touchPointID == -1) {
+ touchPointID = touchInputIDToTouchPointID.count();
+ touchInputIDToTouchPointID.insert(touchInput.dwID, touchPointID);
+ }
+
+ if (allTouchPoints.count() <= touchPointID)
+ allTouchPoints.resize(touchPointID + 1);
+
+ QTouchEvent::TouchPoint *touchPoint = allTouchPoints.at(touchPointID);
+ if (!touchPoint)
+ touchPoint = allTouchPoints[touchPointID] = new QTouchEvent::TouchPoint(touchPointID);
+
+ // update state
+ bool down = touchPoint->d->state != Qt::TouchPointReleased;
+ QPointF globalPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.));
+ if (!down && (touchInput.dwFlags & TOUCHEVENTF_DOWN)) {
+ insertActiveTouch(touchPoint);
+ touchPoint->d->state = Qt::TouchPointPressed;
+ touchPoint->d->globalPos = touchPoint->d->startGlobalPos = touchPoint->d->lastGlobalPos = globalPos;
+ touchPoint->d->pressure = qreal(1.);
+ } else if (down && (touchInput.dwFlags & TOUCHEVENTF_UP)) {
+ removeActiveTouch(touchPoint);
+ touchPoint->d->state = Qt::TouchPointReleased;
+ touchPoint->d->lastGlobalPos = touchPoint->d->globalPos;
+ touchPoint->d->globalPos = globalPos;
+ touchPoint->d->pressure = qreal(0.);
+ } else if (down) {
+ touchPoint->d->state = globalPos == touchPoint->d->globalPos
+ ? Qt::TouchPointStationary
+ : Qt::TouchPointMoved;
+ touchPoint->d->lastGlobalPos = touchPoint->d->globalPos;
+ touchPoint->d->globalPos = globalPos;
+ // pressure should still be 1.
+ }
+ }
+ QApplicationPrivate::CloseTouchInputHandle((HANDLE) msg.lParam);
+
+ bool sendTouchEnd = currentTouchPoints.isEmpty();
+
+ if (activeTouchPoints.isEmpty())
+ return false;
+
+ if (sendTouchBegin) {
+ // the window under the first touch point gets the touch event
+ int firstTouchId = activeTouchPoints.first()->id();
+ const QPoint &globalPos = allTouchPoints.at(firstTouchId)->d->globalPos.toPoint();
+ QWidget *window = q->topLevelAt(globalPos);
+ if (window) {
+ QWidget *child = window->childAt(window->mapFromGlobal(globalPos));
+ if (!child)
+ child = window;
+ currentMultitouchWidget = child;
+ }
+ }
+
+ QWidget *widget = q->activePopupWidget();
+ if (!widget)
+ widget = currentMultitouchWidget;
+
+ if (sendTouchEnd) {
+ // reset currentMultitouchWindow when the last touch is released
+ currentMultitouchWidget = 0;
+ if (!currentTouchPoints.isEmpty()) {
+ qFatal("Qt: INTERNAL ERROR, currentTouchPoints should be empty!");
+ }
+ }
+
+ // deliver the event
+ if (widget && QApplicationPrivate::tryModalHelper(widget, 0)) {
+ QTouchEvent touchEvent((sendTouchBegin
+ ? QEvent::TouchBegin
+ : sendTouchEnd
+ ? QEvent::TouchEnd
+ : QEvent::TouchUpdate),
+ q->keyboardModifiers(), activeTouchPoints);
+ updateTouchPointsForWidget(widget, &touchEvent);
+
+ bool res = QApplication::sendSpontaneousEvent(widget, &touchEvent);
+ return (qt_tabletChokeMouse = res && touchEvent.isAccepted());
+ }
+
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index 8c7e47d..d571212 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -3506,4 +3506,168 @@ QMenubarUpdatedEvent::QMenubarUpdatedEvent(QMenuBar * const menuBar)
#endif
+/*! \class QTouchEvent
+ \brief The QTouchEvent class contains parameters that describe a touch event
+.
+ \since 4.6
+ \ingroup events
+
+ Touch events occur when pressing, releasing, or moving one or more
+ touch points on a touch device (such as a touch-screen or
+ track-pad), and if the widget has the Qt::WA_AcceptTouchEvents
+ attribute.
+
+ Like QMouseEvent, Qt automatically grabs the touch device on the
+ first press inside a widget; the widget will receive all touch
+ events until the last touch point is released.
+
+ A touch event contains a special accept flag that indicates
+ whether the receiver wants the event. By default, the event is
+ ignored. You should call accept() if the touch event is handled by
+ your widget. A touch event is propagated up the parent widget
+ chain until a widget accepts it with accept(), or an event filter
+ consumes it. If the touch event is neither accepted nor consumed,
+ then mouse events are simulated from the state of the first touch
+ point.
+
+ All touch events are of type QEvent::Touch. The touchPoints()
+ function returns a list of all touch points contained in the
+ event. Information about each touch point can be retreived using
+ the QTouchEvent::TouchPoint class.
+
+ The Qt::TouchPointState enum describes the different states that a
+ touch point may have.
+
+ QTouchEvent::TouchPoint Qt::TouchPointState Qt::WA_AcceptTouchEvents
+*/
+
+/*! \enum Qt::TouchPointState
+ \since 4.6
+
+ This enum represents the state of a touch point at the time the
+ QTouchEvent occurred.
+
+ \value TouchPointPressed The touch point is now pressed.
+ \value TouchPointMoved The touch point moved.
+ \value TouchPointStationary The touch point did not move.
+ \value TouchPointReleased The touch point was released.
+*/
+
+/*! \class QTouchEvent::TouchPoint
+ \brief The QTouchEvent::TouchPoint class provide information about a touch point in a QTouchEvent.
+ \since 4.6
+*/
+
+/*!
+ Constructs a QTouchEvent with the given \a type and \a
+ touchPoints. The \a modifiers are the current keyboard modifiers
+ at the time of the event.
+*/
+QTouchEvent::QTouchEvent(QEvent::Type type,
+ Qt::KeyboardModifiers modifiers,
+ const QList<TouchPoint *> &touchPoints)
+ : QInputEvent(type, modifiers), _touchPoints(touchPoints)
+{ }
+
+/*! \fn const QList<QTouchEvent::TouchPoint *> &QTouchEvent::touchPoints() const
+
+ Returns the list of touch points contained in the touch event.
+*/
+
+/*! \internal
+
+ Constructs a QTouchEvent::TouchPoint for use in a QTouchEvent.
+*/
+QTouchEvent::TouchPoint::TouchPoint(int id)
+ : d(new QTouchEventTouchPointPrivate(id))
+{ }
+
+/*! \internal
+
+ Destroys the QTouchEvent::TouchPoint.
+*/
+QTouchEvent::TouchPoint::~TouchPoint()
+{
+ delete d;
+}
+
+/*!
+ Returns the id number of this touch point. Id numbers are
+ sequential, starting at zero, meaning the first touch point has id
+ 0, the second has id 1, and so on...
+*/
+int QTouchEvent::TouchPoint::id() const
+{
+ return d->id;
+}
+
+/*!
+ Returns the current state of this touch point.
+*/
+Qt::TouchPointState QTouchEvent::TouchPoint::state() const
+{
+ return d->state;
+}
+
+/*!
+ Returns the position of this touch point, relative to the widget
+ that received the event.
+*/
+const QPointF &QTouchEvent::TouchPoint::pos() const
+{
+ return d->pos;
+}
+
+/*!
+ Returns the starting position of this touch point, relative to the
+ widget that received the event.
+*/
+const QPointF &QTouchEvent::TouchPoint::startPos() const
+{
+ return d->startPos;
+}
+
+/*!
+ Returns the position of this touch point from the previous touch
+ event, relative to the widget that received the event.
+*/
+const QPointF &QTouchEvent::TouchPoint::lastPos() const
+{
+ return d->lastPos;
+}
+
+/*!
+ Returns the global position of this touch point.
+*/
+const QPointF &QTouchEvent::TouchPoint::globalPos() const
+{
+ return d->globalPos;
+}
+
+/*!
+ Returns the global starting position of this touch point.
+*/
+const QPointF &QTouchEvent::TouchPoint::startGlobalPos() const
+{
+ return d->startGlobalPos;
+}
+
+/*!
+ Returns the global position of this touch point from the previous
+ touch event.
+*/
+const QPointF &QTouchEvent::TouchPoint::lastGlobalPos() const
+{
+ return d->lastGlobalPos;
+}
+
+/*!
+ Returns the pressure of this touch point. The return value is in
+ the range 0.0 to 1.0.
+*/
+qreal QTouchEvent::TouchPoint::pressure() const
+{
+ return d->pressure;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index 449730d..506e0c1 100644
--- a/src/gui/kernel/qevent.h
+++ b/src/gui/kernel/qevent.h
@@ -719,6 +719,49 @@ inline bool operator==(QKeyEvent *e, QKeySequence::StandardKey key){return (e ?
inline bool operator==(QKeySequence::StandardKey key, QKeyEvent *e){return (e ? e->matches(key) : false);}
#endif // QT_NO_SHORTCUT
+class QTouchEventTouchPointPrivate;
+class Q_GUI_EXPORT QTouchEvent : public QInputEvent
+{
+public:
+ class Q_GUI_EXPORT TouchPoint
+ {
+ public:
+ TouchPoint(int id = -1);
+ ~TouchPoint();
+
+ int id() const;
+
+ Qt::TouchPointState state() const;
+
+ const QPointF &pos() const;
+ const QPointF &startPos() const;
+ const QPointF &lastPos() const;
+
+ const QPointF &globalPos() const;
+ const QPointF &startGlobalPos() const;
+ const QPointF &lastGlobalPos() const;
+
+ qreal pressure() const; // 0.0 -> 1.0
+
+ private:
+ QTouchEventTouchPointPrivate *d;
+
+ friend class QApplicationPrivate;
+ };
+
+ QTouchEvent(QEvent::Type type,
+ Qt::KeyboardModifiers modifiers,
+ const QList<TouchPoint *> &touchPoints);
+
+ inline const QList<TouchPoint *> &touchPoints() const { return _touchPoints;
+ }
+
+protected:
+ QList<TouchPoint *> _touchPoints;
+
+ friend class QApplicationPrivate;
+};
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h
index cc94aad..5e24eeb 100644
--- a/src/gui/kernel/qevent_p.h
+++ b/src/gui/kernel/qevent_p.h
@@ -89,6 +89,22 @@ protected:
friend class QMouseEvent;
};
+class QTouchEventTouchPointPrivate
+{
+public:
+ inline QTouchEventTouchPointPrivate(int id)
+ : id(id),
+ state(Qt::TouchPointReleased),
+ pressure(qreal(-1.))
+ { }
+
+ int id;
+ Qt::TouchPointState state;
+ QPointF pos, startPos, lastPos;
+ QPointF globalPos, startGlobalPos, lastGlobalPos;
+ qreal pressure;
+};
+
QT_END_NAMESPACE
#endif // QEVENT_P_H
diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp
index ffbb341..b55f1c8 100644
--- a/src/gui/kernel/qwidget_win.cpp
+++ b/src/gui/kernel/qwidget_win.cpp
@@ -503,6 +503,10 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
}
}
+ // ### don't always register for touch events
+ if (QApplicationPrivate::RegisterTouchWindow && !desktop)
+ QApplicationPrivate::RegisterTouchWindow(id, 0);
+
q->setAttribute(Qt::WA_WState_Created); // accept move/resize events
hd = 0; // no display context