diff options
author | Jason Barron <jbarron@trolltech.com> | 2009-06-30 09:21:56 (GMT) |
---|---|---|
committer | Jason Barron <jbarron@trolltech.com> | 2009-06-30 09:21:56 (GMT) |
commit | 197df24edfe095a10e2bf65116796e027fea44e2 (patch) | |
tree | 4ffb08f614b550298663f90297c9e559ecb47a3c /src/gui/kernel/qapplication.cpp | |
parent | 1e84894225e31adf80a7a33da7f655fb5c38ea0e (diff) | |
parent | e3c1039d4d10aa383a1f681e7dd9c1129d22d8ca (diff) | |
download | Qt-197df24edfe095a10e2bf65116796e027fea44e2.zip Qt-197df24edfe095a10e2bf65116796e027fea44e2.tar.gz Qt-197df24edfe095a10e2bf65116796e027fea44e2.tar.bz2 |
Merge commit 'qt/master-stable' into 4.6-merged
Conflicts:
.gitignore
configure.exe
src/corelib/concurrent/qtconcurrentthreadengine.h
src/corelib/global/qnamespace.h
src/gui/graphicsview/qgraphicssceneevent.h
src/gui/kernel/qapplication.cpp
src/gui/kernel/qapplication.h
src/gui/kernel/qapplication_p.h
src/gui/kernel/qapplication_qws.cpp
src/gui/kernel/qwidget.h
src/gui/painting/qpaintengine_raster.cpp
src/gui/text/qfontdatabase.cpp
src/network/access/qnetworkaccesshttpbackend.cpp
tests/auto/network-settings.h
tests/auto/qscriptjstestsuite/qscriptjstestsuite.pro
tests/auto/qvariant/tst_qvariant.cpp
Diffstat (limited to 'src/gui/kernel/qapplication.cpp')
-rw-r--r-- | src/gui/kernel/qapplication.cpp | 402 |
1 files changed, 363 insertions, 39 deletions
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index a8ac9a1..7fee0e3 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** @@ -34,7 +34,7 @@ ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. +** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -88,10 +88,13 @@ #include <stdlib.h> #include "qapplication_p.h" +#include "qevent_p.h" #include "qwidget_p.h" #include "qapplication.h" +#include <private/qgesturemanager_p.h> + #ifdef Q_WS_WINCE #include "qdatetime.h" #include "qguifunctions_wince.h" @@ -100,6 +103,8 @@ extern bool qt_wince_is_mobile(); //qguifunctions_wince.cpp extern bool qt_wince_is_pocket_pc(); //qguifunctions_wince.cpp #endif +#include "qdatetime.h" + //#define ALIEN_DEBUG static void initResources() @@ -137,6 +142,14 @@ bool QApplicationPrivate::autoSipEnabled = false; bool QApplicationPrivate::autoSipEnabled = true; #endif +QGestureManager* QGestureManager::instance() +{ + QApplicationPrivate *d = qApp->d_func(); + if (!d->gestureManager) + d->gestureManager = new QGestureManager(qApp); + return d->gestureManager; +} + QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::Type type) : QCoreApplicationPrivate(argc, argv) { @@ -160,6 +173,8 @@ QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::T directPainters = 0; #endif + gestureManager = 0; + if (!self) self = this; } @@ -478,15 +493,12 @@ static inline bool isAlien(QWidget *widget) // ######## move to QApplicationPrivate // Default application palettes and fonts (per widget type) - -typedef QHash<QByteArray, QPalette> PaletteHash; Q_GLOBAL_STATIC(PaletteHash, app_palettes) PaletteHash *qt_app_palettes_hash() { return app_palettes(); } -typedef QHash<QByteArray, QFont> FontHash; Q_GLOBAL_STATIC(FontHash, app_fonts) FontHash *qt_app_fonts_hash() { @@ -899,6 +911,8 @@ void QApplicationPrivate::initialize() QApplicationPrivate::wheel_scroll_lines = 3; #endif #endif + + initializeMultitouch(); } /*! @@ -1050,6 +1064,8 @@ QApplication::~QApplication() delete QDragManager::self(); #endif + d->cleanupMultitouch(); + qt_cleanup(); if (QApplicationPrivate::widgetCount) @@ -1402,7 +1418,7 @@ void QApplication::setStyle(QStyle *style) #endif // QT_NO_STYLE_STYLESHEET QApplicationPrivate::app_style = style; QApplicationPrivate::app_style->setParent(qApp); // take ownership - + // take care of possible palette requirements of certain gui // styles. Do it before polishing the application since the style // might call QApplication::setPalette() itself @@ -2901,7 +2917,8 @@ QWidget *QApplicationPrivate::pickMouseReceiver(QWidget *candidate, const QPoint */ bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget, QWidget *nativeWidget, - QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver) + QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver, + bool spontaneous) { Q_ASSERT(receiver); Q_ASSERT(event); @@ -2954,7 +2971,11 @@ bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event, // We need this quard in case someone opens a modal dialog / popup. If that's the case // leaveAfterRelease is set to null, but we shall not update lastMouseReceiver. const bool wasLeaveAfterRelease = leaveAfterRelease != 0; - bool result = QApplication::sendSpontaneousEvent(receiver, event); + bool result; + if (spontaneous) + result = QApplication::sendSpontaneousEvent(receiver, event); + else + result = QApplication::sendEvent(receiver, event); if (!graphicsWidget && leaveAfterRelease && event->type() == QEvent::MouseButtonRelease && !event->buttons() && QWidget::mouseGrabber() != leaveAfterRelease) { @@ -3628,26 +3649,32 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QApplicationPrivate::mouse_buttons |= me->button(); else QApplicationPrivate::mouse_buttons &= ~me->button(); - } + } #if !defined(QT_NO_WHEELEVENT) || !defined(QT_NO_TABLETEVENT) - else if ( + else if (false # ifndef QT_NO_WHEELEVENT - e->type() == QEvent::Wheel -# else - false + || e->type() == QEvent::Wheel # endif # ifndef QT_NO_TABLETEVENT - || e->type() == QEvent::TabletMove - || e->type() == QEvent::TabletPress - || e->type() == QEvent::TabletRelease + || e->type() == QEvent::TabletMove + || e->type() == QEvent::TabletPress + || e->type() == QEvent::TabletRelease # endif - ) { + ) { QInputEvent *ie = static_cast<QInputEvent*>(e); QApplicationPrivate::modifier_buttons = ie->modifiers(); } #endif // !QT_NO_WHEELEVENT || !QT_NO_TABLETEVENT } + if (!d->grabbedGestures.isEmpty() && e->spontaneous() && receiver->isWidgetType()) { + const QEvent::Type t = e->type(); + if (t != QEvent::Gesture && t != QEvent::GraphicsSceneGesture) { + if (QGestureManager::instance()->filterEvent(static_cast<QWidget*>(receiver), e)) + return true; + } + } + // User input and window activation makes tooltips sleep switch (e->type()) { case QEvent::Wheel: @@ -3784,17 +3811,9 @@ bool QApplication::notify(QObject *receiver, QEvent *e) #endif 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) { @@ -3876,17 +3895,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) { @@ -4091,7 +4102,45 @@ bool QApplication::notify(QObject *receiver, QEvent *e) } break; #endif + case QEvent::TouchBegin: + // Note: TouchUpdate and TouchEnd events are 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 + bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents); + touchEvent->setWidget(widget); + touchEvent->setAccepted(acceptTouchEvents); + res = acceptTouchEvents && d->notify_helper(widget, touchEvent); + eventAccepted = touchEvent->isAccepted(); + widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, res && eventAccepted); + touchEvent->spont = false; + if (res && eventAccepted) { + // the first widget to accept the TouchBegin gets an implicit grab. + for (int i = 0; i < touchEvent->touchPoints().count(); ++i) { + const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i); + d->widgetForTouchPointId[touchPoint.id()] = widget; + } + break; + } else if (widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) { + break; + } + widget = widget->parentWidget(); + d->updateTouchPointsForWidget(widget, touchEvent); + } + + touchEvent->setAccepted(eventAccepted); + break; + } case QEvent::RequestSoftwareInputPanel: case QEvent::CloseSoftwareInputPanel: #ifndef QT_NO_IM @@ -5076,6 +5125,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; @@ -5089,6 +5155,57 @@ bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy) return true; } +/*! + \since 4.6 + + Adds custom gesture \a recognizer object. + + Qt takes ownership of the provided \a recognizer. + + \sa Qt::AA_EnableGestures, QGestureEvent +*/ +void QApplication::addGestureRecognizer(QGestureRecognizer *recognizer) +{ + QGestureManager::instance()->addRecognizer(recognizer); +} + +/*! + \since 4.6 + + Removes custom gesture \a recognizer object. + + \sa Qt::AA_EnableGestures, QGestureEvent +*/ +void QApplication::removeGestureRecognizer(QGestureRecognizer *recognizer) +{ + Q_D(QApplication); + if (!d->gestureManager) + return; + d->gestureManager->removeRecognizer(recognizer); +} + +/*! + \property QApplication::eventDeliveryDelayForGestures + \since 4.6 + + Specifies the \a delay before input events are delivered to the + gesture enabled widgets. + + The delay allows to postpone widget's input event handling until + gestures framework can successfully recognize a gesture. + + \sa QWidget::grabGesture +*/ +void QApplication::setEventDeliveryDelayForGestures(int delay) +{ + QGestureManager::instance()->setEventDeliveryDelay(delay); +} + +int QApplication::eventDeliveryDelayForGestures() +{ + return QGestureManager::instance()->eventDeliveryDelay(); +} + /*! \fn QDecoration &QApplication::qwsDecoration() Return the QWSDecoration used for decorating windows. @@ -5220,6 +5337,213 @@ bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy) This normally takes some time. Does nothing on other platforms. */ +void QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent) +{ + for (int i = 0; i < touchEvent->touchPoints().count(); ++i) { + QTouchEvent::TouchPoint &touchPoint = touchEvent->_touchPoints[i]; + + // preserve the sub-pixel resolution + QRectF rect = touchPoint.screenRect(); + const QPointF screenPos = rect.center(); + const QPointF delta = screenPos - screenPos.toPoint(); + + rect.moveCenter(widget->mapFromGlobal(screenPos.toPoint()) + delta); + touchPoint.setRect(rect); + touchPoint.setStartPos(widget->mapFromGlobal(touchPoint.startScreenPos().toPoint()) + delta); + touchPoint.setLastPos(widget->mapFromGlobal(touchPoint.lastScreenPos().toPoint()) + delta); + } +} + +void QApplicationPrivate::initializeMultitouch() +{ + widgetForTouchPointId.clear(); + appCurrentTouchPoints.clear(); + + initializeMultitouch_sys(); +} + +void QApplicationPrivate::cleanupMultitouch() +{ + cleanupMultitouch_sys(); + + widgetForTouchPointId.clear(); + appCurrentTouchPoints.clear(); +} + +int QApplicationPrivate::findClosestTouchPointId(const QPointF &screenPos) +{ + int closestTouchPointId = -1; + qreal closestDistance = qreal(0.); + foreach (const QTouchEvent::TouchPoint &touchPoint, appCurrentTouchPoints) { + qreal distance = QLineF(screenPos, touchPoint.screenPos()).length(); + if (closestTouchPointId == -1 || distance < closestDistance) { + closestTouchPointId = touchPoint.id(); + closestDistance = distance; + } + } + return closestTouchPointId; +} + +void QApplicationPrivate::translateRawTouchEvent(QWidget *window, + QTouchEvent::DeviceType deviceType, + const QList<QTouchEvent::TouchPoint> &touchPoints) +{ + QApplicationPrivate *d = self; + QApplication *q = self->q_func(); + + typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints; + QHash<QWidget *, StatesAndTouchPoints> widgetsNeedingEvents; + + for (int i = 0; i < touchPoints.count(); ++i) { + QTouchEvent::TouchPoint touchPoint = touchPoints.at(i); + + // update state + QWidget *widget = 0; + switch (touchPoint.state()) { + case Qt::TouchPointPressed: + { + if (deviceType == QTouchEvent::TouchPad) { + // on touch-pads, send all touch points to the same widget + widget = d->widgetForTouchPointId.isEmpty() + ? 0 + : d->widgetForTouchPointId.constBegin().value(); + } + + if (!widget) { + // determine which widget this event will go to + if (!window) + window = q->topLevelAt(touchPoint.screenPos().toPoint()); + if (!window) + continue; + widget = window->childAt(window->mapFromGlobal(touchPoint.screenPos().toPoint())); + if (!widget) + widget = window; + } + + if (deviceType == QTouchEvent::TouchScreen) { + int closestTouchPointId = d->findClosestTouchPointId(touchPoint.screenPos()); + QWidget *closestWidget = d->widgetForTouchPointId.value(closestTouchPointId); + if (closestWidget + && (widget->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget))) { + widget = closestWidget; + } + } + + d->widgetForTouchPointId[touchPoint.id()] = widget; + touchPoint.setStartScreenPos(touchPoint.screenPos()); + touchPoint.setLastScreenPos(touchPoint.screenPos()); + touchPoint.setStartNormalizedPos(touchPoint.normalizedPos()); + touchPoint.setLastNormalizedPos(touchPoint.normalizedPos()); + if (touchPoint.pressure() < qreal(0.)) + touchPoint.setPressure(qreal(1.)); + d->appCurrentTouchPoints.insert(touchPoint.id(), touchPoint); + break; + } + case Qt::TouchPointReleased: + { + widget = d->widgetForTouchPointId.take(touchPoint.id()); + if (!widget) + continue; + + QTouchEvent::TouchPoint previousTouchPoint = d->appCurrentTouchPoints.take(touchPoint.id()); + touchPoint.setStartScreenPos(previousTouchPoint.startScreenPos()); + touchPoint.setLastScreenPos(previousTouchPoint.screenPos()); + touchPoint.setStartNormalizedPos(previousTouchPoint.startNormalizedPos()); + touchPoint.setLastNormalizedPos(previousTouchPoint.normalizedPos()); + if (touchPoint.pressure() < qreal(0.)) + touchPoint.setPressure(qreal(0.)); + break; + } + default: + widget = d->widgetForTouchPointId.value(touchPoint.id()); + if (!widget) + continue; + + Q_ASSERT(d->appCurrentTouchPoints.contains(touchPoint.id())); + QTouchEvent::TouchPoint previousTouchPoint = d->appCurrentTouchPoints.value(touchPoint.id()); + touchPoint.setStartScreenPos(previousTouchPoint.startScreenPos()); + touchPoint.setLastScreenPos(previousTouchPoint.screenPos()); + touchPoint.setStartNormalizedPos(previousTouchPoint.startNormalizedPos()); + touchPoint.setLastNormalizedPos(previousTouchPoint.normalizedPos()); + if (touchPoint.pressure() < qreal(0.)) + touchPoint.setPressure(qreal(1.)); + d->appCurrentTouchPoints[touchPoint.id()] = touchPoint; + break; + } + Q_ASSERT(widget != 0); + + // make the *scene* functions return the same as the *screen* functions + touchPoint.setSceneRect(touchPoint.screenRect()); + touchPoint.setStartScenePos(touchPoint.startScreenPos()); + touchPoint.setLastScenePos(touchPoint.lastScreenPos()); + + StatesAndTouchPoints &maskAndPoints = widgetsNeedingEvents[widget]; + maskAndPoints.first |= touchPoint.state(); + if (touchPoint.isPrimary()) + maskAndPoints.first |= Qt::TouchPointPrimary; + maskAndPoints.second.append(touchPoint); + } + + if (widgetsNeedingEvents.isEmpty()) + return; + + QHash<QWidget *, StatesAndTouchPoints>::ConstIterator it = widgetsNeedingEvents.constBegin(); + const QHash<QWidget *, StatesAndTouchPoints>::ConstIterator end = widgetsNeedingEvents.constEnd(); + for (; it != end; ++it) { + QWidget *widget = it.key(); + if (!QApplicationPrivate::tryModalHelper(widget, 0)) + continue; + + QEvent::Type eventType; + switch (it.value().first & Qt::TouchPointStateMask) { + case Qt::TouchPointPressed: + eventType = QEvent::TouchBegin; + break; + case Qt::TouchPointReleased: + eventType = QEvent::TouchEnd; + break; + case Qt::TouchPointStationary: + // don't send the event if nothing changed + continue; + default: + eventType = QEvent::TouchUpdate; + break; + } + + QTouchEvent touchEvent(eventType, + deviceType, + q->keyboardModifiers(), + it.value().first, + it.value().second); + updateTouchPointsForWidget(widget, &touchEvent); + + switch (touchEvent.type()) { + case QEvent::TouchBegin: + { + // if the TouchBegin handler recurses, we assume that means the event + // has been implicitly accepted and continue to send touch events + widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent); + (void ) QApplication::sendSpontaneousEvent(widget, &touchEvent); + break; + } + default: + if (widget->testAttribute(Qt::WA_WState_AcceptedTouchBeginEvent)) { + if (touchEvent.type() == QEvent::TouchEnd) + widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, false); + (void) QApplication::sendSpontaneousEvent(widget, &touchEvent); + } + break; + } + } +} + +Q_GUI_EXPORT void qt_translateRawTouchEvent(QWidget *window, + QTouchEvent::DeviceType deviceType, + const QList<QTouchEvent::TouchPoint> &touchPoints) +{ + QApplicationPrivate::translateRawTouchEvent(window, deviceType, touchPoints); +} + QT_END_NAMESPACE #include "moc_qapplication.cpp" |