diff options
Diffstat (limited to 'src')
52 files changed, 1045 insertions, 275 deletions
diff --git a/src/angle/src/config.pri b/src/angle/src/config.pri index 07a18620da..f23bebef44 100644 --- a/src/angle/src/config.pri +++ b/src/angle/src/config.pri @@ -41,6 +41,8 @@ DEFINES += _WINDOWS \ CONFIG += angle_d3d11 # Remove to disable D3D11 renderer +equals(QMAKE_TARGET_OS, xp): CONFIG -= angle_d3d11 + angle_d3d11 { DEFINES += ANGLE_ENABLE_D3D11 ANGLE_DEFAULT_D3D11=1 !build_pass: message("Enabling D3D11 mode for ANGLE") diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index a0c943df62..6571c39385 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -4237,7 +4237,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters) \relates <QtGlobal> Forward-declares a mutable Core Foundation \a type. This includes the actual - type and the ref type. For example, Q_FORWARD_DECLARE_CF_TYPE(CFString) + type and the ref type. For example, Q_FORWARD_DECLARE_MUTABLE_CF_TYPE(CFMutableString) declares __CFMutableString and CFMutableStringRef. */ diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 8b4245ccdc..39d6f9539a 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -1275,23 +1275,6 @@ static void android_default_message_handler(QtMsgType type, static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &buf) { - // to determine logging destination and marking logging environment variable as deprecated - // ### remove when deprecated - struct LogDestination { - LogDestination(const char *deprecated, bool forceConsole) { - const char* replacement = "QT_LOGGING_TO_CONSOLE"; - bool newEnv = qEnvironmentVariableIsSet(replacement); - bool oldEnv = qEnvironmentVariableIsSet(deprecated); - if (oldEnv && !newEnv && !forceConsole) { - fprintf(stderr, "Warning: Environment variable %s is deprecated, " - "use %s instead.\n", deprecated, replacement); - fflush(stderr); - } - toConsole = newEnv || oldEnv || forceConsole; - } - bool toConsole; - }; - QString logMessage = qFormatLogMessage(type, context, buf); #if defined(Q_OS_WIN) && defined(QT_BUILD_CORE_LIB) @@ -1301,8 +1284,8 @@ static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &con } #endif // Q_OS_WIN -#if defined(QT_USE_SLOG2) static const bool logToConsole = qEnvironmentVariableIsSet("QT_LOGGING_TO_CONSOLE"); +#if defined(QT_USE_SLOG2) if (!logToConsole) { slog2_default_handler(type, logMessage.toLocal8Bit().constData()); } else { @@ -1310,11 +1293,9 @@ static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &con fflush(stderr); } #elif defined(QT_USE_JOURNALD) && !defined(QT_BOOTSTRAPPED) - // We use isatty to catch the obvious case of someone running something interactively. - // We also support environment variables for Qt Creator use, or more complicated cases + // We support environment variables for Qt Creator use, or more complicated cases // like subprocesses. - static const LogDestination logdest("QT_NO_JOURNALD_LOG", isatty(fileno(stdin))); - if (Q_LIKELY(!logdest.toConsole)) { + if (!logToConsole) { // remove trailing \n, systemd appears to want them newline-less logMessage.chop(1); systemd_default_message_handler(type, context, logMessage); @@ -1323,8 +1304,7 @@ static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &con fflush(stderr); } #elif defined(Q_OS_ANDROID) - static const LogDestination logdest("QT_ANDROID_PLAIN_LOG", false); - if (!logdest.toConsole) { + if (!logToConsole) { android_default_message_handler(type, context, logMessage); } else { fprintf(stderr, "%s", logMessage.toLocal8Bit().constData()); @@ -1334,6 +1314,7 @@ static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &con fprintf(stderr, "%s", logMessage.toLocal8Bit().constData()); fflush(stderr); #endif + Q_UNUSED(logToConsole); } /*! diff --git a/src/corelib/kernel/qbasictimer.cpp b/src/corelib/kernel/qbasictimer.cpp index f3366489d5..377c45219c 100644 --- a/src/corelib/kernel/qbasictimer.cpp +++ b/src/corelib/kernel/qbasictimer.cpp @@ -118,13 +118,19 @@ QT_BEGIN_NAMESPACE void QBasicTimer::start(int msec, QObject *obj) { QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance(); - if (!eventDispatcher) { + if (Q_UNLIKELY(!eventDispatcher)) { qWarning("QBasicTimer::start: QBasicTimer can only be used with threads started with QThread"); return; } + if (Q_UNLIKELY(obj && obj->thread() != eventDispatcher->thread())) { + qWarning("QBasicTimer::start: Timers cannot be started from another thread"); + return; + } if (id) { - eventDispatcher->unregisterTimer(id); - QAbstractEventDispatcherPrivate::releaseTimerId(id); + if (Q_LIKELY(eventDispatcher->unregisterTimer(id))) + QAbstractEventDispatcherPrivate::releaseTimerId(id); + else + qWarning("QBasicTimer::start: Stopping previous timer failed. Possibly trying to stop from a different thread"); } id = 0; if (obj) @@ -145,13 +151,23 @@ void QBasicTimer::start(int msec, QObject *obj) void QBasicTimer::start(int msec, Qt::TimerType timerType, QObject *obj) { QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance(); - if (!eventDispatcher) { + if (Q_UNLIKELY(msec < 0)) { + qWarning("QBasicTimer::start: Timers cannot have negative timeouts"); + return; + } + if (Q_UNLIKELY(!eventDispatcher)) { qWarning("QBasicTimer::start: QBasicTimer can only be used with threads started with QThread"); return; } + if (Q_UNLIKELY(obj && obj->thread() != eventDispatcher->thread())) { + qWarning("QBasicTimer::start: Timers cannot be started from another thread"); + return; + } if (id) { - eventDispatcher->unregisterTimer(id); - QAbstractEventDispatcherPrivate::releaseTimerId(id); + if (Q_LIKELY(eventDispatcher->unregisterTimer(id))) + QAbstractEventDispatcherPrivate::releaseTimerId(id); + else + qWarning("QBasicTimer::start: Stopping previous timer failed. Possibly trying to stop from a different thread"); } id = 0; if (obj) @@ -167,9 +183,13 @@ void QBasicTimer::stop() { if (id) { QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance(); - if (eventDispatcher) - eventDispatcher->unregisterTimer(id); - QAbstractEventDispatcherPrivate::releaseTimerId(id); + if (eventDispatcher) { + if (Q_UNLIKELY(!eventDispatcher->unregisterTimer(id))) { + qWarning("QBasicTimer::stop: Failed. Possibly trying to stop from a different thread"); + return; + } + QAbstractEventDispatcherPrivate::releaseTimerId(id); + } } id = 0; } diff --git a/src/corelib/kernel/qeventdispatcher_glib.cpp b/src/corelib/kernel/qeventdispatcher_glib.cpp index e87e830c39..c4a5fc1ea8 100644 --- a/src/corelib/kernel/qeventdispatcher_glib.cpp +++ b/src/corelib/kernel/qeventdispatcher_glib.cpp @@ -518,7 +518,7 @@ void QEventDispatcherGlib::registerTimer(int timerId, int interval, Qt::TimerTyp qWarning("QEventDispatcherGlib::registerTimer: invalid arguments"); return; } else if (object->thread() != thread() || thread() != QThread::currentThread()) { - qWarning("QObject::startTimer: timers cannot be started from another thread"); + qWarning("QEventDispatcherGlib::registerTimer: timers cannot be started from another thread"); return; } #endif @@ -534,7 +534,7 @@ bool QEventDispatcherGlib::unregisterTimer(int timerId) qWarning("QEventDispatcherGlib::unregisterTimer: invalid argument"); return false; } else if (thread() != QThread::currentThread()) { - qWarning("QObject::killTimer: timers cannot be stopped from another thread"); + qWarning("QEventDispatcherGlib::unregisterTimer: timers cannot be stopped from another thread"); return false; } #endif @@ -550,7 +550,7 @@ bool QEventDispatcherGlib::unregisterTimers(QObject *object) qWarning("QEventDispatcherGlib::unregisterTimers: invalid argument"); return false; } else if (object->thread() != thread() || thread() != QThread::currentThread()) { - qWarning("QObject::killTimers: timers cannot be stopped from another thread"); + qWarning("QEventDispatcherGlib::unregisterTimers: timers cannot be stopped from another thread"); return false; } #endif diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp index 69363bc3c9..9674fd5417 100644 --- a/src/corelib/kernel/qeventdispatcher_unix.cpp +++ b/src/corelib/kernel/qeventdispatcher_unix.cpp @@ -338,7 +338,7 @@ void QEventDispatcherUNIX::registerTimer(int timerId, int interval, Qt::TimerTyp qWarning("QEventDispatcherUNIX::registerTimer: invalid arguments"); return; } else if (obj->thread() != thread() || thread() != QThread::currentThread()) { - qWarning("QObject::startTimer: timers cannot be started from another thread"); + qWarning("QEventDispatcherUNIX::registerTimer: timers cannot be started from another thread"); return; } #endif @@ -357,7 +357,7 @@ bool QEventDispatcherUNIX::unregisterTimer(int timerId) qWarning("QEventDispatcherUNIX::unregisterTimer: invalid argument"); return false; } else if (thread() != QThread::currentThread()) { - qWarning("QObject::killTimer: timers cannot be stopped from another thread"); + qWarning("QEventDispatcherUNIX::unregisterTimer: timers cannot be stopped from another thread"); return false; } #endif @@ -376,7 +376,7 @@ bool QEventDispatcherUNIX::unregisterTimers(QObject *object) qWarning("QEventDispatcherUNIX::unregisterTimers: invalid argument"); return false; } else if (object->thread() != thread() || thread() != QThread::currentThread()) { - qWarning("QObject::killTimers: timers cannot be stopped from another thread"); + qWarning("QEventDispatcherUNIX::unregisterTimers: timers cannot be stopped from another thread"); return false; } #endif diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index f38ac7bf26..b7594d1dd3 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -908,13 +908,15 @@ void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier) void QEventDispatcherWin32::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object) { +#ifndef QT_NO_DEBUG if (timerId < 1 || interval < 0 || !object) { qWarning("QEventDispatcherWin32::registerTimer: invalid arguments"); return; } else if (object->thread() != thread() || thread() != QThread::currentThread()) { - qWarning("QObject::startTimer: timers cannot be started from another thread"); + qWarning("QEventDispatcherWin32::registerTimer: timers cannot be started from another thread"); return; } +#endif Q_D(QEventDispatcherWin32); @@ -936,15 +938,17 @@ void QEventDispatcherWin32::registerTimer(int timerId, int interval, Qt::TimerTy bool QEventDispatcherWin32::unregisterTimer(int timerId) { +#ifndef QT_NO_DEBUG if (timerId < 1) { qWarning("QEventDispatcherWin32::unregisterTimer: invalid argument"); return false; } QThread *currentThread = QThread::currentThread(); if (thread() != currentThread) { - qWarning("QObject::killTimer: timers cannot be stopped from another thread"); + qWarning("QEventDispatcherWin32::unregisterTimer: timers cannot be stopped from another thread"); return false; } +#endif Q_D(QEventDispatcherWin32); if (d->timerVec.isEmpty() || timerId <= 0) @@ -962,15 +966,17 @@ bool QEventDispatcherWin32::unregisterTimer(int timerId) bool QEventDispatcherWin32::unregisterTimers(QObject *object) { +#ifndef QT_NO_DEBUG if (!object) { qWarning("QEventDispatcherWin32::unregisterTimers: invalid argument"); return false; } QThread *currentThread = QThread::currentThread(); if (object->thread() != thread() || thread() != currentThread) { - qWarning("QObject::killTimers: timers cannot be stopped from another thread"); + qWarning("QEventDispatcherWin32::unregisterTimers: timers cannot be stopped from another thread"); return false; } +#endif Q_D(QEventDispatcherWin32); if (d->timerVec.isEmpty()) diff --git a/src/corelib/kernel/qeventdispatcher_winrt.cpp b/src/corelib/kernel/qeventdispatcher_winrt.cpp index aec0981677..d75d30f48e 100644 --- a/src/corelib/kernel/qeventdispatcher_winrt.cpp +++ b/src/corelib/kernel/qeventdispatcher_winrt.cpp @@ -254,13 +254,15 @@ void QEventDispatcherWinRT::registerTimer(int timerId, int interval, Qt::TimerTy { Q_UNUSED(timerType); +#ifndef QT_NO_DEBUG if (timerId < 1 || interval < 0 || !object) { qWarning("QEventDispatcherWinRT::registerTimer: invalid arguments"); return; } else if (object->thread() != thread() || thread() != QThread::currentThread()) { - qWarning("QObject::startTimer: timers cannot be started from another thread"); + qWarning("QEventDispatcherWinRT::registerTimer: timers cannot be started from another thread"); return; } +#endif Q_D(QEventDispatcherWinRT); @@ -289,14 +291,16 @@ void QEventDispatcherWinRT::registerTimer(int timerId, int interval, Qt::TimerTy bool QEventDispatcherWinRT::unregisterTimer(int timerId) { +#ifndef QT_NO_DEBUG if (timerId < 1) { qWarning("QEventDispatcherWinRT::unregisterTimer: invalid argument"); return false; } if (thread() != QThread::currentThread()) { - qWarning("QObject::killTimer: timers cannot be stopped from another thread"); + qWarning("QEventDispatcherWinRT::unregisterTimer: timers cannot be stopped from another thread"); return false; } +#endif Q_D(QEventDispatcherWinRT); @@ -310,15 +314,17 @@ bool QEventDispatcherWinRT::unregisterTimer(int timerId) bool QEventDispatcherWinRT::unregisterTimers(QObject *object) { +#ifndef QT_NO_DEBUG if (!object) { qWarning("QEventDispatcherWinRT::unregisterTimers: invalid argument"); return false; } QThread *currentThread = QThread::currentThread(); if (object->thread() != thread() || thread() != currentThread) { - qWarning("QObject::killTimers: timers cannot be stopped from another thread"); + qWarning("QEventDispatcherWinRT::unregisterTimers: timers cannot be stopped from another thread"); return false; } +#endif Q_D(QEventDispatcherWinRT); for (QHash<int, WinRTTimerInfo *>::iterator it = d->timerDict.begin(); it != d->timerDict.end();) { diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 2c53ed8f17..f72a679b82 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -225,13 +225,17 @@ QObjectPrivate::QObjectPrivate(int version) QObjectPrivate::~QObjectPrivate() { if (extraData && !extraData->runningTimers.isEmpty()) { - // unregister pending timers - if (threadData->eventDispatcher.load()) - threadData->eventDispatcher.load()->unregisterTimers(q_ptr); - - // release the timer ids back to the pool - for (int i = 0; i < extraData->runningTimers.size(); ++i) - QAbstractEventDispatcherPrivate::releaseTimerId(extraData->runningTimers.at(i)); + if (Q_LIKELY(threadData->thread == QThread::currentThread())) { + // unregister pending timers + if (threadData->eventDispatcher.load()) + threadData->eventDispatcher.load()->unregisterTimers(q_ptr); + + // release the timer ids back to the pool + for (int i = 0; i < extraData->runningTimers.size(); ++i) + QAbstractEventDispatcherPrivate::releaseTimerId(extraData->runningTimers.at(i)); + } else { + qWarning("QObject::~QObject: Timers cannot be stopped from another thread"); + } } if (postedEvents) @@ -1612,15 +1616,18 @@ int QObject::startTimer(int interval, Qt::TimerType timerType) { Q_D(QObject); - if (interval < 0) { + if (Q_UNLIKELY(interval < 0)) { qWarning("QObject::startTimer: Timers cannot have negative intervals"); return 0; } - - if (!d->threadData->eventDispatcher.load()) { + if (Q_UNLIKELY(!d->threadData->eventDispatcher.load())) { qWarning("QObject::startTimer: Timers can only be used with threads started with QThread"); return 0; } + if (Q_UNLIKELY(thread() != QThread::currentThread())) { + qWarning("QObject::startTimer: Timers cannot be started from another thread"); + return 0; + } int timerId = d->threadData->eventDispatcher.load()->registerTimer(interval, timerType, this); if (!d->extraData) d->extraData = new QObjectPrivate::ExtraData; @@ -1640,6 +1647,10 @@ int QObject::startTimer(int interval, Qt::TimerType timerType) void QObject::killTimer(int id) { Q_D(QObject); + if (Q_UNLIKELY(thread() != QThread::currentThread())) { + qWarning("QObject::killTimer: Timers cannot be stopped from another thread"); + return; + } if (id) { int at = d->extraData ? d->extraData->runningTimers.indexOf(id) : -1; if (at == -1) { diff --git a/src/corelib/kernel/qsocketnotifier.cpp b/src/corelib/kernel/qsocketnotifier.cpp index 6470873d9a..2598f02a19 100644 --- a/src/corelib/kernel/qsocketnotifier.cpp +++ b/src/corelib/kernel/qsocketnotifier.cpp @@ -274,6 +274,10 @@ void QSocketNotifier::setEnabled(bool enable) if (!d->threadData->eventDispatcher.load()) // perhaps application/thread is shutting down return; + if (Q_UNLIKELY(thread() != QThread::currentThread())) { + qWarning("QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread"); + return; + } if (d->snenabled) d->threadData->eventDispatcher.load()->registerSocketNotifier(this); else diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index 97aae6f7e0..5c09b483c6 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -395,6 +395,10 @@ void QTimer::singleShot(int msec, const QObject *receiver, const char *member) */ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member) { + if (Q_UNLIKELY(msec < 0)) { + qWarning("QTimer::singleShot: Timers cannot have negative timeouts"); + return; + } if (receiver && member) { if (msec == 0) { // special code shortpath for 0-timers diff --git a/src/corelib/kernel/qwineventnotifier.cpp b/src/corelib/kernel/qwineventnotifier.cpp index c694237dc3..d2c623d489 100644 --- a/src/corelib/kernel/qwineventnotifier.cpp +++ b/src/corelib/kernel/qwineventnotifier.cpp @@ -140,11 +140,11 @@ QWinEventNotifier::QWinEventNotifier(HANDLE hEvent, QObject *parent) { Q_D(QWinEventNotifier); QAbstractEventDispatcher *eventDispatcher = d->threadData->eventDispatcher.load(); - if (!eventDispatcher) { + if (Q_UNLIKELY(!eventDispatcher)) { qWarning("QWinEventNotifier: Can only be used with threads started with QThread"); - } else { - eventDispatcher->registerEventNotifier(this); + return; } + eventDispatcher->registerEventNotifier(this); d->enabled = true; } @@ -215,6 +215,10 @@ void QWinEventNotifier::setEnabled(bool enable) QAbstractEventDispatcher *eventDispatcher = d->threadData->eventDispatcher.load(); if (!eventDispatcher) // perhaps application is shutting down return; + if (Q_UNLIKELY(thread() != QThread::currentThread())) { + qWarning("QWinEventNotifier: Event notifiers cannot be enabled or disabled from another thread"); + return; + } if (enable) eventDispatcher->registerEventNotifier(this); diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp index 933f7fa6b3..4d148249c0 100644 --- a/src/corelib/tools/qversionnumber.cpp +++ b/src/corelib/tools/qversionnumber.cpp @@ -54,6 +54,7 @@ #endif #include <algorithm> +#include <limits> QT_BEGIN_NAMESPACE @@ -390,14 +391,13 @@ QVersionNumber QVersionNumber::fromString(const QString &string, int *suffixInde const char *end = start; const char *lastGoodEnd = start; const char *endOfString = cString.constData() + cString.size(); - int value; do { bool ok = false; - value = int(qstrtoull(start, &end, 10, &ok)); - if (!ok) + const qulonglong value = qstrtoull(start, &end, 10, &ok); + if (!ok || value > qulonglong(std::numeric_limits<int>::max())) break; - seg.append(value); + seg.append(int(value)); start = end + 1; lastGoodEnd = end; } while (start < endOfString && (end < endOfString && *end == '.')); diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 72972ff163..50dcc9eca2 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -4664,7 +4664,7 @@ static Q_CONSTEXPR QPixelFormat pixelformats[] = { //QImage::Format_Invalid: QPixelFormat(), //QImage::Format_Mono: - QPixelFormat(QPixelFormat::Grayscale, + QPixelFormat(QPixelFormat::Indexed, /*RED*/ 1, /*GREEN*/ 0, /*BLUE*/ 0, @@ -4677,7 +4677,7 @@ static Q_CONSTEXPR QPixelFormat pixelformats[] = { /*INTERPRETATION*/ QPixelFormat::UnsignedByte, /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), //QImage::Format_MonoLSB: - QPixelFormat(QPixelFormat::Grayscale, + QPixelFormat(QPixelFormat::Indexed, /*RED*/ 1, /*GREEN*/ 0, /*BLUE*/ 0, @@ -4789,7 +4789,7 @@ static Q_CONSTEXPR QPixelFormat pixelformats[] = { /*FIFTH*/ 0, /*ALPHA*/ 6, /*ALPHA USAGE*/ QPixelFormat::UsesAlpha, - /*ALPHA POSITION*/ QPixelFormat::AtBeginning, + /*ALPHA POSITION*/ QPixelFormat::AtEnd, /*PREMULTIPLIED*/ QPixelFormat::Premultiplied, /*INTERPRETATION*/ QPixelFormat::UnsignedInteger, /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), @@ -4854,7 +4854,7 @@ static Q_CONSTEXPR QPixelFormat pixelformats[] = { /*FIFTH*/ 0, /*ALPHA*/ 4, /*ALPHA USAGE*/ QPixelFormat::UsesAlpha, - /*ALPHA POSITION*/ QPixelFormat::AtBeginning, + /*ALPHA POSITION*/ QPixelFormat::AtEnd, /*PREMULTIPLIED*/ QPixelFormat::Premultiplied, /*INTERPRETATION*/ QPixelFormat::UnsignedShort, /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 958df48f17..57c9da2dda 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -642,6 +642,10 @@ QWheelEvent::QWheelEvent(const QPointF &pos, int delta, : QInputEvent(Wheel, modifiers), p(pos), qt4D(delta), qt4O(orient), mouseState(buttons) { g = QCursor::pos(); + if (orient == Qt::Vertical) + angleD = QPoint(0, delta); + else + angleD = QPoint(delta, 0); } /*! @@ -670,7 +674,12 @@ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, int delta Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Qt::Orientation orient) : QInputEvent(Wheel, modifiers), p(pos), g(globalPos), qt4D(delta), qt4O(orient), mouseState(buttons) -{} +{ + if (orient == Qt::Vertical) + angleD = QPoint(0, delta); + else + angleD = QPoint(delta, 0); +} /*! Constructs a wheel event object. diff --git a/src/gui/kernel/qplatformcursor.cpp b/src/gui/kernel/qplatformcursor.cpp index c2f510b496..0162360718 100644 --- a/src/gui/kernel/qplatformcursor.cpp +++ b/src/gui/kernel/qplatformcursor.cpp @@ -122,8 +122,13 @@ QPoint QPlatformCursor::pos() const void QPlatformCursor::setPos(const QPoint &pos) { - Q_UNUSED(pos); - qWarning("This plugin does not support QCursor::setPos()"); + static bool firstCall = true; + if (firstCall) { + firstCall = false; + qWarning("This plugin does not support QCursor::setPos()" + "; emulating movement within the application."); + } + QWindowSystemInterface::handleMouseEvent(0, pos, pos, Qt::NoButton); } // End of display and pointer event handling code diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index d82abd73dc..fb1f582214 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -501,7 +501,6 @@ void QOpenGL2PaintEngineExPrivate::drawTexture(const QOpenGLRect& dest, const QO { // Setup for texture drawing currentBrush = noBrush; - shaderManager->setSrcPixelType(pattern ? QOpenGLEngineShaderManager::PatternSrc : QOpenGLEngineShaderManager::ImageSrc); if (snapToPixelGrid) { snapToPixelGrid = false; @@ -1367,6 +1366,11 @@ void QOpenGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixma Q_D(QOpenGL2PaintEngineEx); QOpenGLContext *ctx = d->ctx; + // Draw pixmaps that are really images as images since drawImage has + // better handling of non-default image formats. + if (pixmap.paintEngine()->type() == QPaintEngine::Raster && !pixmap.isQBitmap()) + return drawImage(dest, pixmap.toImage(), src); + int max_texture_size = ctx->d_func()->maxTextureSize(); if (pixmap.width() > max_texture_size || pixmap.height() > max_texture_size) { QPixmap scaled = pixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio); @@ -1391,6 +1395,8 @@ void QOpenGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixma d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, state()->renderHints & QPainter::SmoothPixmapTransform, id); + + d->shaderManager->setSrcPixelType(isBitmap ? QOpenGLEngineShaderManager::PatternSrc : QOpenGLEngineShaderManager::ImageSrc); d->drawTexture(dest, srcRect, pixmap.size(), isOpaque, isBitmap); } @@ -1414,12 +1420,25 @@ void QOpenGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, c ensureActive(); d->transferMode(ImageDrawingMode); - d->funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); + QOpenGLTextureCache::BindOptions bindOption = QOpenGLTextureCache::PremultipliedAlphaBindOption; + // Use specialized bind for formats we have specialized shaders for. + switch (image.format()) { + case QImage::Format_RGBA8888: + case QImage::Format_ARGB32: + d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::NonPremultipliedImageSrc); + bindOption = 0; + break; + default: + d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc); + break; + } - GLuint id = QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, image); + d->funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); + GLuint id = QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, image, bindOption); d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, state()->renderHints & QPainter::SmoothPixmapTransform, id); + d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel()); } @@ -1466,6 +1485,7 @@ bool QOpenGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, co d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, state()->renderHints & QPainter::SmoothPixmapTransform, textureId); + d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc); d->drawTexture(dest, srcRect, size, false); return true; } diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp index 1e778af3f6..26f4dfd3cf 100644 --- a/src/gui/painting/qregion.cpp +++ b/src/gui/painting/qregion.cpp @@ -2955,11 +2955,11 @@ typedef struct { typedef struct _EdgeTableEntry { int ymax; /* ycoord at which we exit this edge. */ + int ClockWise; /* flag for winding number rule */ BRESINFO bres; /* Bresenham info to run the edge */ struct _EdgeTableEntry *next; /* next in the list */ struct _EdgeTableEntry *back; /* for insertion sort */ struct _EdgeTableEntry *nextWETE; /* for winding num rule */ - int ClockWise; /* flag for winding number rule */ } EdgeTableEntry; diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 5f801c3bf4..4faa018a40 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -374,7 +374,7 @@ bool QFontEngine::supportsScript(QChar::Script script) const hb_tag_t script_tag_1, script_tag_2; hb_ot_tags_from_script(hb_qt_script_to_script(script), &script_tag_1, &script_tag_2); - unsigned int script_index = -1; + unsigned int script_index; ret = hb_ot_layout_table_find_script(face, HB_OT_TAG_GSUB, script_tag_1, &script_index); if (!ret) { ret = hb_ot_layout_table_find_script(face, HB_OT_TAG_GSUB, script_tag_2, &script_index); diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index e572745d51..d9185d5efb 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -2420,7 +2420,7 @@ qint64 QAbstractSocket::readData(char *data, qint64 maxSize) return 0; // This is for a buffered QTcpSocket - if (d->isBuffered && d->buffer.isEmpty()) + if (d->isBuffered) // if we're still connected, return 0 indicating there may be more data in the future // if we're not connected, return -1 indicating EOF return d->state == QAbstractSocket::ConnectedState ? qint64(0) : qint64(-1); diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm index 204e0ed98b..1ade985b79 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm @@ -158,6 +158,7 @@ static void populateRoleMap() roleMap[QAccessible::Heading] = @"AXHeading"; roleMap[QAccessible::Note] = NSAccessibilityGroupRole; roleMap[QAccessible::ComplementaryContent] = NSAccessibilityGroupRole; + roleMap[QAccessible::Graphic] = NSAccessibilityImageRole; } /* diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index 1d28befe41..e765812024 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -109,13 +109,6 @@ static inline ID2D1Factory1 *factory() return QWindowsDirect2DContext::instance()->d2dFactory(); } -inline static FLOAT pixelSizeToDIP(int pixelSize) -{ - FLOAT dpiX, dpiY; - QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&dpiX, &dpiY); - return FLOAT(pixelSize) * 96.0f / dpiY; -} - class Direct2DPathGeometryWriter { public: @@ -300,6 +293,14 @@ public: : D2D1_ANTIALIAS_MODE_ALIASED; } + inline D2D1_LAYER_OPTIONS1 layerOptions() const + { + if (flags & QWindowsDirect2DPaintEngine::TranslucentTopLevelWindow) + return D2D1_LAYER_OPTIONS1_NONE; + else + return D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND; + } + void updateTransform(const QTransform &transform) { dc()->SetTransform(to_d2d_matrix_3x2_f(transform)); @@ -345,7 +346,7 @@ public: D2D1::IdentityMatrix(), 1.0, NULL, - D2D1_LAYER_OPTIONS1_NONE), + layerOptions()), NULL); pushedClips.push(LayerClip); } @@ -858,19 +859,19 @@ public: Q_Q(QWindowsDirect2DPaintEngine); DWRITE_GLYPH_RUN glyphRun = { - fontFace, // IDWriteFontFace *fontFace; - pixelSizeToDIP(fontDef.pixelSize), // FLOAT fontEmSize; - numGlyphs, // UINT32 glyphCount; - glyphIndices, // const UINT16 *glyphIndices; - glyphAdvances, // const FLOAT *glyphAdvances; - glyphOffsets, // const DWRITE_GLYPH_OFFSET *glyphOffsets; - FALSE, // BOOL isSideways; - rtl ? 1 : 0 // UINT32 bidiLevel; + fontFace, // IDWriteFontFace *fontFace; + fontDef.pixelSize, // FLOAT fontEmSize; + numGlyphs, // UINT32 glyphCount; + glyphIndices, // const UINT16 *glyphIndices; + glyphAdvances, // const FLOAT *glyphAdvances; + glyphOffsets, // const DWRITE_GLYPH_OFFSET *glyphOffsets; + FALSE, // BOOL isSideways; + rtl ? 1 : 0 // UINT32 bidiLevel; }; const bool antiAlias = bool((q->state()->renderHints & QPainter::TextAntialiasing) && !(fontDef.styleStrategy & QFont::NoAntialias)); - const D2D1_TEXT_ANTIALIAS_MODE antialiasMode = (flags & QWindowsDirect2DPaintEngine::UseGrayscaleAntialiasing) + const D2D1_TEXT_ANTIALIAS_MODE antialiasMode = (flags & QWindowsDirect2DPaintEngine::TranslucentTopLevelWindow) ? D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE : D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; dc()->SetTextAntialiasMode(antiAlias ? antialiasMode : D2D1_TEXT_ANTIALIAS_MODE_ALIASED); @@ -956,7 +957,7 @@ bool QWindowsDirect2DPaintEngine::begin(QPaintDevice * pdev) D2D1::IdentityMatrix(), 1.0, NULL, - D2D1_LAYER_OPTIONS1_NONE), + d->layerOptions()), NULL); } else { QRect clip(0, 0, pdev->width(), pdev->height()); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h index 4ed817b75f..af0aaf93f7 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h @@ -61,7 +61,7 @@ class QWindowsDirect2DPaintEngine : public QPaintEngineEx public: enum Flag { NoFlag = 0, - UseGrayscaleAntialiasing = 1, + TranslucentTopLevelWindow = 1 }; Q_DECLARE_FLAGS(Flags, Flag) diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp index f739493c1a..36e306929d 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp @@ -310,7 +310,7 @@ void QWindowsDirect2DWindow::setupBitmap() QWindowsDirect2DPaintEngine::Flags flags = QWindowsDirect2DPaintEngine::NoFlag; if (!m_directRendering) - flags |= QWindowsDirect2DPaintEngine::UseGrayscaleAntialiasing; + flags |= QWindowsDirect2DPaintEngine::TranslucentTopLevelWindow; QWindowsDirect2DPlatformPixmap *pp = new QWindowsDirect2DPlatformPixmap(QPlatformPixmap::PixmapType, flags, m_bitmap.data()); diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro index 82f0bd91c4..6b67a42f69 100644 --- a/src/plugins/platforms/ios/ios.pro +++ b/src/plugins/platforms/ios/ios.pro @@ -28,6 +28,7 @@ OBJECTIVE_SOURCES = \ quiaccessibilityelement.mm \ qiosplatformaccessibility.mm \ qiostextresponder.mm \ + qiosmenu.mm \ HEADERS = \ qiosintegration.h \ @@ -48,6 +49,7 @@ HEADERS = \ quiaccessibilityelement.h \ qiosplatformaccessibility.h \ qiostextresponder.h \ + qiosmenu.h \ OTHER_FILES = \ quiview_textinput.mm \ diff --git a/src/plugins/platforms/ios/qiosmenu.h b/src/plugins/platforms/ios/qiosmenu.h new file mode 100644 index 0000000000..9897483a3e --- /dev/null +++ b/src/plugins/platforms/ios/qiosmenu.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QIOSMENU_H +#define QIOSMENU_H + +#import <UIKit/UIKit.h> + +#include <QtCore/QtCore> +#include <qpa/qplatformmenu.h> + +#import "quiview.h" + +@class QUIMenuController; +@class QUIPickerView; + +class QIOSMenuItem : public QPlatformMenuItem +{ +public: + QIOSMenuItem(); + + void setTag(quintptr tag) Q_DECL_OVERRIDE; + quintptr tag()const Q_DECL_OVERRIDE; + + void setText(const QString &text) Q_DECL_OVERRIDE; + void setIcon(const QIcon &) Q_DECL_OVERRIDE {} + void setMenu(QPlatformMenu *) Q_DECL_OVERRIDE {} + void setVisible(bool isVisible) Q_DECL_OVERRIDE; + void setIsSeparator(bool) Q_DECL_OVERRIDE {} + void setFont(const QFont &) Q_DECL_OVERRIDE {} + void setRole(MenuRole role) Q_DECL_OVERRIDE; + void setCheckable(bool) Q_DECL_OVERRIDE {} + void setChecked(bool) Q_DECL_OVERRIDE {} + void setShortcut(const QKeySequence&) Q_DECL_OVERRIDE {} + void setEnabled(bool enabled) Q_DECL_OVERRIDE; + void setIconSize(int) Q_DECL_OVERRIDE {} + + quintptr m_tag; + bool m_visible; + QString m_text; + MenuRole m_role; + bool m_enabled; + +private: + QString removeMnemonics(const QString &original); +}; + +typedef QList<QIOSMenuItem *> QIOSMenuItemList; + +class QIOSMenu : public QPlatformMenu +{ +public: + QIOSMenu(); + ~QIOSMenu(); + + void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) Q_DECL_OVERRIDE; + void removeMenuItem(QPlatformMenuItem *menuItem) Q_DECL_OVERRIDE; + void syncMenuItem(QPlatformMenuItem *) Q_DECL_OVERRIDE {} + void syncSeparatorsCollapsible(bool) Q_DECL_OVERRIDE {} + + void setTag(quintptr tag) Q_DECL_OVERRIDE; + quintptr tag()const Q_DECL_OVERRIDE; + + void setText(const QString &) Q_DECL_OVERRIDE; + void setIcon(const QIcon &) Q_DECL_OVERRIDE {} + void setEnabled(bool enabled) Q_DECL_OVERRIDE; + void setVisible(bool visible) Q_DECL_OVERRIDE; + void setMenuType(MenuType type) Q_DECL_OVERRIDE; + + void showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item) Q_DECL_OVERRIDE; + void dismiss() Q_DECL_OVERRIDE; + + QPlatformMenuItem *menuItemAt(int position) const Q_DECL_OVERRIDE; + QPlatformMenuItem *menuItemForTag(quintptr tag) const Q_DECL_OVERRIDE; + + static QIOSMenu *currentMenu() { return m_currentMenu; } + static id menuActionTarget() { return m_currentMenu ? m_currentMenu->m_menuController : 0; } + +protected: + bool eventFilter(QObject *obj, QEvent *event); + +private: + quintptr m_tag; + bool m_enabled; + bool m_visible; + bool m_effectiveVisible; + QString m_text; + MenuType m_menuType; + MenuType m_effectiveMenuType; + QRect m_targetRect; + const QIOSMenuItem *m_targetItem; + QUIMenuController *m_menuController; + QUIPickerView *m_pickerView; + QIOSMenuItemList m_menuItems; + + static QIOSMenu *m_currentMenu; + + void updateVisibility(); + void updateVisibilityUsingUIMenuController(); + void updateVisibilityUsingUIPickerView(); + QIOSMenuItemList visibleMenuItems() const; + void repositionMenu(); + void hide() { setVisible(false); } +}; + +#endif // QIOSMENU_H diff --git a/src/plugins/platforms/ios/qiosmenu.mm b/src/plugins/platforms/ios/qiosmenu.mm new file mode 100644 index 0000000000..8f7baa9756 --- /dev/null +++ b/src/plugins/platforms/ios/qiosmenu.mm @@ -0,0 +1,525 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qglobal.h> +#include <qguiapplication.h> + +#include "qiosglobal.h" +#include "qiosmenu.h" +#include "qioswindow.h" +#include "qiosinputcontext.h" +#include "qiosintegration.h" +#include "qiostextresponder.h" + +// m_currentMenu points to the currently visible menu. +// Only one menu will be visible at a time, and if a second menu +// is shown on top of a first, the first one will be told to hide. +QIOSMenu *QIOSMenu::m_currentMenu = 0; + +// ------------------------------------------------------------------------- + +static NSString *const kSelectorPrefix = @"_qtMenuItem_"; + +@interface QUIMenuController : UIResponder { + QIOSMenuItemList m_visibleMenuItems; +} +@end + +@implementation QUIMenuController + +- (id)initWithVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems +{ + if (self = [super init]) { + m_visibleMenuItems = visibleMenuItems; + NSMutableArray *menuItemArray = [NSMutableArray arrayWithCapacity:m_visibleMenuItems.size()]; + // Create an array of UIMenuItems, one for each visible QIOSMenuItem. Each + // UIMenuItem needs a callback assigned, so we assign one of the placeholder methods + // added to UIWindow (QIOSMenuActionTargets) below. Each method knows its own index, which + // corresponds to the index of the corresponding QIOSMenuItem in m_visibleMenuItems. When + // triggered, menuItemActionCallback will end up being called. + for (int i = 0; i < m_visibleMenuItems.count(); ++i) { + QIOSMenuItem *item = m_visibleMenuItems.at(i); + SEL sel = NSSelectorFromString([NSString stringWithFormat:@"%@%i:", kSelectorPrefix, i]); + [menuItemArray addObject:[[[UIMenuItem alloc] initWithTitle:item->m_text.toNSString() action:sel] autorelease]]; + } + [UIMenuController sharedMenuController].menuItems = menuItemArray; + } + + return self; +} + +- (id)targetForAction:(SEL)action withSender:(id)sender +{ + BOOL containsPrefix = ([NSStringFromSelector(action) rangeOfString:kSelectorPrefix].location != NSNotFound); + return (containsPrefix && [sender isKindOfClass:[UIMenuController class]]) ? self : 0; +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector +{ + Q_UNUSED(selector); + // Just return a dummy signature that NSObject can create an NSInvocation from. + // We end up only checking selector in forwardInvocation anyway. + return [super methodSignatureForSelector:@selector(methodSignatureForSelector:)]; +} + +- (void)forwardInvocation:(NSInvocation *)invocation +{ + // Since none of the menu item selector methods actually exist, this function + // will end up being called as a final resort. We can then handle the action. + NSString *selector = NSStringFromSelector(invocation.selector); + NSRange range = NSMakeRange(kSelectorPrefix.length, selector.length - kSelectorPrefix.length - 1); + NSInteger selectedIndex = [[selector substringWithRange:range] integerValue]; + + emit m_visibleMenuItems.at(selectedIndex)->activated(); + QIOSMenu::currentMenu()->setVisible(false); +} + +@end + +// ------------------------------------------------------------------------- + +@interface QUIPickerView : UIPickerView <UIPickerViewDelegate, UIPickerViewDataSource> { + QIOSMenuItemList m_visibleMenuItems; + QPointer<QObject> m_focusObjectWithPickerView; + NSInteger m_selectedRow; +} + +@property(retain) UIToolbar *toolbar; + +@end + +@implementation QUIPickerView + +- (id)initWithVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems selectItem:(const QIOSMenuItem *)selectItem +{ + if (self = [super init]) { + self.autoresizingMask = UIViewAutoresizingFlexibleWidth; + m_visibleMenuItems = visibleMenuItems; + m_selectedRow = visibleMenuItems.indexOf(const_cast<QIOSMenuItem *>(selectItem)); + if (m_selectedRow == -1) + m_selectedRow = 0; + + self.toolbar = [[[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 100, 44)] autorelease]; + self.toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + + UIBarButtonItem *doneButton = [[[UIBarButtonItem alloc] + initWithBarButtonSystemItem:UIBarButtonSystemItemDone + target:self action:@selector(closeMenu)] autorelease]; + UIBarButtonItem *spaceButton = [[[UIBarButtonItem alloc] + initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace + target:self action:@selector(closeMenu)] autorelease]; + UIBarButtonItem *cancelButton = [[[UIBarButtonItem alloc] + initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + target:self action:@selector(cancelMenu)] autorelease]; + [self.toolbar setItems:[NSArray arrayWithObjects:doneButton, spaceButton, cancelButton, nil]]; + + [self setDelegate:self]; + [self setDataSource:self]; + [self selectRow:m_selectedRow inComponent:0 animated:false]; + } + + return self; +} + +-(void)dealloc +{ + self.toolbar = 0; + [super dealloc]; +} + +- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component +{ + Q_UNUSED(pickerView); + Q_UNUSED(component); + return m_visibleMenuItems.at(row)->m_text.toNSString(); +} + +- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView +{ + Q_UNUSED(pickerView); + return 1; +} + +- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component +{ + Q_UNUSED(pickerView); + Q_UNUSED(component); + return m_visibleMenuItems.length(); +} + +- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component +{ + Q_UNUSED(pickerView); + Q_UNUSED(component); + m_selectedRow = row; +} + +- (void)closeMenu +{ + if (!m_visibleMenuItems.isEmpty()) + emit m_visibleMenuItems.at(m_selectedRow)->activated(); + QIOSMenu::currentMenu()->setVisible(false); +} + +- (void)cancelMenu +{ + QIOSMenu::currentMenu()->setVisible(false); +} + +@end + +// ------------------------------------------------------------------------- + +QIOSMenuItem::QIOSMenuItem() + : QPlatformMenuItem() + , m_tag(0) + , m_visible(true) + , m_text(QString()) + , m_role(MenuRole(0)) + , m_enabled(true) +{ +} + +void QIOSMenuItem::setTag(quintptr tag) +{ + m_tag = tag; +} + +quintptr QIOSMenuItem::tag() const +{ + return m_tag; +} + +void QIOSMenuItem::setText(const QString &text) +{ + m_text = removeMnemonics(text); +} + +void QIOSMenuItem::setVisible(bool isVisible) +{ + m_visible = isVisible; +} + +void QIOSMenuItem::setRole(QPlatformMenuItem::MenuRole role) +{ + m_role = role; +} + +void QIOSMenuItem::setEnabled(bool enabled) +{ + m_enabled = enabled; +} + +QString QIOSMenuItem::removeMnemonics(const QString &original) +{ + // Copied from qcocoahelpers + QString returnText(original.size(), 0); + int finalDest = 0; + int currPos = 0; + int l = original.length(); + while (l) { + if (original.at(currPos) == QLatin1Char('&') + && (l == 1 || original.at(currPos + 1) != QLatin1Char('&'))) { + ++currPos; + --l; + if (l == 0) + break; + } else if (original.at(currPos) == QLatin1Char('(') && l >= 4 && + original.at(currPos + 1) == QLatin1Char('&') && + original.at(currPos + 2) != QLatin1Char('&') && + original.at(currPos + 3) == QLatin1Char(')')) { + /* remove mnemonics its format is "\s*(&X)" */ + int n = 0; + while (finalDest > n && returnText.at(finalDest - n - 1).isSpace()) + ++n; + finalDest -= n; + currPos += 4; + l -= 4; + continue; + } + returnText[finalDest] = original.at(currPos); + ++currPos; + ++finalDest; + --l; + } + returnText.truncate(finalDest); + return returnText; +} + +QIOSMenu::QIOSMenu() + : QPlatformMenu() + , m_tag(0) + , m_enabled(true) + , m_visible(false) + , m_effectiveVisible(false) + , m_text(QString()) + , m_menuType(DefaultMenu) + , m_effectiveMenuType(DefaultMenu) + , m_targetRect(QRect(qGuiApp->primaryScreen()->availableGeometry().center(), QSize())) + , m_targetItem(0) + , m_menuController(0) + , m_pickerView(0) +{ +} + +QIOSMenu::~QIOSMenu() +{ + dismiss(); +} + +void QIOSMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) +{ + if (!before) { + m_menuItems.append(static_cast<QIOSMenuItem *>(menuItem)); + } else { + int index = m_menuItems.indexOf(static_cast<QIOSMenuItem *>(before)) + 1; + m_menuItems.insert(index, static_cast<QIOSMenuItem *>(menuItem)); + } +} + +void QIOSMenu::removeMenuItem(QPlatformMenuItem *menuItem) +{ + m_menuItems.removeOne(static_cast<QIOSMenuItem *>(menuItem)); +} + +void QIOSMenu::setTag(quintptr tag) +{ + m_tag = tag; +} + +quintptr QIOSMenu::tag() const +{ + return m_tag; +} + +void QIOSMenu::setText(const QString &text) +{ + m_text = text; +} + +void QIOSMenu::setEnabled(bool enabled) +{ + if (m_enabled == enabled) + return; + + m_enabled = enabled; + updateVisibility(); +} + +void QIOSMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item) +{ + if (!parentWindow->isActive()) + const_cast<QWindow *>(parentWindow)->requestActivate(); + m_targetRect = QRect(parentWindow->mapToGlobal(targetRect.topLeft()), targetRect.size()); + m_targetItem = static_cast<const QIOSMenuItem *>(item); + setVisible(true); +} + +void QIOSMenu::dismiss() +{ + setVisible(false); +} + +void QIOSMenu::setVisible(bool visible) +{ + if (m_visible == visible) + return; + + m_visible = visible; + updateVisibility(); +} + +void QIOSMenu::updateVisibility() +{ + bool visibleAndEnabled = m_visible && m_enabled; + if ((visibleAndEnabled && m_effectiveVisible) || (!visibleAndEnabled && m_currentMenu != this)) + return; + + if (visibleAndEnabled && !qApp->focusObject()) { + // Since the menus depend on communicating with a focus object, a focus object is required to show + // the menu. Note that QIOSMenu::showPopup() will activate the parent window (and set a focus object) + // before this function is called, so this should normally be the case. Not having a focus object is only + // expected in a hybrid environment where the first responder can be something else than a QUIView (then + // no QWindow will be active). If the focus object changes while the menu is visible, the menu will hide. + qWarning() << "QIOSMenu: cannot open menu without any active QWindows!"; + return; + } + + m_effectiveVisible = visibleAndEnabled; + + if (m_effectiveVisible) { + Q_ASSERT(m_currentMenu != this); + if (m_currentMenu) { + // The current implementation allow only one visible + // menu at a time, so close the one currently showing. + m_currentMenu->setVisible(false); + } + + m_currentMenu = this; + m_effectiveMenuType = m_menuType; + connect(qGuiApp, &QGuiApplication::focusObjectChanged, this, &QIOSMenu::hide); + } else { + disconnect(qGuiApp, &QGuiApplication::focusObjectChanged, this, &QIOSMenu::hide); + m_currentMenu = 0; + } + + switch (m_effectiveMenuType) { + case EditMenu: + updateVisibilityUsingUIMenuController(); + break; + default: + updateVisibilityUsingUIPickerView(); + break; + } + + // Emit the signal after the fact in case a + // receiver opens a new menu when receiving it. + emit (m_effectiveVisible ? aboutToShow() : aboutToHide()); +} + +void QIOSMenu::setMenuType(QPlatformMenu::MenuType type) +{ + m_menuType = type; +} + +void QIOSMenu::updateVisibilityUsingUIMenuController() +{ + if (m_effectiveVisible) { + Q_ASSERT(!m_menuController); + m_menuController = [[QUIMenuController alloc] initWithVisibleMenuItems:visibleMenuItems()]; + repositionMenu(); + connect(qGuiApp->inputMethod(), &QInputMethod::keyboardRectangleChanged, this, &QIOSMenu::repositionMenu); + } else { + disconnect(qGuiApp->inputMethod(), &QInputMethod::keyboardRectangleChanged, this, &QIOSMenu::repositionMenu); + + Q_ASSERT(m_menuController); + [[UIMenuController sharedMenuController] setMenuVisible:NO animated:YES]; + [m_menuController release]; + m_menuController = 0; + } +} + +void QIOSMenu::updateVisibilityUsingUIPickerView() +{ + static QObject *focusObjectWithPickerView = 0; + + if (m_effectiveVisible) { + Q_ASSERT(!m_pickerView); + m_pickerView = [[QUIPickerView alloc] initWithVisibleMenuItems:visibleMenuItems() selectItem:m_targetItem]; + + Q_ASSERT(!focusObjectWithPickerView); + focusObjectWithPickerView = qApp->focusWindow()->focusObject(); + focusObjectWithPickerView->installEventFilter(this); + qApp->inputMethod()->update(Qt::ImPlatformData); + } else { + Q_ASSERT(focusObjectWithPickerView); + focusObjectWithPickerView->removeEventFilter(this); + qApp->inputMethod()->update(Qt::ImPlatformData); + focusObjectWithPickerView = 0; + + Q_ASSERT(m_pickerView); + [m_pickerView release]; + m_pickerView = 0; + } +} + +bool QIOSMenu::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::InputMethodQuery) { + QInputMethodQueryEvent *queryEvent = static_cast<QInputMethodQueryEvent *>(event); + if (queryEvent->queries() & Qt::ImPlatformData) { + // Let object fill inn default query results + obj->event(queryEvent); + + QVariantMap imPlatformData = queryEvent->value(Qt::ImPlatformData).toMap(); + imPlatformData.insert(kImePlatformDataInputView, QVariant::fromValue(static_cast<void *>(m_pickerView))); + imPlatformData.insert(kImePlatformDataInputAccessoryView, QVariant::fromValue(static_cast<void *>(m_pickerView.toolbar))); + queryEvent->setValue(Qt::ImPlatformData, imPlatformData); + + return true; + } + } + + return QObject::eventFilter(obj, event); +} + +QIOSMenuItemList QIOSMenu::visibleMenuItems() const +{ + QIOSMenuItemList visibleMenuItems = m_menuItems; + + for (int i = visibleMenuItems.count() - 1; i >= 0; --i) { + QIOSMenuItem *item = visibleMenuItems.at(i); + if (!item->m_enabled || !item->m_visible) + visibleMenuItems.removeAt(i); + } + + return visibleMenuItems; +} + +void QIOSMenu::repositionMenu() +{ + switch (m_effectiveMenuType) { + case EditMenu: { + UIView *view = [UIApplication sharedApplication].keyWindow.rootViewController.view; + [[UIMenuController sharedMenuController] setTargetRect:toCGRect(m_targetRect) inView:view]; + [[UIMenuController sharedMenuController] setMenuVisible:YES animated:YES]; + break; } + default: + break; + } +} + +QPlatformMenuItem *QIOSMenu::menuItemAt(int position) const +{ + if (position < 0 || position >= m_menuItems.size()) + return 0; + return m_menuItems.at(position); +} + +QPlatformMenuItem *QIOSMenu::menuItemForTag(quintptr tag) const +{ + for (int i = 0; i < m_menuItems.size(); ++i) { + QPlatformMenuItem *item = m_menuItems.at(i); + if (item->tag() == tag) + return item; + } + return 0; +} diff --git a/src/plugins/platforms/ios/qiostheme.h b/src/plugins/platforms/ios/qiostheme.h index b03f65f556..b4b7b8977b 100644 --- a/src/plugins/platforms/ios/qiostheme.h +++ b/src/plugins/platforms/ios/qiostheme.h @@ -55,6 +55,9 @@ public: QVariant themeHint(ThemeHint hint) const; + QPlatformMenuItem* createPlatformMenuItem() const Q_DECL_OVERRIDE; + QPlatformMenu* createPlatformMenu() const Q_DECL_OVERRIDE; + const QFont *font(Font type = SystemFont) const; static const char *name; diff --git a/src/plugins/platforms/ios/qiostheme.mm b/src/plugins/platforms/ios/qiostheme.mm index e51e97bd5a..cbeb157cf2 100644 --- a/src/plugins/platforms/ios/qiostheme.mm +++ b/src/plugins/platforms/ios/qiostheme.mm @@ -53,6 +53,8 @@ #include <UIKit/UIFont.h> #include <UIKit/UIInterface.h> +#include "qiosmenu.h" + QT_BEGIN_NAMESPACE const char *QIOSTheme::name = "ios"; @@ -66,6 +68,16 @@ QIOSTheme::~QIOSTheme() qDeleteAll(m_fonts); } +QPlatformMenuItem* QIOSTheme::createPlatformMenuItem() const +{ + return new QIOSMenuItem(); +} + +QPlatformMenu* QIOSTheme::createPlatformMenu() const +{ + return new QIOSMenu(); +} + QVariant QIOSTheme::themeHint(ThemeHint hint) const { switch (hint) { diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index 5687c078ea..3040e89864 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -44,6 +44,7 @@ #include "qiosglobal.h" #include "qiosintegration.h" #include "qioswindow.h" +#include "qiosmenu.h" #include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qwindow_p.h> @@ -347,6 +348,13 @@ QWindowSystemInterface::flushWindowSystemEvents(); } +- (id)targetForAction:(SEL)action withSender:(id)sender +{ + // Check first if QIOSMenu should handle the action before continuing up the responder chain + id target = [QIOSMenu::menuActionTarget() targetForAction:action withSender:sender]; + return target ? target : [super targetForAction:action withSender:sender]; +} + @end @implementation UIView (QtHelpers) diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 6a3930dc78..a23b3cb4bb 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -144,7 +144,7 @@ static inline QColor mixColors(const QColor &c1, const QColor &c2) static inline QColor getSysColor(int index) { - return qColorToCOLORREF(GetSysColor(index)); + return COLORREFToQColor(GetSysColor(index)); } // from QStyle::standardPalette diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index a18bd2834e..888ca3d598 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -1007,8 +1007,8 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) HRESULT QWinRTScreen::onAutomationProviderRequested(ICoreWindow *, IAutomationProviderRequestedEventArgs *args) { - Q_D(const QWinRTScreen); #ifndef Q_OS_WINPHONE + Q_D(const QWinRTScreen); args->put_AutomationProvider(d->inputContext.Get()); #else Q_UNUSED(args) diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index bd62b07a09..72bd22983e 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -193,17 +193,43 @@ void QXcbConnection::xi2SetupDevices() } bool isTablet = false; #ifndef QT_NO_TABLETEVENT - // If we have found the valuators which we expect a tablet to have, assume it's a tablet. + // If we have found the valuators which we expect a tablet to have, it might be a tablet. if (tabletData.valuatorInfo.contains(QXcbAtom::AbsX) && tabletData.valuatorInfo.contains(QXcbAtom::AbsY) && - tabletData.valuatorInfo.contains(QXcbAtom::AbsPressure)) { - tabletData.deviceId = devices[i].deviceid; + tabletData.valuatorInfo.contains(QXcbAtom::AbsPressure)) + isTablet = true; + + // But we need to be careful not to take the touch and tablet-button devices as tablets. + QByteArray name = QByteArray(devices[i].name).toLower(); + QString dbgType = QLatin1String("UNKNOWN"); + if (name.contains("eraser")) { + isTablet = true; + tabletData.pointerType = QTabletEvent::Eraser; + dbgType = QLatin1String("eraser"); + } else if (name.contains("cursor")) { + isTablet = true; + tabletData.pointerType = QTabletEvent::Cursor; + dbgType = QLatin1String("cursor"); + } else if ((name.contains("pen") || name.contains("stylus")) && isTablet) { tabletData.pointerType = QTabletEvent::Pen; - if (QByteArray(devices[i].name).toLower().contains("eraser")) - tabletData.pointerType = QTabletEvent::Eraser; - m_tabletData.append(tabletData); + dbgType = QLatin1String("pen"); + } else if (name.contains("wacom") && isTablet && !name.contains("touch")) { + // combined device (evdev) rather than separate pen/eraser (wacom driver) + tabletData.pointerType = QTabletEvent::Pen; + dbgType = QLatin1String("pen"); + } else if (name.contains("aiptek") /* && device == QXcbAtom::KEYBOARD */) { + // some "Genius" tablets isTablet = true; - qCDebug(lcQpaXInputDevices) << " it's a tablet with pointer type" << tabletData.pointerType; + tabletData.pointerType = QTabletEvent::Pen; + dbgType = QLatin1String("pen"); + } else { + isTablet = false; + } + + if (isTablet) { + tabletData.deviceId = devices[i].deviceid; + m_tabletData.append(tabletData); + qCDebug(lcQpaXInputDevices) << " it's a tablet with pointer type" << dbgType; } #endif // QT_NO_TABLETEVENT @@ -381,6 +407,10 @@ XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id) } else if (vci->label == atom(QXcbAtom::RelY)) { hasRelativeCoords = true; dev->size.setHeight((vci->max - vci->min) * 1000.0 / vci->resolution); + } else if (vci->label == atom(QXcbAtom::AbsX)) { + dev->size.setHeight((vci->max - vci->min) * 1000.0 / vci->resolution); + } else if (vci->label == atom(QXcbAtom::AbsY)) { + dev->size.setWidth((vci->max - vci->min) * 1000.0 / vci->resolution); } break; } @@ -495,6 +525,10 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) nx = valuatorNormalized(value, vci); } else if (vci->label == atom(QXcbAtom::RelY)) { ny = valuatorNormalized(value, vci); + } else if (vci->label == atom(QXcbAtom::AbsX)) { + nx = valuatorNormalized(value, vci); + } else if (vci->label == atom(QXcbAtom::AbsY)) { + ny = valuatorNormalized(value, vci); } else if (vci->label == atom(QXcbAtom::AbsMTPositionX)) { nx = valuatorNormalized(value, vci); } else if (vci->label == atom(QXcbAtom::AbsMTPositionY)) { diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp index 0eed6ea4d3..d411076649 100644 --- a/src/sql/models/qsqltablemodel.cpp +++ b/src/sql/models/qsqltablemodel.cpp @@ -931,7 +931,7 @@ void QSqlTableModel::setPrimaryKey(const QSqlIndex &key) } /*! - Returns a pointer to the used QSqlDatabase or 0 if no database was set. + Returns the model's database connection. */ QSqlDatabase QSqlTableModel::database() const { diff --git a/src/testlib/qtestblacklist.cpp b/src/testlib/qtestblacklist.cpp index 7921b350b5..69f8ae4ca5 100644 --- a/src/testlib/qtestblacklist.cpp +++ b/src/testlib/qtestblacklist.cpp @@ -70,6 +70,7 @@ QT_BEGIN_NAMESPACE // this table can be extended with new keywords as required const char *matchedConditions[] = { + "*", #ifdef Q_OS_LINUX "linux", #endif diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 877be81fb9..00e7ac62c0 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -2372,6 +2372,11 @@ static LONG WINAPI windowsFaultHandler(struct _EXCEPTION_POINTERS *exInfo) } #endif // Q_OS_WIN) && !Q_OS_WINCE && !Q_OS_WINRT +static void initEnvironment() +{ + qputenv("QT_LOGGING_TO_CONSOLE", "1"); +} + /*! Executes tests declared in \a testObject. In addition, the private slots \c{initTestCase()}, \c{cleanupTestCase()}, \c{init()} and \c{cleanup()} @@ -2412,6 +2417,7 @@ static LONG WINAPI windowsFaultHandler(struct _EXCEPTION_POINTERS *exInfo) int QTest::qExec(QObject *testObject, int argc, char **argv) { + initEnvironment(); QBenchmarkGlobalData benchmarkData; QBenchmarkGlobalData::current = &benchmarkData; diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index c074652cf3..95e845d196 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -2671,8 +2671,9 @@ void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logical opt.iconAlignment = Qt::AlignVCenter; opt.text = d->model->headerData(logicalIndex, d->orientation, Qt::DisplayRole).toString(); + const int margin = 2 * style()->pixelMetric(QStyle::PM_HeaderMargin, 0, this); if (d->textElideMode != Qt::ElideNone) - opt.text = opt.fontMetrics.elidedText(opt.text, d->textElideMode , rect.width() - 4); + opt.text = opt.fontMetrics.elidedText(opt.text, d->textElideMode , rect.width() - margin); QVariant variant = d->model->headerData(logicalIndex, d->orientation, Qt::DecorationRole); diff --git a/src/widgets/kernel/qdesktopwidget.cpp b/src/widgets/kernel/qdesktopwidget.cpp index 3975e423a0..2ac1893256 100644 --- a/src/widgets/kernel/qdesktopwidget.cpp +++ b/src/widgets/kernel/qdesktopwidget.cpp @@ -97,6 +97,8 @@ void QDesktopWidgetPrivate::_q_updateScreens() screenWidget->setGeometry(qScreen->geometry()); QObject::connect(qScreen, SIGNAL(geometryChanged(QRect)), q, SLOT(_q_updateScreens()), Qt::QueuedConnection); + QObject::connect(qScreen, SIGNAL(availableGeometryChanged(QRect)), + q, SLOT(_q_availableGeometryChanged()), Qt::QueuedConnection); QObject::connect(qScreen, SIGNAL(destroyed()), q, SLOT(_q_updateScreens()), Qt::QueuedConnection); screens.append(screenWidget); @@ -122,10 +124,15 @@ void QDesktopWidgetPrivate::_q_updateScreens() if (oldLength != targetLength) emit q->screenCountChanged(targetLength); - foreach (int changedScreen, changedScreens) { + foreach (int changedScreen, changedScreens) emit q->resized(changedScreen); - emit q->workAreaResized(changedScreen); - } +} + +void QDesktopWidgetPrivate::_q_availableGeometryChanged() +{ + Q_Q(QDesktopWidget); + if (QScreen *screen = qobject_cast<QScreen *>(q->sender())) + emit q->workAreaResized(QGuiApplication::screens().indexOf(screen)); } QDesktopWidget::QDesktopWidget() diff --git a/src/widgets/kernel/qdesktopwidget.h b/src/widgets/kernel/qdesktopwidget.h index 42c338f696..4bfbf599c1 100644 --- a/src/widgets/kernel/qdesktopwidget.h +++ b/src/widgets/kernel/qdesktopwidget.h @@ -93,6 +93,7 @@ private: Q_DISABLE_COPY(QDesktopWidget) Q_DECLARE_PRIVATE(QDesktopWidget) Q_PRIVATE_SLOT(d_func(), void _q_updateScreens()) + Q_PRIVATE_SLOT(d_func(), void _q_availableGeometryChanged()) friend class QApplication; friend class QApplicationPrivate; diff --git a/src/widgets/kernel/qdesktopwidget_p.h b/src/widgets/kernel/qdesktopwidget_p.h index 160807cf23..89c70e53b0 100644 --- a/src/widgets/kernel/qdesktopwidget_p.h +++ b/src/widgets/kernel/qdesktopwidget_p.h @@ -75,6 +75,7 @@ class QDesktopWidgetPrivate : public QWidgetPrivate { public: ~QDesktopWidgetPrivate() {foreach(QDesktopScreenWidget *s, screens) delete s; } void _q_updateScreens(); + void _q_availableGeometryChanged(); QList<QDesktopScreenWidget *> screens; }; diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 6fbae53804..110682a7b6 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -418,8 +418,7 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q #ifndef QT_NO_GROUPBOX case PE_FrameGroupBox: if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) { - const QStyleOptionFrameV2 *frame2 = qstyleoption_cast<const QStyleOptionFrameV2 *>(opt); - if (frame2 && (frame2->features & QStyleOptionFrameV2::Flat)) { + if (frame->features & QStyleOptionFrame::Flat) { QRect fr = frame->rect; QPoint p1(fr.x(), fr.y() + 1); QPoint p2(fr.x() + fr.width(), p1.y()); @@ -2234,7 +2233,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, #endif // QT_NO_ITEMVIEWS #ifndef QT_NO_FRAME case CE_ShapedFrame: - if (const QStyleOptionFrameV3 *f = qstyleoption_cast<const QStyleOptionFrameV3 *>(opt)) { + if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) { int frameShape = f->frameShape; int frameShadow = QFrame::Plain; if (f->state & QStyle::State_Sunken) { @@ -2824,14 +2823,14 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt, } break; case SE_FrameContents: - if (const QStyleOptionFrameV2 *f = qstyleoption_cast<const QStyleOptionFrameV2 *>(opt)) { + if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) { int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, f, widget); r = opt->rect.adjusted(fw, fw, -fw, -fw); r = visualRect(opt->direction, opt->rect, r); } break; case SE_ShapedFrameContents: - if (const QStyleOptionFrameV3 *f = qstyleoption_cast<const QStyleOptionFrameV3 *>(opt)) { + if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) { int frameShape = f->frameShape; int frameShadow = QFrame::Plain; if (f->state & QStyle::State_Sunken) { @@ -3652,7 +3651,7 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl QRect textRect = proxy()->subControlRect(CC_GroupBox, opt, SC_GroupBoxLabel, widget); QRect checkBoxRect = proxy()->subControlRect(CC_GroupBox, opt, SC_GroupBoxCheckBox, widget); if (groupBox->subControls & QStyle::SC_GroupBoxFrame) { - QStyleOptionFrameV2 frame; + QStyleOptionFrame frame; frame.QStyleOption::operator=(*groupBox); frame.features = groupBox->features; frame.lineWidth = groupBox->lineWidth; @@ -4243,7 +4242,7 @@ QRect QCommonStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex } int frameWidth = 0; - if ((groupBox->features & QStyleOptionFrameV2::Flat) == 0) + if ((groupBox->features & QStyleOptionFrame::Flat) == 0) frameWidth = proxy()->pixelMetric(PM_DefaultFrameWidth, groupBox, widget); ret = frameRect.adjusted(frameWidth, frameWidth + topHeight - topMargin, -frameWidth, -frameWidth); @@ -4255,7 +4254,7 @@ QRect QCommonStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex QFontMetrics fontMetrics = groupBox->fontMetrics; int h = fontMetrics.height(); int tw = fontMetrics.size(Qt::TextShowMnemonic, groupBox->text + QLatin1Char(' ')).width(); - int marg = (groupBox->features & QStyleOptionFrameV2::Flat) ? 0 : 8; + int marg = (groupBox->features & QStyleOptionFrame::Flat) ? 0 : 8; ret = groupBox->rect.adjusted(marg, 0, -marg, 0); ret.setHeight(h); diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 4d9f3a48e2..5e6e528f6d 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -1827,7 +1827,7 @@ QRenderRule QStyleSheetStyle::renderRule(const QObject *obj, const QStyleOption extraClass |= PseudoClass_Frameless; #endif // QT_NO_SPINBOX } else if (const QStyleOptionGroupBox *gb = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) { - if (gb->features & QStyleOptionFrameV2::Flat) + if (gb->features & QStyleOptionFrame::Flat) extraClass |= PseudoClass_Flat; if (gb->lineWidth == 0) extraClass |= PseudoClass_Frameless; @@ -1934,10 +1934,8 @@ QRenderRule QStyleSheetStyle::renderRule(const QObject *obj, const QStyleOption } else if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) { if (frm->lineWidth == 0) extraClass |= PseudoClass_Frameless; - if (const QStyleOptionFrameV2 *frame2 = qstyleoption_cast<const QStyleOptionFrameV2 *>(opt)) { - if (frame2->features & QStyleOptionFrameV2::Flat) - extraClass |= PseudoClass_Flat; - } + if (frm->features & QStyleOptionFrame::Flat) + extraClass |= PseudoClass_Flat; } #ifndef QT_NO_TOOLBAR else if (const QStyleOptionToolBar *tb = qstyleoption_cast<const QStyleOptionToolBar *>(opt)) { @@ -2994,7 +2992,7 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC } frameRect = subControlRect(CC_GroupBox, opt, SC_GroupBoxFrame, w); - QStyleOptionFrameV2 frame; + QStyleOptionFrame frame; frame.QStyleOption::operator=(*gb); frame.features = gb->features; frame.lineWidth = gb->lineWidth; @@ -4089,7 +4087,7 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q case CE_ShapedFrame: if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) { if (rule.hasNativeBorder()) { - QStyleOptionFrameV3 frmOpt(*frm); + QStyleOptionFrame frmOpt(*frm); rule.configurePalette(&frmOpt.palette, QPalette::Text, QPalette::Base); frmOpt.rect = rule.borderRect(frmOpt.rect); baseStyle()->drawControl(ce, &frmOpt, p, w); @@ -4224,10 +4222,8 @@ void QStyleSheetStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *op case PE_Frame: if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) { if (rule.hasNativeBorder()) { - QStyleOptionFrameV2 frmOpt(*frm); + QStyleOptionFrame frmOpt(*frm); rule.configurePalette(&frmOpt.palette, QPalette::Text, QPalette::Base); - if (!qstyleoption_cast<const QStyleOptionFrameV3 *>(opt)) //if it comes from CE_ShapedFrame, the margins are already sustracted - frmOpt.rect = rule.borderRect(frmOpt.rect); baseStyle()->drawPrimitive(pe, &frmOpt, p, w); } else { rule.drawBorder(p, rule.borderRect(opt->rect)); diff --git a/src/widgets/styles/qwindowsvistastyle.cpp b/src/widgets/styles/qwindowsvistastyle.cpp index bdc5a6ce0e..2d09230436 100644 --- a/src/widgets/styles/qwindowsvistastyle.cpp +++ b/src/widgets/styles/qwindowsvistastyle.cpp @@ -1183,7 +1183,8 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption case CE_MenuItem: if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) { // windows always has a check column, regardless whether we have an icon or not - int checkcol = 25; + int checkcol = 25 / QWindowsXPStylePrivate::devicePixelRatio(widget); + const int gutterWidth = 3 / QWindowsXPStylePrivate::devicePixelRatio(widget); { XPThemeData theme(widget, 0, QWindowsXPStylePrivate::MenuTheme, MENU_POPUPCHECKBACKGROUND, MBI_HOT); @@ -1192,7 +1193,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption themeSize.stateId = 0; const QSize size = themeSize.size() / QWindowsXPStylePrivate::devicePixelRatio(widget); const QMargins margins = themeSize.margins() / QWindowsXPStylePrivate::devicePixelRatio(widget); - checkcol = qMax(menuitem->maxIconWidth, int(3 + size.width() + margins.left() + margins.right())); + checkcol = qMax(menuitem->maxIconWidth, gutterWidth + size.width() + margins.left() + margins.right()); } QRect rect = option->rect; @@ -1201,7 +1202,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption checkcol += rect.x(); QPoint p1 = QStyle::visualPos(option->direction, menuitem->rect, QPoint(checkcol, rect.top())); QPoint p2 = QStyle::visualPos(option->direction, menuitem->rect, QPoint(checkcol, rect.bottom())); - QRect gutterRect(p1.x(), p1.y(), 3, p2.y() - p1.y() + 1); + QRect gutterRect(p1.x(), p1.y(), gutterWidth, p2.y() - p1.y() + 1); XPThemeData theme2(widget, painter, QWindowsXPStylePrivate::MenuTheme, MENU_POPUPGUTTER, stateId, gutterRect); d->drawBackground(theme2); @@ -1216,10 +1217,12 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) { int yoff = y-2 + h / 2; + const int separatorSize = 6 / QWindowsXPStylePrivate::devicePixelRatio(widget); QPoint p1 = QPoint(x + checkcol, yoff); - QPoint p2 = QPoint(x + w + 6 , yoff); + QPoint p2 = QPoint(x + w + separatorSize, yoff); stateId = MBI_HOT; - QRect subRect(p1.x() + (3 - menuitem->rect.x()), p1.y(), p2.x() - p1.x(), 6); + QRect subRect(p1.x() + (gutterWidth - menuitem->rect.x()), p1.y(), + p2.x() - p1.x(), separatorSize); subRect = QStyle::visualRect(option->direction, option->rect, subRect ); XPThemeData theme2(widget, painter, QWindowsXPStylePrivate::MenuTheme, @@ -1229,7 +1232,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption } QRect vCheckRect = visualRect(option->direction, menuitem->rect, QRect(menuitem->rect.x(), - menuitem->rect.y(), checkcol - (3 + menuitem->rect.x()), menuitem->rect.height())); + menuitem->rect.y(), checkcol - (gutterWidth + menuitem->rect.x()), menuitem->rect.height())); if (act) { stateId = dis ? MBI_DISABLED : MBI_HOT; @@ -1294,7 +1297,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption if (dis) painter->setPen(textColor); - int xm = windowsItemFrame + checkcol + windowsItemHMargin + (3 - menuitem->rect.x()) - 1; + int xm = windowsItemFrame + checkcol + windowsItemHMargin + (gutterWidth - menuitem->rect.x()) - 1; int xpos = menuitem->rect.x() + xm; QRect textRect(xpos, y + windowsItemVMargin, w - xm - windowsRightBorder - tab + 1, h - 2 * windowsItemVMargin); QRect vTextRect = visualRect(option->direction, menuitem->rect, textRect); diff --git a/src/widgets/widgets/qabstractspinbox.cpp b/src/widgets/widgets/qabstractspinbox.cpp index 4aed153932..0d8c7957e2 100644 --- a/src/widgets/widgets/qabstractspinbox.cpp +++ b/src/widgets/widgets/qabstractspinbox.cpp @@ -1100,7 +1100,10 @@ void QAbstractSpinBox::keyReleaseEvent(QKeyEvent *event) #ifndef QT_NO_WHEELEVENT void QAbstractSpinBox::wheelEvent(QWheelEvent *event) { - const int steps = (event->delta() > 0 ? 1 : -1); + Q_D(QAbstractSpinBox); + d->wheelDeltaRemainder += event->angleDelta().y(); + const int steps = d->wheelDeltaRemainder / 120; + d->wheelDeltaRemainder -= steps * 120; if (stepEnabled() & (steps > 0 ? StepUpEnabled : StepDownEnabled)) stepBy(event->modifiers() & Qt::ControlModifier ? steps * 10 : steps); event->accept(); @@ -1344,7 +1347,7 @@ QAbstractSpinBoxPrivate::QAbstractSpinBoxPrivate() ignoreCursorPositionChanged(false), frame(true), accelerate(false), keyboardTracking(true), cleared(false), ignoreUpdateEdit(false), correctionMode(QAbstractSpinBox::CorrectToPreviousValue), acceleration(0), hoverControl(QStyle::SC_None), buttonSymbols(QAbstractSpinBox::UpDownArrows), validator(0), - showGroupSeparator(0) + showGroupSeparator(0), wheelDeltaRemainder(0) { } diff --git a/src/widgets/widgets/qabstractspinbox_p.h b/src/widgets/widgets/qabstractspinbox_p.h index da9f1d9757..055fe92591 100644 --- a/src/widgets/widgets/qabstractspinbox_p.h +++ b/src/widgets/widgets/qabstractspinbox_p.h @@ -151,6 +151,7 @@ public: QAbstractSpinBox::ButtonSymbols buttonSymbols; QSpinBoxValidator *validator; uint showGroupSeparator : 1; + int wheelDeltaRemainder; }; class QSpinBoxValidator : public QValidator diff --git a/src/widgets/widgets/qcalendartextnavigator_p.h b/src/widgets/widgets/qcalendartextnavigator_p.h deleted file mode 100644 index 88bd3c6a71..0000000000 --- a/src/widgets/widgets/qcalendartextnavigator_p.h +++ /dev/null @@ -1,112 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtWidgets module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QCALENDARTEXTNAVIGATOR_P_H -#define QCALENDARTEXTNAVIGATOR_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/qobject.h> -#include <QtCore/qdatetime.h> -#include <QtCore/qbasictimer.h> - -#ifndef QT_NO_CALENDARWIDGET - -QT_BEGIN_NAMESPACE - -class QLabel; -class QCalendarDateValidator; -class QFrame; - -class QCalendarTextNavigator: public QObject -{ - Q_OBJECT -public: - QCalendarTextNavigator(QObject *parent = 0) - : QObject(parent), m_dateText(0), m_dateFrame(0), m_dateValidator(0), m_widget(0), m_editDelay(1500), m_date(QDate::currentDate()) { } - - QWidget *widget() const; - void setWidget(QWidget *widget); - - int dateEditAcceptDelay() const; - void setDateEditAcceptDelay(int delay); - - QDate date() const; - void setDate(const QDate &date); - - bool eventFilter(QObject *o, QEvent *e); - void timerEvent(QTimerEvent *e); - -signals: - void dateChanged(const QDate &date); - void editingFinished(); - -private: - void applyDate(); - void updateDateLabel(); - void createDateLabel(); - void removeDateLabel(); - - QLabel *m_dateText; - QFrame *m_dateFrame; - QBasicTimer m_acceptTimer; - QCalendarDateValidator *m_dateValidator; - QWidget *m_widget; - int m_editDelay; - - QDate m_date; -}; - -QT_END_NAMESPACE - -#endif // QT_NO_CALENDARWIDGET - -#endif - diff --git a/src/widgets/widgets/qcalendarwidget.cpp b/src/widgets/widgets/qcalendarwidget.cpp index 8755f99288..b281b98cb0 100644 --- a/src/widgets/widgets/qcalendarwidget.cpp +++ b/src/widgets/widgets/qcalendarwidget.cpp @@ -60,7 +60,6 @@ #include <qapplication.h> #include <qbasictimer.h> #include <qstylepainter.h> -#include <private/qcalendartextnavigator_p.h> QT_BEGIN_NAMESPACE @@ -72,6 +71,8 @@ enum { MinimumDayOffset = 1 }; +namespace { + class QCalendarDateSectionValidator { public: @@ -589,6 +590,7 @@ void QCalendarDateValidator::setFormat(const QString &format) const QChar nextChar = format.at(pos); if (quoting) { separator += nextChar; + quoting = false; } else { SectionToken *token = 0; if (nextChar == QLatin1Char('d')) { @@ -671,6 +673,47 @@ void QCalendarDateValidator::handleKeyEvent(QKeyEvent *keyEvent) toPreviousToken(); } +////////////////////////////////// + +class QCalendarTextNavigator: public QObject +{ + Q_OBJECT +public: + QCalendarTextNavigator(QObject *parent = 0) + : QObject(parent), m_dateText(0), m_dateFrame(0), m_dateValidator(0), m_widget(0), m_editDelay(1500), m_date(QDate::currentDate()) { } + + QWidget *widget() const; + void setWidget(QWidget *widget); + + int dateEditAcceptDelay() const; + void setDateEditAcceptDelay(int delay); + + QDate date() const; + void setDate(const QDate &date); + + bool eventFilter(QObject *o, QEvent *e); + void timerEvent(QTimerEvent *e); + +signals: + void dateChanged(const QDate &date); + void editingFinished(); + +private: + void applyDate(); + void updateDateLabel(); + void createDateLabel(); + void removeDateLabel(); + + QLabel *m_dateText; + QFrame *m_dateFrame; + QBasicTimer m_acceptTimer; + QCalendarDateValidator *m_dateValidator; + QWidget *m_widget; + int m_editDelay; + + QDate m_date; +}; + QWidget *QCalendarTextNavigator::widget() const { return m_widget; @@ -1573,6 +1616,8 @@ protected: } }; +} // unnamed namespace + class QCalendarWidgetPrivate : public QWidgetPrivate { Q_DECLARE_PUBLIC(QCalendarWidget) diff --git a/src/widgets/widgets/qplaintextedit.cpp b/src/widgets/widgets/qplaintextedit.cpp index 3ff8e8cbbf..f1471cc6e4 100644 --- a/src/widgets/widgets/qplaintextedit.cpp +++ b/src/widgets/widgets/qplaintextedit.cpp @@ -2277,11 +2277,8 @@ void QPlainTextEdit::wheelEvent(QWheelEvent *e) Q_D(QPlainTextEdit); if (!(d->control->textInteractionFlags() & Qt::TextEditable)) { if (e->modifiers() & Qt::ControlModifier) { - const int delta = e->delta(); - if (delta < 0) - zoomOut(); - else if (delta > 0) - zoomIn(); + float delta = e->angleDelta().y() / 120.f; + zoomInF(delta); return; } } @@ -2301,12 +2298,7 @@ void QPlainTextEdit::wheelEvent(QWheelEvent *e) */ void QPlainTextEdit::zoomIn(int range) { - QFont f = font(); - const int newSize = f.pointSize() + range; - if (newSize <= 0) - return; - f.setPointSize(newSize); - setFont(f); + zoomInF(range); } /*! @@ -2322,7 +2314,22 @@ void QPlainTextEdit::zoomIn(int range) */ void QPlainTextEdit::zoomOut(int range) { - zoomIn(-range); + zoomInF(-range); +} + +/*! + \internal +*/ +void QPlainTextEdit::zoomInF(float range) +{ + if (range == 0.f) + return; + QFont f = font(); + const float newSize = f.pointSizeF() + range; + if (newSize <= 0) + return; + f.setPointSizeF(newSize); + setFont(f); } #ifndef QT_NO_CONTEXTMENU diff --git a/src/widgets/widgets/qplaintextedit.h b/src/widgets/widgets/qplaintextedit.h index 54cd3e14ed..f61d9c3aaa 100644 --- a/src/widgets/widgets/qplaintextedit.h +++ b/src/widgets/widgets/qplaintextedit.h @@ -271,6 +271,7 @@ protected: QRectF blockBoundingGeometry(const QTextBlock &block) const; QAbstractTextDocumentLayout::PaintContext getPaintContext() const; + void zoomInF(float range); private: Q_DISABLE_COPY(QPlainTextEdit) diff --git a/src/widgets/widgets/qtextedit.cpp b/src/widgets/widgets/qtextedit.cpp index f106b70c12..b4dd09d6d4 100644 --- a/src/widgets/widgets/qtextedit.cpp +++ b/src/widgets/widgets/qtextedit.cpp @@ -1813,11 +1813,8 @@ void QTextEdit::wheelEvent(QWheelEvent *e) Q_D(QTextEdit); if (!(d->control->textInteractionFlags() & Qt::TextEditable)) { if (e->modifiers() & Qt::ControlModifier) { - const int delta = e->delta(); - if (delta < 0) - zoomOut(); - else if (delta > 0) - zoomIn(); + float delta = e->angleDelta().y() / 120.f; + zoomInF(delta); return; } } @@ -2276,12 +2273,7 @@ void QTextEdit::scrollToAnchor(const QString &name) */ void QTextEdit::zoomIn(int range) { - QFont f = font(); - const int newSize = f.pointSize() + range; - if (newSize <= 0) - return; - f.setPointSize(newSize); - setFont(f); + zoomInF(range); } /*! @@ -2297,7 +2289,22 @@ void QTextEdit::zoomIn(int range) */ void QTextEdit::zoomOut(int range) { - zoomIn(-range); + zoomInF(-range); +} + +/*! + \internal +*/ +void QTextEdit::zoomInF(float range) +{ + if (range == 0.f) + return; + QFont f = font(); + const float newSize = f.pointSizeF() + range; + if (newSize <= 0) + return; + f.setPointSizeF(newSize); + setFont(f); } /*! diff --git a/src/widgets/widgets/qtextedit.h b/src/widgets/widgets/qtextedit.h index a283a51b90..d23d2d59ce 100644 --- a/src/widgets/widgets/qtextedit.h +++ b/src/widgets/widgets/qtextedit.h @@ -304,6 +304,8 @@ protected: virtual void scrollContentsBy(int dx, int dy); virtual void doSetTextCursor(const QTextCursor &cursor); + void zoomInF(float range); + private: Q_DISABLE_COPY(QTextEdit) Q_PRIVATE_SLOT(d_func(), void _q_repaintContents(const QRectF &r)) diff --git a/src/widgets/widgets/widgets.pri b/src/widgets/widgets/widgets.pri index a924ba9acc..342d2093db 100644 --- a/src/widgets/widgets/widgets.pri +++ b/src/widgets/widgets/widgets.pri @@ -8,7 +8,6 @@ HEADERS += \ widgets/qabstractslider_p.h \ widgets/qabstractspinbox.h \ widgets/qabstractspinbox_p.h \ - widgets/qcalendartextnavigator_p.h \ widgets/qcalendarwidget.h \ widgets/qcheckbox.h \ widgets/qcombobox.h \ |