From 0fd6390800969d174dba819c54c4183a99e8f83c Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Tue, 27 Oct 2009 09:14:28 +0100 Subject: Implement support for wheel delta with finer resolution than 15 deg. At the moment, Qt, in many places, does not really understand that a mouse wheel, or touch pad, might operate on a much higher granularity than 15 degrees (that is, a delta of 120). This is clear disadvantage on mac, since the mighty mouse, and track pad, got a resolution that is close to 1 degree. This is called pixel scrolling. This patch first and formost changes the implementation of QAbstractSlider::wheelEvent to _really_ understand what to do when delta is less than 120. Rather than accumulate delta until 120 is reached, then scroll with a value equal to: offset * step * QApplication::wheelScrollLines (default = 3), we multiply offset directly, before waiting for 120. This means that event tough offset is below 120, multiplying it with wheelScrollLines and step will very often give a value over 120, menaing we can scroll much earlier and _much more_ fined grained. This also fixes some auto tests that was ifdeffed out because of specialised mac code written inside this function from before. (NB: we still plan to introduce a new event for pixel scrolling, perhaps for Qt-4.7) Rev-By: Andreas Rev-By: denis --- src/gui/kernel/qapplication.cpp | 4 -- src/gui/kernel/qapplication_mac.mm | 37 +++--------------- src/gui/kernel/qcocoaview_mac.mm | 24 ++++++------ src/gui/widgets/qabstractslider.cpp | 44 ++++++++++------------ tests/auto/qabstractslider/tst_qabstractslider.cpp | 16 -------- 5 files changed, 38 insertions(+), 87 deletions(-) diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 7c38d4b..85b055e 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -940,12 +940,8 @@ void QApplicationPrivate::initialize() graphics_system = QGraphicsSystemFactory::create(graphics_system_name); #endif #ifndef QT_NO_WHEELEVENT -#ifdef Q_OS_MAC - QApplicationPrivate::wheel_scroll_lines = 1; -#else QApplicationPrivate::wheel_scroll_lines = 3; #endif -#endif initializeMultitouch(); } diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm index 771cddc..84e0d50 100644 --- a/src/gui/kernel/qapplication_mac.mm +++ b/src/gui/kernel/qapplication_mac.mm @@ -1697,15 +1697,14 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event // (actually two events; one for horizontal and one for vertical). // As a results of this, and to make sure we dont't receive duplicate events, // we try to detect when this happend by checking the 'compatibilityEvent'. - const int scrollFactor = 4 * 8; SInt32 mdelt = 0; GetEventParameter(event, kEventParamMouseWheelSmoothHorizontalDelta, typeSInt32, 0, sizeof(mdelt), 0, &mdelt); - wheel_deltaX = mdelt * scrollFactor; + wheel_deltaX = mdelt; mdelt = 0; GetEventParameter(event, kEventParamMouseWheelSmoothVerticalDelta, typeSInt32, 0, sizeof(mdelt), 0, &mdelt); - wheel_deltaY = mdelt * scrollFactor; + wheel_deltaY = mdelt; GetEventParameter(event, kEventParamEventRef, typeEventRef, 0, sizeof(compatibilityEvent), 0, &compatibilityEvent); } else if (ekind == kEventMouseWheelMoved) { @@ -1718,31 +1717,11 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, 0, sizeof(axis), 0, &axis); - // The 'new' event has acceleration applied by the OS, while the old (on - // Carbon only), has not. So we introduce acceleration here to be consistent. - // The acceleration is trying to respect both pixel based and line scrolling, - // which turns out to be rather difficult. - int linesToScroll = mdelt > 0 ? 1 : -1; - static QTime t; - int elapsed = t.elapsed(); - t.restart(); - if (elapsed < 20) - linesToScroll *= 120; - else if (elapsed < 30) - linesToScroll *= 60; - else if (elapsed < 50) - linesToScroll *= 30; - else if (elapsed < 100) - linesToScroll *= 6; - else if (elapsed < 200) - linesToScroll *= 3; - else if (elapsed < 300) - linesToScroll *= 2; - + // Remove acceleration, and use either -120 or 120 as delta: if (axis == kEventMouseWheelAxisX) - wheel_deltaX = linesToScroll * 120; + wheel_deltaX = qBound(-120, int(mdelt * 10000), 120); else - wheel_deltaY = linesToScroll * 120; + wheel_deltaY = qBound(-120, int(mdelt * 10000), 120); } } @@ -2695,11 +2674,7 @@ int QApplication::keyboardInputInterval() void QApplication::setWheelScrollLines(int n) { - Q_UNUSED(n); - // On Mac, acceleration is handled by the OS. Multiplying wheel scroll - // deltas with n will not be as cross platform as one might think! So - // we choose to go native in this case (and let wheel_scroll_lines == 1). - // QApplicationPrivate::wheel_scroll_lines = n; + QApplicationPrivate::wheel_scroll_lines = n; } int QApplication::wheelScrollLines() diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index d49c150..ecc6bc9 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -795,23 +795,23 @@ extern "C" { const EventRef carbonEvent = (EventRef)[theEvent eventRef]; const UInt32 carbonEventKind = carbonEvent ? ::GetEventKind(carbonEvent) : 0; - if (carbonEventKind == kEventMouseScroll) { + const bool scrollEvent = carbonEventKind == kEventMouseScroll; + + if (scrollEvent) { // The mouse device containts pixel scroll wheel support (Mighty Mouse, Trackpad). // Since deviceDelta is delivered as pixels rather than degrees, we need to // convert from pixels to degrees in a sensible manner. // It looks like four degrees per pixel behaves most native. // Qt expects the unit for delta to be 1/8 of a degree: - const int scrollFactor = 4 * 8; - deltaX = (int)[theEvent deviceDeltaX] * scrollFactor; - deltaY = (int)[theEvent deviceDeltaY] * scrollFactor; - deltaZ = (int)[theEvent deviceDeltaZ] * scrollFactor; - } else { // carbonEventKind == kEventMouseWheelMoved - // Mouse wheel deltas seem to tick in at increments of 0.1. - // Qt widgets expect the delta to be a multiple of 120. - const int scrollFactor = 10 * 120; - deltaX = [theEvent deltaX] * scrollFactor; - deltaY = [theEvent deltaY] * scrollFactor; - deltaZ = [theEvent deltaZ] * scrollFactor; + deltaX = [theEvent deviceDeltaX]; + deltaY = [theEvent deviceDeltaY]; + deltaZ = [theEvent deviceDeltaZ]; + } else { + // carbonEventKind == kEventMouseWheelMoved + // Remove acceleration, and use either -120 or 120 as delta: + deltaX = qBound(-120, int([theEvent deltaX] * 10000), 120); + deltaY = qBound(-120, int([theEvent deltaY] * 10000), 120); + deltaZ = qBound(-120, int([theEvent deltaZ] * 10000), 120); } if (deltaX != 0) { diff --git a/src/gui/widgets/qabstractslider.cpp b/src/gui/widgets/qabstractslider.cpp index 588a48e..fec9fab 100644 --- a/src/gui/widgets/qabstractslider.cpp +++ b/src/gui/widgets/qabstractslider.cpp @@ -693,29 +693,27 @@ void QAbstractSlider::wheelEvent(QWheelEvent * e) if (e->orientation() != d->orientation && !rect().contains(e->pos())) return; - qreal currentOffset = qreal(e->delta()) / 120; - d->offset_accumulated += currentOffset; - if (int(d->offset_accumulated) == 0) { - // QAbstractSlider works on integer values. So if the accumulated - // offset is less than +/- 1, we need to wait until we get more - // wheel events (this means that the wheel resolution is higher than - // 15 degrees, e.g. when using mac mighty mouse/trackpad): - return; - } + int stepsToScroll = 0; + qreal offset = qreal(e->delta()) / 120; - int stepsToScroll; if ((e->modifiers() & Qt::ControlModifier) || (e->modifiers() & Qt::ShiftModifier)) { - stepsToScroll = currentOffset > 0 ? d->pageStep : -d->pageStep; + // Scroll one page regardless of delta: + stepsToScroll = qBound(-d->pageStep, int(offset * d->pageStep), d->pageStep); + d->offset_accumulated = 0; } else { - // Calculate the number of steps to scroll (per 15 degrees of rotate): -#ifdef Q_OS_MAC - // On mac, since mouse wheel scrolling is accelerated and - // fine tuned by the OS, we skip applying acceleration: - stepsToScroll = int(d->offset_accumulated); -#else - stepsToScroll = int(d->offset_accumulated) * QApplication::wheelScrollLines() * d->singleStep; -#endif - stepsToScroll = qBound(-d->pageStep, stepsToScroll, d->pageStep); + // Calculate how many lines to scroll. Depending on what delta is (and + // offset), we might end up with a fraction (e.g. scroll 1.3 lines). We can + // only scroll whole lines, so we keep the reminder until next event. + qreal stepsToScrollF = offset * QApplication::wheelScrollLines() * d->singleStep; + // Check if wheel changed direction since last event: + if (d->offset_accumulated != 0 && (offset / d->offset_accumulated) < 0) + d->offset_accumulated = 0; + + d->offset_accumulated += stepsToScrollF; + stepsToScroll = qBound(-d->pageStep, int(d->offset_accumulated), d->pageStep); + d->offset_accumulated -= int(d->offset_accumulated); + if (stepsToScroll == 0) + return; } if (d->invertedControls) @@ -725,12 +723,10 @@ void QAbstractSlider::wheelEvent(QWheelEvent * e) d->position = d->overflowSafeAdd(stepsToScroll); // value will be updated by triggerAction() triggerAction(SliderMove); - if (prevValue == d->value) { + if (prevValue == d->value) d->offset_accumulated = 0; - } else { - d->offset_accumulated -= int(d->offset_accumulated); + else e->accept(); - } } #endif #ifdef QT_KEYPAD_NAVIGATION diff --git a/tests/auto/qabstractslider/tst_qabstractslider.cpp b/tests/auto/qabstractslider/tst_qabstractslider.cpp index 5c70bde..d9574df 100644 --- a/tests/auto/qabstractslider/tst_qabstractslider.cpp +++ b/tests/auto/qabstractslider/tst_qabstractslider.cpp @@ -714,11 +714,7 @@ void tst_QAbstractSlider::wheelEvent_data() << 1 // delta << int(Qt::Vertical) // orientation of slider << int(Qt::Vertical) // orientation of wheel -#ifdef Q_WS_MAC - << 1 // expected position after -#else << 20 // expected position after -#endif << QPoint(0,0); QTest::newRow("Normal data page") << 0 // initial position @@ -777,11 +773,7 @@ void tst_QAbstractSlider::wheelEvent_data() << 1 // delta << int(Qt::Horizontal) // orientation of slider << int(Qt::Horizontal) // orientation of wheel -#ifdef Q_WS_MAC - << 49 // expected position after -#else << 30 // expected position after -#endif << QPoint(1,1); QTest::newRow("Past end") << 50 // initial position @@ -792,11 +784,7 @@ void tst_QAbstractSlider::wheelEvent_data() << false // inverted controls << 1 // wheel scroll lines << false // with modifiers -#ifdef Q_WS_MAC - << 60 // delta -#else << 2 // delta -#endif << int(Qt::Horizontal) // orientation of slider << int(Qt::Horizontal) // orientation of wheel << 100 // expected position after @@ -810,11 +798,7 @@ void tst_QAbstractSlider::wheelEvent_data() << false // inverted controls << 1 // wheel scroll lines << false // with modifiers -#ifdef Q_WS_MAC - << -60 // delta -#else << -2 // delta -#endif << int(Qt::Horizontal) // orientation of slider << int(Qt::Horizontal) // orientation of wheel << 0 // expected position after -- cgit v0.12 From 138962d1c25a9cbb4375aa09bdeb7901c6536ce1 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Tue, 27 Oct 2009 14:03:06 +0100 Subject: Carbon: active window not restored After closing a window we used to go through the list of kDocumentWindowClass windows to pick the next one to pop to front. This patch will search the kMoveableWindowClass list of windows first, and as such, pop to front any modal window first Rev-By: MortenS --- src/gui/kernel/qwidget_mac.mm | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index d08f8a9..95c0bed 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -3390,12 +3390,19 @@ void QWidgetPrivate::hide_sys() w = q->parentWidget()->window(); if(!w || (!w->isVisible() && !w->isMinimized())) { #ifndef QT_MAC_USE_COCOA - for(WindowPtr wp = GetFrontWindowOfClass(kDocumentWindowClass, true); - wp; wp = GetNextWindowOfClass(wp, kDocumentWindowClass, true)) { + for (WindowPtr wp = GetFrontWindowOfClass(kMovableModalWindowClass, true); + wp; wp = GetNextWindowOfClass(wp, kMovableModalWindowClass, true)) { if((w = qt_mac_find_window(wp))) break; } if (!w){ + for (WindowPtr wp = GetFrontWindowOfClass(kDocumentWindowClass, true); + wp; wp = GetNextWindowOfClass(wp, kDocumentWindowClass, true)) { + if((w = qt_mac_find_window(wp))) + break; + } + } + if (!w){ for(WindowPtr wp = GetFrontWindowOfClass(kSimpleWindowClass, true); wp; wp = GetNextWindowOfClass(wp, kSimpleWindowClass, true)) { if((w = qt_mac_find_window(wp))) -- cgit v0.12 From 8135af2cebdaaccefb95f0be149328077d237a89 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 27 Oct 2009 13:03:23 +0100 Subject: Fix integer overflow in string.remove len parameter Task: 262677 Reviewed-by: joao --- src/corelib/tools/qstring.cpp | 6 +++--- tests/auto/qstring/tst_qstring.cpp | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index a996f30..55ad28d 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -1590,12 +1590,12 @@ QString &QString::append(QChar ch) */ QString &QString::remove(int pos, int len) { - if (pos < 0) + if (pos < 0) // count from end of string pos += d->size; if (pos < 0 || pos >= d->size) { // range problems - } else if (pos + len >= d->size) { // pos ok - resize(pos); + } else if (len >= d->size - pos) { + resize(pos); // truncate } else if (len > 0) { detach(); memmove(d->data + pos, d->data + pos + len, diff --git a/tests/auto/qstring/tst_qstring.cpp b/tests/auto/qstring/tst_qstring.cpp index 5dc1da7..2eb3152 100644 --- a/tests/auto/qstring/tst_qstring.cpp +++ b/tests/auto/qstring/tst_qstring.cpp @@ -201,6 +201,7 @@ private slots: void repeatedSignature() const; void repeated() const; void repeated_data() const; + void task262677remove(); }; typedef QList IntList; @@ -4669,6 +4670,14 @@ void tst_QString::repeated_data() const << 4; } +void tst_QString::task262677remove() +{ + QString driveName = QLatin1String("V:\\blahblah\\more_blahblah\\"); + driveName.remove(2, INT_MAX); // should be "V:" - instead, it's "V::\\blahblah\\more_blahblah\\" + QVERIFY(driveName == QLatin1String("V:")); +} + + QTEST_APPLESS_MAIN(tst_QString) #include "tst_qstring.moc" -- cgit v0.12