summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorJani Heikkinen <jani.heikkinen@theqtcompany.com>2016-01-21 04:27:06 +0000
committerThe Qt Project <gerrit-noreply@qt-project.org>2016-01-21 04:27:06 +0000
commit7b2fb038ae4b8b9231ae989ad309b6eca107a858 (patch)
tree04001416e9589b7e79a6a5b1490e7eaabc22e82a /src/corelib
parent9c0de96454570aec3fe88ba6b5d7c61b666b5753 (diff)
parent8f569c740a91b98365dcdaee2444038ce4957a76 (diff)
Merge "Merge remote-tracking branch 'origin/5.5' into 5.6" into refs/staging/5.6
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/codecs/qutfcodec.cpp9
-rw-r--r--src/corelib/io/qfiledevice.cpp2
-rw-r--r--src/corelib/io/qfileselector.cpp11
-rw-r--r--src/corelib/io/qfsfileengine.cpp46
-rw-r--r--src/corelib/io/qiodevice_p.h16
-rw-r--r--src/corelib/io/qlockfile_p.h2
-rw-r--r--src/corelib/io/qlockfile_unix.cpp42
-rw-r--r--src/corelib/io/qsettings.cpp8
-rw-r--r--src/corelib/io/qwinoverlappedionotifier.cpp2
-rw-r--r--src/corelib/json/qjson_p.h2
-rw-r--r--src/corelib/kernel/qeventdispatcher_win.cpp44
-rw-r--r--src/corelib/kernel/qeventdispatcher_win_p.h2
-rw-r--r--src/corelib/kernel/qsignalmapper.cpp3
-rw-r--r--src/corelib/kernel/qvariant.cpp9
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp10
15 files changed, 137 insertions, 71 deletions
diff --git a/src/corelib/codecs/qutfcodec.cpp b/src/corelib/codecs/qutfcodec.cpp
index a64b3d167e..476990fb7a 100644
--- a/src/corelib/codecs/qutfcodec.cpp
+++ b/src/corelib/codecs/qutfcodec.cpp
@@ -363,6 +363,7 @@ QString QUtf8::convertToUnicode(const char *chars, int len, QTextCodec::Converte
// main body, stateless decoding
res = 0;
const uchar *nextAscii = src;
+ const uchar *start = src;
while (res >= 0 && src < end) {
if (src >= nextAscii && simdDecodeAscii(dst, nextAscii, src, end))
break;
@@ -371,9 +372,11 @@ QString QUtf8::convertToUnicode(const char *chars, int len, QTextCodec::Converte
res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(ch, dst, src, end);
if (!headerdone && res >= 0) {
headerdone = true;
- // eat the UTF-8 BOM
- if (dst[-1] == 0xfeff)
- --dst;
+ if (src == start + 3) { // 3 == sizeof(utf8-bom)
+ // eat the UTF-8 BOM (it can only appear at the beginning of the string).
+ if (dst[-1] == 0xfeff)
+ --dst;
+ }
}
if (res == QUtf8BaseTraits::Error) {
res = 0;
diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp
index 4c5ed0aef6..8531d32523 100644
--- a/src/corelib/io/qfiledevice.cpp
+++ b/src/corelib/io/qfiledevice.cpp
@@ -560,7 +560,7 @@ qint64 QFileDevice::writeData(const char *data, qint64 len)
char *writePointer = d->writeBuffer.reserve(len);
if (len == 1)
*writePointer = *data;
- else
+ else if (len)
::memcpy(writePointer, data, len);
return len;
}
diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp
index f033392df8..52ac414645 100644
--- a/src/corelib/io/qfileselector.cpp
+++ b/src/corelib/io/qfileselector.cpp
@@ -248,9 +248,16 @@ QUrl QFileSelector::select(const QUrl &filePath) const
return filePath;
QUrl ret(filePath);
if (isLocalScheme(filePath.scheme())) {
- QString equivalentPath = QLatin1Char(':') + filePath.path();
+ QLatin1String scheme(":");
+#ifdef Q_OS_ANDROID
+ // use other scheme because ":" means "qrc" here
+ if (filePath.scheme() == QLatin1String("assets"))
+ scheme = QLatin1String("assets:");
+#endif
+
+ QString equivalentPath = scheme + filePath.path();
QString selectedPath = d->select(equivalentPath);
- ret.setPath(selectedPath.remove(0, 1));
+ ret.setPath(selectedPath.remove(0, scheme.size()));
} else {
ret = QUrl::fromLocalFile(d->select(ret.toLocalFile()));
}
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp
index 429c40da1a..10e116a23a 100644
--- a/src/corelib/io/qfsfileengine.cpp
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -724,29 +724,33 @@ qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len)
qint64 writtenBytes = 0;
- if (fh) {
- // Buffered stdlib mode.
-
- size_t result;
- do {
- result = fwrite(data + writtenBytes, 1, size_t(len - writtenBytes), fh);
- writtenBytes += result;
- } while (result == 0 ? errno == EINTR : writtenBytes < len);
+ if (len) { // avoid passing nullptr to fwrite() or QT_WRITE() (UB)
- } else if (fd != -1) {
- // Unbuffered stdio mode.
+ if (fh) {
+ // Buffered stdlib mode.
+
+ size_t result;
+ do {
+ result = fwrite(data + writtenBytes, 1, size_t(len - writtenBytes), fh);
+ writtenBytes += result;
+ } while (result == 0 ? errno == EINTR : writtenBytes < len);
+
+ } else if (fd != -1) {
+ // Unbuffered stdio mode.
+
+ SignedIOType result;
+ do {
+ // calculate the chunk size
+ // on Windows or 32-bit no-largefile Unix, we'll need to read in chunks
+ // we limit to the size of the signed type, otherwise we could get a negative number as a result
+ quint64 wantedBytes = quint64(len) - quint64(writtenBytes);
+ UnsignedIOType chunkSize = std::numeric_limits<SignedIOType>::max();
+ if (chunkSize > wantedBytes)
+ chunkSize = wantedBytes;
+ result = QT_WRITE(fd, data + writtenBytes, chunkSize);
+ } while (result > 0 && (writtenBytes += result) < len);
+ }
- SignedIOType result;
- do {
- // calculate the chunk size
- // on Windows or 32-bit no-largefile Unix, we'll need to read in chunks
- // we limit to the size of the signed type, otherwise we could get a negative number as a result
- quint64 wantedBytes = quint64(len) - quint64(writtenBytes);
- UnsignedIOType chunkSize = std::numeric_limits<SignedIOType>::max();
- if (chunkSize > wantedBytes)
- chunkSize = wantedBytes;
- result = QT_WRITE(fd, data + writtenBytes, chunkSize);
- } while (result > 0 && (writtenBytes += result) < len);
}
if (len && writtenBytes == 0) {
diff --git a/src/corelib/io/qiodevice_p.h b/src/corelib/io/qiodevice_p.h
index 56a89ab680..6ab1de27e0 100644
--- a/src/corelib/io/qiodevice_p.h
+++ b/src/corelib/io/qiodevice_p.h
@@ -102,14 +102,17 @@ public:
}
qint64 read(char* target, qint64 size) {
qint64 r = qMin(size, len);
- memcpy(target, first, r);
- len -= r;
- first += r;
+ if (r) {
+ memcpy(target, first, r);
+ len -= r;
+ first += r;
+ }
return r;
}
qint64 peek(char* target, qint64 size) {
qint64 r = qMin(size, len);
- memcpy(target, first, r);
+ if (r)
+ memcpy(target, first, r);
return r;
}
char* reserve(qint64 size) {
@@ -141,7 +144,7 @@ public:
return r;
}
bool canReadLine() const {
- return memchr(first, '\n', len);
+ return first && memchr(first, '\n', len);
}
void ungetChar(char c) {
if (first == buf) {
@@ -172,7 +175,8 @@ private:
if (newCapacity > capacity) {
// allocate more space
char* newBuf = new char[newCapacity];
- memmove(newBuf + moveOffset, first, len);
+ if (first)
+ memmove(newBuf + moveOffset, first, len);
delete [] buf;
buf = newBuf;
capacity = newCapacity;
diff --git a/src/corelib/io/qlockfile_p.h b/src/corelib/io/qlockfile_p.h
index 168062f467..48b642abd0 100644
--- a/src/corelib/io/qlockfile_p.h
+++ b/src/corelib/io/qlockfile_p.h
@@ -78,7 +78,7 @@ public:
static QString processNameByPid(qint64 pid);
#ifdef Q_OS_UNIX
- static int checkFcntlWorksAfterFlock();
+ static int checkFcntlWorksAfterFlock(const QString &fn);
#endif
QString fileName;
diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp
index 365f3e07ab..623968b869 100644
--- a/src/corelib/io/qlockfile_unix.cpp
+++ b/src/corelib/io/qlockfile_unix.cpp
@@ -39,6 +39,10 @@
#include "QtCore/qfileinfo.h"
#include "QtCore/qdebug.h"
#include "QtCore/qdatetime.h"
+#include "QtCore/qfileinfo.h"
+#include "QtCore/qcache.h"
+#include "QtCore/qglobalstatic.h"
+#include "QtCore/qmutex.h"
#include "private/qcore_unix_p.h" // qt_safe_open
#include "private/qabstractfileengine_p.h"
@@ -89,10 +93,10 @@ static qint64 qt_write_loop(int fd, const char *data, qint64 len)
return pos;
}
-int QLockFilePrivate::checkFcntlWorksAfterFlock()
+int QLockFilePrivate::checkFcntlWorksAfterFlock(const QString &fn)
{
#ifndef QT_NO_TEMPORARYFILE
- QTemporaryFile file;
+ QTemporaryFile file(fn);
if (!file.open())
return 0;
const int fd = file.d_func()->engine()->handle();
@@ -114,24 +118,34 @@ int QLockFilePrivate::checkFcntlWorksAfterFlock()
#endif
}
-static QBasicAtomicInt fcntlOK = Q_BASIC_ATOMIC_INITIALIZER(-1);
+// Cache the result of checkFcntlWorksAfterFlock for each directory a lock
+// file is created in because in some filesystems, like NFS, both locks
+// are the same. This does not take into account a filesystem changing.
+// QCache is set to hold a maximum of 10 entries, this is to avoid unbounded
+// growth, this is caching directories of files and it is assumed a low number
+// will be sufficient.
+typedef QCache<QString, bool> CacheType;
+Q_GLOBAL_STATIC_WITH_ARGS(CacheType, fcntlOK, (10));
+static QBasicMutex fcntlLock;
/*!
\internal
Checks that the OS isn't using POSIX locks to emulate flock().
OS X is one of those.
*/
-static bool fcntlWorksAfterFlock()
+static bool fcntlWorksAfterFlock(const QString &fn)
{
- int value = fcntlOK.load();
- if (Q_UNLIKELY(value == -1)) {
- value = QLockFilePrivate::checkFcntlWorksAfterFlock();
- fcntlOK.store(value);
+ QMutexLocker lock(&fcntlLock);
+ bool *worksPtr = fcntlOK->object(fn);
+ if (!worksPtr) {
+ worksPtr = new bool(QLockFilePrivate::checkFcntlWorksAfterFlock(fn));
+ fcntlOK->insert(fn, worksPtr);
}
- return value == 1;
+
+ return *worksPtr;
}
-static bool setNativeLocks(int fd)
+static bool setNativeLocks(const QString &fileName, int fd)
{
#if defined(LOCK_EX) && defined(LOCK_NB)
if (flock(fd, LOCK_EX | LOCK_NB) == -1) // other threads, and other processes on a local fs
@@ -143,8 +157,10 @@ static bool setNativeLocks(int fd)
flockData.l_start = 0;
flockData.l_len = 0; // 0 = entire file
flockData.l_pid = getpid();
- if (fcntlWorksAfterFlock() && fcntl(fd, F_SETLK, &flockData) == -1) // for networked filesystems
+ if (fcntlWorksAfterFlock(QDir::cleanPath(QFileInfo(fileName).absolutePath()) + QString('/'))
+ && fcntl(fd, F_SETLK, &flockData) == -1) { // for networked filesystems
return false;
+ }
return true;
}
@@ -171,7 +187,7 @@ QLockFile::LockError QLockFilePrivate::tryLock_sys()
}
}
// Ensure nobody else can delete the file while we have it
- if (!setNativeLocks(fd)) {
+ if (!setNativeLocks(fileName, fd)) {
const int errnoSaved = errno;
qWarning() << "setNativeLocks failed:" << qt_error_string(errnoSaved);
}
@@ -202,7 +218,7 @@ bool QLockFilePrivate::removeStaleLock()
const int fd = qt_safe_open(lockFileName.constData(), O_WRONLY, 0644);
if (fd < 0) // gone already?
return false;
- bool success = setNativeLocks(fd) && (::unlink(lockFileName) == 0);
+ bool success = setNativeLocks(fileName, fd) && (::unlink(lockFileName) == 0);
close(fd);
return success;
}
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index 0c44582af8..1c7ceed3c1 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -1410,13 +1410,17 @@ void QConfFileSettingsPrivate::syncConfFile(int confFileNo)
Concurrent read and write are not a problem because the writing operation is atomic.
*/
QLockFile lockFile(confFile->name + QLatin1String(".lock"));
+#endif
if (!readOnly) {
- if (!confFile->isWritable() || !lockFile.lock() ) {
+ if (!confFile->isWritable()
+#ifndef QT_BOOTSTRAPPED
+ || !lockFile.lock()
+#endif
+ ) {
setStatus(QSettings::AccessError);
return;
}
}
-#endif
/*
We hold the lock. Let's reread the file if it has changed
diff --git a/src/corelib/io/qwinoverlappedionotifier.cpp b/src/corelib/io/qwinoverlappedionotifier.cpp
index c9de6671f7..0cefa374fa 100644
--- a/src/corelib/io/qwinoverlappedionotifier.cpp
+++ b/src/corelib/io/qwinoverlappedionotifier.cpp
@@ -364,7 +364,7 @@ bool QWinOverlappedIoNotifier::waitForNotified(int msecs, OVERLAPPED *overlapped
return false;
if (triggeredOverlapped == overlapped)
return true;
- msecs = qt_subtract_from_timeout(msecs, stopWatch.elapsed());
+ t = qt_subtract_from_timeout(msecs, stopWatch.elapsed());
if (t == 0)
return false;
}
diff --git a/src/corelib/json/qjson_p.h b/src/corelib/json/qjson_p.h
index 35a16b0ef6..7f5a2d88a1 100644
--- a/src/corelib/json/qjson_p.h
+++ b/src/corelib/json/qjson_p.h
@@ -305,7 +305,7 @@ public:
{
d->length = str.length();
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- const qle_ushort *uc = (const qle_ushort *)str.unicode();
+ const ushort *uc = (const ushort *)str.unicode();
for (int i = 0; i < str.length(); ++i)
d->utf16[i] = uc[i];
#else
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp
index bb091e9f6d..1a14500bd4 100644
--- a/src/corelib/kernel/qeventdispatcher_win.cpp
+++ b/src/corelib/kernel/qeventdispatcher_win.cpp
@@ -78,6 +78,7 @@ extern uint qGlobalPostedEventsCount();
enum {
WM_QT_SOCKETNOTIFIER = WM_USER,
WM_QT_SENDPOSTEDEVENTS = WM_USER + 1,
+ WM_QT_ACTIVATENOTIFIERS = WM_USER + 2,
SendPostedEventsWindowsTimerId = ~1u
};
@@ -308,7 +309,7 @@ static void resolveTimerAPI()
QEventDispatcherWin32Private::QEventDispatcherWin32Private()
: threadId(GetCurrentThreadId()), interrupt(false), closingDown(false), internalHwnd(0),
getMessageHook(0), serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0),
- wakeUps(0)
+ wakeUps(0), activateNotifiersPosted(false)
{
resolveTimerAPI();
}
@@ -392,6 +393,7 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
if (sn) {
d->doWsaAsyncSelect(sn->fd, 0);
d->active_fd[sn->fd].selected = false;
+ d->postActivateSocketNotifiers();
if (type < 3) {
QEvent event(QEvent::SockAct);
QCoreApplication::sendEvent(sn->obj, &event);
@@ -402,6 +404,20 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
}
}
return 0;
+ } else if (message == WM_QT_ACTIVATENOTIFIERS) {
+ Q_ASSERT(d != 0);
+
+ // register all socket notifiers
+ for (QSFDict::iterator it = d->active_fd.begin(), end = d->active_fd.end();
+ it != end; ++it) {
+ QSockFd &sd = it.value();
+ if (!sd.selected) {
+ d->doWsaAsyncSelect(it.key(), sd.event);
+ sd.selected = true;
+ }
+ }
+ d->activateNotifiersPosted = false;
+ return 0;
} else if (message == WM_QT_SENDPOSTEDEVENTS
// we also use a Windows timer to send posted events when the message queue is full
|| (message == WM_TIMER
@@ -642,6 +658,12 @@ void QEventDispatcherWin32Private::doWsaAsyncSelect(int socket, long event)
WSAAsyncSelect(socket, internalHwnd, event ? int(WM_QT_SOCKETNOTIFIER) : 0, event);
}
+void QEventDispatcherWin32Private::postActivateSocketNotifiers()
+{
+ if (!activateNotifiersPosted)
+ activateNotifiersPosted = PostMessage(internalHwnd, WM_QT_ACTIVATENOTIFIERS, 0, 0);
+}
+
void QEventDispatcherWin32::createInternalHwnd()
{
Q_D(QEventDispatcherWin32);
@@ -760,16 +782,6 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
d->queuedSocketEvents.append(msg);
continue;
}
- } else if (!(flags & QEventLoop::ExcludeSocketNotifiers)) {
- // register all socket notifiers
- for (QSFDict::iterator it = d->active_fd.begin(), end = d->active_fd.end();
- it != end; ++it) {
- QSockFd &sd = it.value();
- if (!sd.selected) {
- d->doWsaAsyncSelect(it.key(), sd.event);
- sd.selected = true;
- }
- }
}
}
if (!haveMessage) {
@@ -890,6 +902,8 @@ void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
"same socket %d and type %s", sockfd, t[type]);
}
+ createInternalHwnd();
+
QSockNot *sn = new QSockNot;
sn->obj = notifier;
sn->fd = sockfd;
@@ -914,6 +928,8 @@ void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
} else {
d->active_fd.insert(sockfd, QSockFd(event));
}
+
+ d->postActivateSocketNotifiers();
}
void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier)
@@ -939,10 +955,12 @@ void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier)
d->doWsaAsyncSelect(sockfd, 0);
const long event[3] = { FD_READ | FD_CLOSE | FD_ACCEPT, FD_WRITE | FD_CONNECT, FD_OOB };
sd.event ^= event[type];
- if (sd.event == 0)
+ if (sd.event == 0) {
d->active_fd.erase(it);
- else
+ } else if (sd.selected) {
sd.selected = false;
+ d->postActivateSocketNotifiers();
+ }
}
QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h
index 8578110ee4..9a53e06730 100644
--- a/src/corelib/kernel/qeventdispatcher_win_p.h
+++ b/src/corelib/kernel/qeventdispatcher_win_p.h
@@ -178,7 +178,9 @@ public:
QSNDict sn_write;
QSNDict sn_except;
QSFDict active_fd;
+ bool activateNotifiersPosted;
void doWsaAsyncSelect(int socket, long event);
+ void postActivateSocketNotifiers();
QList<QWinEventNotifier *> winEventNotifierList;
void activateEventNotifier(QWinEventNotifier * wen);
diff --git a/src/corelib/kernel/qsignalmapper.cpp b/src/corelib/kernel/qsignalmapper.cpp
index 00aa31383f..5e8ce0c251 100644
--- a/src/corelib/kernel/qsignalmapper.cpp
+++ b/src/corelib/kernel/qsignalmapper.cpp
@@ -220,6 +220,9 @@ QObject *QSignalMapper::mapping(QObject *object) const
Removes all mappings for \a sender.
This is done automatically when mapped objects are destroyed.
+
+ \note This does not disconnect any signals. If \a sender is not destroyed
+ then this will need to be done explicitly if required.
*/
void QSignalMapper::removeMappings(QObject *sender)
{
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 3e6aefab2a..9298093f44 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -2891,6 +2891,7 @@ static const quint32 qCanConvertMatrix[QVariant::LastCoreType + 1] =
/*QUuid*/ 1 << QVariant::String
};
+static const size_t qCanConvertMatrixMaximumTargetType = 8 * sizeof(*qCanConvertMatrix);
#ifndef QT_BOOTSTRAPPED
/*!
@@ -3140,8 +3141,9 @@ bool QVariant::canConvert(int targetTypeId) const
case QMetaType::ULong:
case QMetaType::Short:
case QMetaType::UShort:
- return qCanConvertMatrix[QVariant::Int] & (1 << currentType)
- || currentType == QVariant::Int
+ return currentType == QVariant::Int
+ || (currentType < qCanConvertMatrixMaximumTargetType
+ && qCanConvertMatrix[QVariant::Int] & (1U << currentType))
|| QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration;
case QMetaType::QObjectStar:
return canConvertMetaObject(currentType, targetTypeId, d.data.o);
@@ -3152,7 +3154,8 @@ bool QVariant::canConvert(int targetTypeId) const
if (targetTypeId == String && currentType == StringList)
return v_cast<QStringList>(&d)->count() == 1;
- return qCanConvertMatrix[targetTypeId] & (1 << currentType);
+ return currentType < qCanConvertMatrixMaximumTargetType
+ && qCanConvertMatrix[targetTypeId] & (1U << currentType);
}
/*!
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index 20d5ed890b..63cf7672cf 100644
--- a/src/corelib/statemachine/qstatemachine.cpp
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -1891,12 +1891,14 @@ void QStateMachinePrivate::_q_process()
}
}
if (enabledTransitions.isEmpty()) {
- processing = false;
- stopProcessingReason = EventQueueEmpty;
- noMicrostep();
+ if (isInternalEventQueueEmpty()) {
+ processing = false;
+ stopProcessingReason = EventQueueEmpty;
+ noMicrostep();
#ifdef QSTATEMACHINE_DEBUG
- qDebug() << q << ": no transitions enabled";
+ qDebug() << q << ": no transitions enabled";
#endif
+ }
} else {
didChange = true;
q->beginMicrostep(e);