diff options
Diffstat (limited to 'src')
61 files changed, 821 insertions, 282 deletions
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 8d6f7834b0..53d2b7b58b 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -2804,11 +2804,11 @@ This enum type describes the state of a gesture. + \value NoGesture No gesture has been detected. \value GestureStarted A continuous gesture has started. \value GestureUpdated A gesture continues. \value GestureFinished A gesture has finished. \value GestureCanceled A gesture was canceled. - \omitvalue NoGesture \sa QGesture */ diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index d4c5e03058..b21e9b51e1 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -403,6 +403,7 @@ #include "qdebug.h" #include "qhash.h" #include "qdir.h" // for QDir::fromNativeSeparators +#include "qdatastream.h" #include "qtldurl_p.h" #include "private/qipaddress_p.h" #include "qurlquery.h" @@ -429,6 +430,16 @@ static inline QString fileScheme() return QStringLiteral("file"); } +static inline QString webDavScheme() +{ + return QStringLiteral("webdavs"); +} + +static inline QString webDavSslTag() +{ + return QStringLiteral("@SSL"); +} + #ifdef Q_COMPILER_CLASS_ENUM # define colon_uchar : uchar #else @@ -992,10 +1003,15 @@ inline bool QUrlPrivate::setScheme(const QString &value, int len, bool doSetErro } // did we set to the file protocol? - if (scheme == fileScheme()) + if (scheme == fileScheme() +#ifdef Q_OS_WIN + || scheme == webDavScheme() +#endif + ) { flags |= IsLocalFile; - else + } else { flags &= ~IsLocalFile; + } return true; } @@ -3738,7 +3754,7 @@ QUrl QUrl::fromLocalFile(const QString &localFile) QUrl url; if (localFile.isEmpty()) return url; - url.setScheme(fileScheme()); + QString scheme = fileScheme(); QString deslashified = QDir::fromNativeSeparators(localFile); // magic for drives on windows @@ -3747,13 +3763,21 @@ QUrl QUrl::fromLocalFile(const QString &localFile) } else if (deslashified.startsWith(QLatin1String("//"))) { // magic for shared drive on windows int indexOfPath = deslashified.indexOf(QLatin1Char('/'), 2); - url.setHost(deslashified.mid(2, indexOfPath - 2)); + QString hostSpec = deslashified.mid(2, indexOfPath - 2); + // Check for Windows-specific WebDAV specification: "//host@SSL/path". + if (hostSpec.endsWith(webDavSslTag(), Qt::CaseInsensitive)) { + hostSpec.chop(4); + scheme = webDavScheme(); + } + url.setHost(hostSpec); + if (indexOfPath > 2) deslashified = deslashified.right(deslashified.length() - indexOfPath); else deslashified.clear(); } + url.setScheme(scheme); url.setPath(deslashified, DecodedMode); return url; } @@ -3783,8 +3807,14 @@ QString QUrl::toLocalFile() const // magic for shared drive on windows if (!d->host.isEmpty()) { - tmp = QStringLiteral("//") + host() + (ourPath.length() > 0 && ourPath.at(0) != QLatin1Char('/') - ? QLatin1Char('/') + ourPath : ourPath); + tmp = QStringLiteral("//") + host(); +#ifdef Q_OS_WIN // QTBUG-42346, WebDAV is visible as local file on Windows only. + if (scheme() == webDavScheme()) + tmp += webDavSslTag(); +#endif + if (!ourPath.isEmpty() && !ourPath.startsWith(QLatin1Char('/'))) + tmp += QLatin1Char('/'); + tmp += ourPath; } else { tmp = ourPath; #ifdef Q_OS_WIN diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp index a95c7dc8b3..3c383532bb 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp +++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp @@ -1196,11 +1196,7 @@ void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &sourc parents << q->mapFromSource(source_parent); emit q->layoutAboutToBeChanged(parents, QAbstractItemModel::VerticalSortHint); QModelIndexPairList source_indexes = store_persistent_indexes(); - remove_source_items(m->proxy_rows, m->source_rows, source_rows_resort, - source_parent, Qt::Vertical, false); - sort_source_rows(source_rows_resort, source_parent); - insert_source_items(m->proxy_rows, m->source_rows, source_rows_resort, - source_parent, Qt::Vertical, false); + sort_source_rows(m->source_rows, source_parent); update_persistent_indexes(source_indexes); emit q->layoutChanged(parents, QAbstractItemModel::VerticalSortHint); // Make sure we also emit dataChanged for the rows diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 45647f2056..77900ba906 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -714,9 +714,7 @@ void QCoreApplication::init() Q_ASSERT_X(!self, "QCoreApplication", "there should be only one application object"); QCoreApplication::self = this; -#ifndef QT_BOOTSTRAPPED QLoggingRegistry::instance()->init(); -#endif #ifndef QT_NO_QOBJECT // use the event dispatcher created by the app programmer (if any) diff --git a/src/corelib/tools/qbytearraylist.h b/src/corelib/tools/qbytearraylist.h index 9d7e776028..dd84ec642c 100644 --- a/src/corelib/tools/qbytearraylist.h +++ b/src/corelib/tools/qbytearraylist.h @@ -63,6 +63,7 @@ class QByteArrayList : public QList<QByteArray> template <> struct QListSpecialMethods<QByteArray> #endif { +public: inline QByteArray join() const { return QtPrivate::QByteArrayList_join(self(), 0, 0); } inline QByteArray join(const QByteArray &sep) const diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index a253057435..a923be50c0 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -3144,7 +3144,7 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, } bool QLocaleData::validateChars(const QString &str, NumberMode numMode, QByteArray *buff, - int decDigits) const + int decDigits, bool rejectGroupSeparators) const { buff->clear(); buff->reserve(str.length()); @@ -3205,7 +3205,7 @@ bool QLocaleData::validateChars(const QString &str, NumberMode numMode, QByteArr case ',': //it can only be placed after a digit which is before the decimal point - if (!lastWasDigit || decPointCnt > 0) + if (rejectGroupSeparators || !lastWasDigit || decPointCnt > 0) return false; break; diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h index c33ced35d5..c5e62027c4 100644 --- a/src/corelib/tools/qlocale_p.h +++ b/src/corelib/tools/qlocale_p.h @@ -251,7 +251,9 @@ public: inline char digitToCLocale(QChar c) const; // this function is used in QIntValidator (QtGui) - Q_CORE_EXPORT bool validateChars(const QString &str, NumberMode numMode, QByteArray *buff, int decDigits = -1) const; + Q_CORE_EXPORT bool validateChars(const QString &str, NumberMode numMode, + QByteArray *buff, int decDigits = -1, + bool rejectGroupSeparators = false) const; public: quint16 m_language_id, m_script_id, m_country_id; diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index ef12c1b8e3..29b546770c 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -3863,28 +3863,31 @@ QString QString::section(const QString &sep, int start, int end, SectionFlags fl { QStringList sections = split(sep, KeepEmptyParts, (flags & SectionCaseInsensitiveSeps) ? Qt::CaseInsensitive : Qt::CaseSensitive); - if (sections.isEmpty()) - return QString(); + const int sectionsSize = sections.size(); + if (!(flags & SectionSkipEmpty)) { if (start < 0) - start += sections.count(); + start += sectionsSize; if (end < 0) - end += sections.count(); + end += sectionsSize; } else { int skip = 0; - for (int k=0; k<sections.size(); ++k) { + for (int k = 0; k < sectionsSize; ++k) { if (sections.at(k).isEmpty()) skip++; } if (start < 0) - start += sections.count() - skip; + start += sectionsSize - skip; if (end < 0) - end += sections.count() - skip; + end += sectionsSize - skip; } + if (start >= sectionsSize || end < 0 || start > end) + return QString(); + int x = 0; QString ret; int first_i = start, last_i = end; - for (int i = 0; x <= end && i < sections.size(); ++i) { + for (int i = 0; x <= end && i < sectionsSize; ++i) { QString section = sections.at(i); const bool empty = section.isEmpty(); if (x >= start) { @@ -3892,16 +3895,16 @@ QString QString::section(const QString &sep, int start, int end, SectionFlags fl first_i = i; if(x == end) last_i = i; - if(x > start) + if (x > start && i > 0) ret += sep; ret += section; } if (!empty || !(flags & SectionSkipEmpty)) x++; } - if((flags & SectionIncludeLeadingSep) && first_i) + if ((flags & SectionIncludeLeadingSep) && first_i > 0) ret.prepend(sep); - if((flags & SectionIncludeTrailingSep) && last_i < sections.size()-1) + if ((flags & SectionIncludeTrailingSep) && last_i < sectionsSize - 1) ret += sep; return ret; } @@ -3919,15 +3922,32 @@ static QString extractSections(const QList<qt_section_chunk> §ions, int end, QString::SectionFlags flags) { - if (start < 0) - start += sections.count(); - if (end < 0) - end += sections.count(); + const int sectionsSize = sections.size(); + + if (!(flags & QString::SectionSkipEmpty)) { + if (start < 0) + start += sectionsSize; + if (end < 0) + end += sectionsSize; + } else { + int skip = 0; + for (int k = 0; k < sectionsSize; ++k) { + const qt_section_chunk §ion = sections.at(k); + if (section.length == section.string.length()) + skip++; + } + if (start < 0) + start += sectionsSize - skip; + if (end < 0) + end += sectionsSize - skip; + } + if (start >= sectionsSize || end < 0 || start > end) + return QString(); QString ret; int x = 0; int first_i = start, last_i = end; - for (int i = 0; x <= end && i < sections.size(); ++i) { + for (int i = 0; x <= end && i < sectionsSize; ++i) { const qt_section_chunk §ion = sections.at(i); const bool empty = (section.length == section.string.length()); if (x >= start) { @@ -3944,12 +3964,13 @@ static QString extractSections(const QList<qt_section_chunk> §ions, x++; } - if ((flags & QString::SectionIncludeLeadingSep) && first_i < sections.size()) { + if ((flags & QString::SectionIncludeLeadingSep) && first_i >= 0) { const qt_section_chunk §ion = sections.at(first_i); ret.prepend(section.string.left(section.length)); } - if ((flags & QString::SectionIncludeTrailingSep) && last_i+1 <= sections.size()-1) { + if ((flags & QString::SectionIncludeTrailingSep) + && last_i < sectionsSize - 1) { const qt_section_chunk §ion = sections.at(last_i+1); ret += section.string.left(section.length); } diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 59bcd37251..fe92ead846 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -163,7 +163,6 @@ QWindow *QGuiApplicationPrivate::focus_window = 0; static QBasicMutex applicationFontMutex; QFont *QGuiApplicationPrivate::app_font = 0; bool QGuiApplicationPrivate::obey_desktop_settings = true; -bool QGuiApplicationPrivate::noGrab = false; static qreal fontSmoothingGamma = 1.7; @@ -1196,20 +1195,10 @@ void QGuiApplicationPrivate::eventDispatcherReady() platform_integration->initialize(); } -#if defined(QT_DEBUG) && defined(Q_OS_LINUX) -// Find out if our parent process is gdb by looking at the 'exe' symlink under /proc. -static bool runningUnderDebugger() -{ - const QFileInfo parentProcExe(QStringLiteral("/proc/") + QString::number(getppid()) + QStringLiteral("/exe")); - return parentProcExe.isSymLink() && parentProcExe.symLinkTarget().endsWith(QLatin1String("/gdb")); -} -#endif - void QGuiApplicationPrivate::init() { QCoreApplicationPrivate::is_app_running = false; // Starting up. - bool doGrabUnderDebugger = false; bool loadTestability = false; QList<QByteArray> pluginList; // Get command line params @@ -1244,10 +1233,6 @@ void QGuiApplicationPrivate::init() QDir::setCurrent(qbundlePath.section(QLatin1Char('/'), 0, -2)); } #endif - } else if (arg == "-nograb") { - QGuiApplicationPrivate::noGrab = true; - } else if (arg == "-dograb") { - doGrabUnderDebugger = true; #ifndef QT_NO_SESSIONMANAGER } else if (arg == "-session" && i < argc-1) { ++i; @@ -1273,16 +1258,6 @@ void QGuiApplicationPrivate::init() argc = j; } -#if defined(QT_DEBUG) && defined(Q_OS_LINUX) - if (!doGrabUnderDebugger && !QGuiApplicationPrivate::noGrab && runningUnderDebugger()) { - QGuiApplicationPrivate::noGrab = true; - qDebug("Qt: gdb: -nograb added to command-line options.\n" - "\t Use the -dograb option to enforce grabbing."); - } -#else - Q_UNUSED(doGrabUnderDebugger) -#endif - // Load environment exported generic plugins foreach (const QByteArray &plugin, qgetenv("QT_QPA_GENERIC_PLUGINS").split(',')) pluginList << plugin; diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index 8988bd461d..eed3d5c10e 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -221,7 +221,6 @@ public: QStyleHints *styleHints; static bool obey_desktop_settings; - static bool noGrab; QInputMethod *inputMethod; QString firstWindowTitle; diff --git a/src/gui/kernel/qopenglcontext_p.h b/src/gui/kernel/qopenglcontext_p.h index d5a3126176..975553e7cd 100644 --- a/src/gui/kernel/qopenglcontext_p.h +++ b/src/gui/kernel/qopenglcontext_p.h @@ -203,6 +203,7 @@ public: , workaround_brokenTexSubImage(false) , workaround_missingPrecisionQualifiers(false) , active_engine(0) + , qgl_current_fbo_invalid(false) { requestedFormat = QSurfaceFormat::defaultFormat(); } @@ -237,6 +238,8 @@ public: QPaintEngineEx *active_engine; + bool qgl_current_fbo_invalid; + QVariant nativeHandle; static QOpenGLContext *setCurrentContext(QOpenGLContext *context); diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 99bf469f87..c6dd0955aa 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -1639,8 +1639,6 @@ QPlatformSurface *QWindow::surfaceHandle() const bool QWindow::setKeyboardGrabEnabled(bool grab) { Q_D(QWindow); - if (grab && QGuiApplicationPrivate::noGrab) - return false; if (d->platformWindow) return d->platformWindow->setKeyboardGrabEnabled(grab); return false; @@ -1658,8 +1656,6 @@ bool QWindow::setKeyboardGrabEnabled(bool grab) bool QWindow::setMouseGrabEnabled(bool grab) { Q_D(QWindow); - if (grab && QGuiApplicationPrivate::noGrab) - return false; if (d->platformWindow) return d->platformWindow->setMouseGrabEnabled(grab); return false; diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp index b185e332e6..124d9d53f6 100644 --- a/src/gui/opengl/qopenglframebufferobject.cpp +++ b/src/gui/opengl/qopenglframebufferobject.cpp @@ -469,6 +469,8 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi funcs.glGenFramebuffers(1, &fbo); funcs.glBindFramebuffer(GL_FRAMEBUFFER, fbo); + QOpenGLContextPrivate::get(ctx)->qgl_current_fbo_invalid = true; + GLuint color_buffer = 0; QT_CHECK_GLERROR(); @@ -997,7 +999,11 @@ bool QOpenGLFramebufferObject::bind() if (current->shareGroup() != d->fbo_guard->group()) qWarning("QOpenGLFramebufferObject::bind() called from incompatible context"); #endif + d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo()); + + QOpenGLContextPrivate::get(current)->qgl_current_fbo_invalid = true; + if (d->texture_guard || d->format.samples() != 0) d->valid = d->checkFramebufferStatus(current); else @@ -1029,9 +1035,12 @@ bool QOpenGLFramebufferObject::release() qWarning("QOpenGLFramebufferObject::release() called from incompatible context"); #endif - if (current) + if (current) { d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, current->defaultFramebufferObject()); + QOpenGLContextPrivate::get(current)->qgl_current_fbo_invalid = true; + } + return true; } @@ -1194,9 +1203,23 @@ Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, If used together with QOpenGLPaintDevice, \a flipped should be the opposite of the value of QOpenGLPaintDevice::paintFlipped(). - Will try to return a premultiplied ARBG32 or RGB32 image. Since 5.2 it will fall back to - a premultiplied RGBA8888 or RGBx8888 image when reading to ARGB32 is not supported. Since 5.4 an - A2BGR30 image is returned if the internal format is RGB10_A2. + The returned image has a format of premultiplied ARGB32 or RGB32. The latter is used + only when internalTextureFormat() is set to \c GL_RGB. + + If the rendering in the framebuffer was not done with premultiplied alpha in mind, + create a wrapper QImage with a non-premultiplied format. This is necessary before + performing operations like QImage::save() because otherwise the image data would get + unpremultiplied, even though it was not premultiplied in the first place. To create + such a wrapper without performing a copy of the pixel data, do the following: + + \code + QImage fboImage(fbo.toImage()); + QImage image(fboImage.constBits(), fboImage.width(), fboImage.height(), QImage::Format_ARGB32); + \endcode + + Since Qt 5.2 the function will fall back to premultiplied RGBA8888 or RGBx8888 when + reading to (A)RGB32 is not supported. Since 5.4 an A2BGR30 image is returned if the + internal format is RGB10_A2. For multisampled framebuffer objects the samples are resolved using the \c{GL_EXT_framebuffer_blit} extension. If the extension is not available, the contents @@ -1272,8 +1295,10 @@ bool QOpenGLFramebufferObject::bindDefault() { QOpenGLContext *ctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext()); - if (ctx) + if (ctx) { ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject()); + QOpenGLContextPrivate::get(ctx)->qgl_current_fbo_invalid = true; + } #ifdef QT_DEBUG else qWarning("QOpenGLFramebufferObject::bindDefault() called without current context."); @@ -1342,6 +1367,7 @@ void QOpenGLFramebufferObject::setAttachment(QOpenGLFramebufferObject::Attachmen qWarning("QOpenGLFramebufferObject::setAttachment() called from incompatible context"); #endif d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo()); + QOpenGLContextPrivate::get(current)->qgl_current_fbo_invalid = true; d->initAttachments(current, attachment); } diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp index d120175108..d136f3a903 100644 --- a/src/gui/painting/qbrush.cpp +++ b/src/gui/painting/qbrush.cpp @@ -708,6 +708,9 @@ void QBrush::setStyle(Qt::BrushStyle style) void QBrush::setColor(const QColor &c) { + if (d->color == c) + return; + detach(d->style); d->color = c; } diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index f2d27a0e2a..6482cc50f7 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -6829,7 +6829,7 @@ void qInitDrawhelperAsm() qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon; #endif -#ifdef Q_PROCESSOR_MIPS_32 +#if defined(Q_PROCESSOR_MIPS_32) && defined(QT_COMPILER_SUPPORTS_MIPS_DSP) qt_memfill32 = qt_memfill32_asm_mips_dsp; #endif // Q_PROCESSOR_MIPS_32 diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index b0cfa49b36..83d9edab94 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -1459,10 +1459,7 @@ void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_me bool QFontEngineFT::supportsTransformation(const QTransform &transform) const { - // The freetype engine falls back to QFontEngine for tranformed glyphs, - // which uses fast-tranform and produces very ugly results, so we claim - // to support just translations. - return transform.type() <= QTransform::TxTranslate; + return transform.type() <= QTransform::TxRotate; } void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) @@ -1943,17 +1940,75 @@ void QFontEngineFT::unlockAlphaMapForGlyph() currentlyLockedAlphaMap = QImage(); } -QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format) +QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, + QFixed subPixelPosition, + GlyphFormat format, + const QTransform &t) { - return defaultGlyphSet.outline_drawing ? 0 : - loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, g, subPixelPosition, format); + FT_Face face = 0; + QGlyphSet *glyphSet = 0; + FT_Matrix ftMatrix = QTransformToFTMatrix(t); + if (cacheEnabled) { + if (t.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) { + for (int i = 0; i < transformedGlyphSets.count(); ++i) { + const QGlyphSet &g = transformedGlyphSets.at(i); + if (g.transformationMatrix.xx == ftMatrix.xx + && g.transformationMatrix.xy == ftMatrix.xy + && g.transformationMatrix.yx == ftMatrix.yx + && g.transformationMatrix.yy == ftMatrix.yy) { + + // found a match, move it to the front + transformedGlyphSets.move(i, 0); + glyphSet = &transformedGlyphSets[0]; + break; + } + } + + if (!glyphSet) { + // don't cache more than 10 transformations + if (transformedGlyphSets.count() >= 10) { + transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0); + } else { + transformedGlyphSets.prepend(QGlyphSet()); + } + glyphSet = &transformedGlyphSets[0]; + glyphSet->clear(); + glyphSet->transformationMatrix = ftMatrix; + } + } else { + glyphSet = &defaultGlyphSet; + } + Q_ASSERT(glyphSet != 0); + } + + if (glyphSet != 0 && glyphSet->outline_drawing) + return 0; + + Glyph *glyph = glyphSet != 0 ? glyphSet->getGlyph(g, subPixelPosition) : 0; + if (!glyph || glyph->format != format) { + face = lockFace(); + FT_Matrix m = this->matrix; + FT_Matrix_Multiply(&ftMatrix, &m); + freetype->matrix = m; + glyph = loadGlyph(glyphSet, g, subPixelPosition, format, false); + } + + if (face) + unlockFace(); + + return glyph; } QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition) { + return alphaMapForGlyph(g, subPixelPosition, QTransform()); +} + +QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t) +{ lockFace(); - QScopedPointer<Glyph> glyph(loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono)); + QScopedPointer<Glyph> glyph(loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono, t)); if (!glyph || !glyph->data) { unlockFace(); return QFontEngine::alphaMapForGlyph(g); @@ -1987,12 +2042,12 @@ QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition) QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t) { - if (t.type() > QTransform::TxTranslate) + if (t.type() > QTransform::TxRotate) return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t); lockFace(); - QScopedPointer<Glyph> glyph(loadGlyphFor(g, subPixelPosition, Format_A32)); + QScopedPointer<Glyph> glyph(loadGlyphFor(g, subPixelPosition, Format_A32, t)); if (!glyph || !glyph->data) { unlockFace(); return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t); diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h index a73c281f1d..1894d25d70 100644 --- a/src/gui/text/qfontengine_ft_p.h +++ b/src/gui/text/qfontengine_ft_p.h @@ -233,6 +233,7 @@ private: virtual void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags flags) const; virtual QImage alphaMapForGlyph(glyph_t g) { return alphaMapForGlyph(g, 0); } virtual QImage alphaMapForGlyph(glyph_t, QFixed); + QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t); virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t); virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, @@ -265,7 +266,7 @@ private: inline Glyph *loadGlyph(uint glyph, QFixed subPixelPosition, GlyphFormat format = Format_None, bool fetchMetricsOnly = false) const { return loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, subPixelPosition, format, fetchMetricsOnly); } Glyph *loadGlyph(QGlyphSet *set, uint glyph, QFixed subPixelPosition, GlyphFormat = Format_None, bool fetchMetricsOnly = false) const; - Glyph *loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format); + Glyph *loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format, const QTransform &t); QGlyphSet *loadTransformedGlyphSet(const QTransform &matrix); bool loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs, diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp index 1b5a10f733..f879847935 100644 --- a/src/gui/util/qvalidator.cpp +++ b/src/gui/util/qvalidator.cpp @@ -316,7 +316,12 @@ void QValidator::fixup(QString &) const QIntValidator uses its locale() to interpret the number. For example, in Arabic locales, QIntValidator will accept Arabic digits. - \sa QDoubleValidator, QRegExpValidator, {Line Edits Example} + \note The QLocale::NumberOptions set on the locale() also affect the + way the number is interpreted. For example, since QLocale::RejectGroupSeparator + is not set by default, the validator will accept group separators. It is thus + recommended to use QLocale::toInt() to obtain the numeric value. + + \sa QDoubleValidator, QRegExpValidator, QLocale::toInt(), {Line Edits Example} */ /*! @@ -393,7 +398,8 @@ static qlonglong pow10(int exp) QValidator::State QIntValidator::validate(QString & input, int&) const { QByteArray buff; - if (!locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, &buff)) { + if (!locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, &buff, + -1, locale().numberOptions() & QLocale::RejectGroupSeparator)) { return Invalid; } @@ -432,7 +438,8 @@ QValidator::State QIntValidator::validate(QString & input, int&) const void QIntValidator::fixup(QString &input) const { QByteArray buff; - if (!locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, &buff)) { + if (!locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, &buff, + -1, locale().numberOptions() & QLocale::RejectGroupSeparator)) { return; } bool ok, overflow; @@ -548,7 +555,12 @@ public: in the German locale, "1,234" will be accepted as the fractional number 1.234. In Arabic locales, QDoubleValidator will accept Arabic digits. - \sa QIntValidator, QRegExpValidator, {Line Edits Example} + \note The QLocale::NumberOptions set on the locale() also affect the + way the number is interpreted. For example, since QLocale::RejectGroupSeparator + is not set by default, the validator will accept group separators. It is thus + recommended to use QLocale::toDouble() to obtain the numeric value. + + \sa QIntValidator, QRegExpValidator, QLocale::toDouble(), {Line Edits Example} */ /*! @@ -648,8 +660,10 @@ QValidator::State QDoubleValidatorPrivate::validateWithLocale(QString &input, QL { Q_Q(const QDoubleValidator); QByteArray buff; - if (!locale.d->m_data->validateChars(input, numMode, &buff, q->dec)) + if (!locale.d->m_data->validateChars(input, numMode, &buff, q->dec, + locale.numberOptions() & QLocale::RejectGroupSeparator)) { return QValidator::Invalid; + } if (buff.isEmpty()) return QValidator::Intermediate; @@ -1003,7 +1017,7 @@ QValidator::State QRegularExpressionValidator::validate(QString &input, int &pos const QRegularExpressionMatch m = d->usedRe.match(input, 0, QRegularExpression::PartialPreferCompleteMatch); if (m.hasMatch()) { return Acceptable; - } else if (m.hasPartialMatch()) { + } else if (input.isEmpty() || m.hasPartialMatch()) { return Intermediate; } else { pos = input.size(); diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index f50a79b061..66f093e490 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -151,7 +151,7 @@ QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request } if (request.d->operation == QHttpNetworkRequest::Post) { // add content type, if not set in the request - if (request.headerField("content-type").isEmpty()) { + if (request.headerField("content-type").isEmpty() && ((request.d->uploadByteDevice && request.d->uploadByteDevice->size() > 0) || request.d->url.hasQuery())) { //Content-Type is mandatory. We can't say anything about the encoding, but x-www-form-urlencoded is the most likely to work. //This warning indicates a bug in application code not setting a required header. //Note that if using QHttpMultipart, the content-type is set in QNetworkAccessManagerPrivate::prepareMultipart already diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp index f4562cdb21..71b8237e03 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols.cpp +++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp @@ -63,6 +63,9 @@ #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) #include <link.h> #endif +#ifdef Q_OS_DARWIN +#include "private/qcore_mac_p.h" +#endif #include <algorithm> @@ -452,6 +455,15 @@ static QStringList libraryPathList() # ifdef Q_OS_DARWIN paths = QString::fromLatin1(qgetenv("DYLD_LIBRARY_PATH")) .split(QLatin1Char(':'), QString::SkipEmptyParts); + + // search in .app/Contents/Frameworks + UInt32 packageType; + CFBundleGetPackageInfo(CFBundleGetMainBundle(), &packageType, NULL); + if (packageType == FOUR_CHAR_CODE('APPL')) { + QUrl bundleUrl = QUrl::fromCFURL(QCFType<CFURLRef>(CFBundleCopyBundleURL(CFBundleGetMainBundle()))); + QUrl frameworksUrl = QUrl::fromCFURL(QCFType<CFURLRef>(CFBundleCopyPrivateFrameworksURL(CFBundleGetMainBundle()))); + paths << bundleUrl.resolved(frameworksUrl).path(); + } # else paths = QString::fromLatin1(qgetenv("LD_LIBRARY_PATH")) .split(QLatin1Char(':'), QString::SkipEmptyParts); @@ -601,7 +613,13 @@ static QPair<QLibrary*, QLibrary*> loadOpenSsl() } #endif +#ifndef Q_OS_DARWIN // second attempt: find the development files libssl.so and libcrypto.so + // + // disabled on OS X/iOS: + // OS X's /usr/lib/libssl.dylib, /usr/lib/libcrypto.dylib will be picked up in the third + // attempt, _after_ <bundle>/Contents/Frameworks has been searched. + // iOS does not ship a system libssl.dylib, libcrypto.dylib in the first place. libssl->setFileNameAndVersion(QLatin1String("ssl"), -1); libcrypto->setFileNameAndVersion(QLatin1String("crypto"), -1); if (libcrypto->load() && libssl->load()) { @@ -611,6 +629,7 @@ static QPair<QLibrary*, QLibrary*> loadOpenSsl() libssl->unload(); libcrypto->unload(); } +#endif // third attempt: loop on the most common library paths and find libssl QStringList sslList = findAllLibSsl(); diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 43df311636..1fa5723d85 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -612,6 +612,21 @@ void QGL2PaintEngineExPrivate::resetGLState() #endif } +bool QGL2PaintEngineExPrivate::resetOpenGLContextActiveEngine() +{ + QOpenGLContext *guiGlContext = ctx->contextHandle(); + QOpenGLContextPrivate *guiGlContextPrivate = + guiGlContext ? QOpenGLContextPrivate::get(guiGlContext) : 0; + + if (guiGlContextPrivate && guiGlContextPrivate->active_engine) { + ctx->d_func()->refreshCurrentFbo(); + guiGlContextPrivate->active_engine = 0; + return true; + } + + return false; +} + void QGL2PaintEngineEx::endNativePainting() { Q_D(QGL2PaintEngineEx); @@ -2015,6 +2030,8 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->ctx = d->device->context(); d->ctx->d_ptr->active_engine = this; + d->resetOpenGLContextActiveEngine(); + const QSize sz = d->device->size(); d->width = sz.width(); d->height = sz.height(); @@ -2080,6 +2097,8 @@ bool QGL2PaintEngineEx::end() ctx->d_ptr->active_engine = 0; + d->resetOpenGLContextActiveEngine(); + d->resetGLState(); delete d->shaderManager; @@ -2105,7 +2124,7 @@ void QGL2PaintEngineEx::ensureActive() Q_D(QGL2PaintEngineEx); QGLContext *ctx = d->ctx; - if (isActive() && ctx->d_ptr->active_engine != this) { + if (isActive() && (ctx->d_ptr->active_engine != this || d->resetOpenGLContextActiveEngine())) { ctx->d_ptr->active_engine = this; d->needsSync = true; } diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 528bfdeeb9..ac1d63df17 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -191,6 +191,7 @@ public: void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id = GLuint(-1)); void resetGLState(); + bool resetOpenGLContextActiveEngine(); // fill, stroke, drawTexture, drawPixmaps & drawCachedGlyphs are the main rendering entry-points, // however writeClip can also be thought of as en entry point as it does similar things. diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp index 211fad267f..8cd26f1ea4 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp @@ -167,6 +167,8 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height) // ### the QTextureGlyphCache API needs to be reworked to allow // ### resizeTextureData to fail + ctx->d_ptr->refreshCurrentFbo(); + funcs->glBindFramebuffer(GL_FRAMEBUFFER, m_textureResource->m_fbo); GLuint tmp_texture; diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 1e49d95087..35f08e0092 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -510,6 +510,35 @@ void QGLContextPrivate::setupSharing() { } } +void QGLContextPrivate::refreshCurrentFbo() +{ + QOpenGLContextPrivate *guiGlContextPrivate = + guiGlContext ? QOpenGLContextPrivate::get(guiGlContext) : 0; + + // if QOpenGLFramebufferObjects have been used in the mean-time, we've lost our cached value + if (guiGlContextPrivate && guiGlContextPrivate->qgl_current_fbo_invalid) { + GLint current; + QOpenGLFunctions *funcs = qgl_functions(); + funcs->glGetIntegerv(GL_FRAMEBUFFER_BINDING, ¤t); + + current_fbo = current; + + guiGlContextPrivate->qgl_current_fbo_invalid = false; + } +} + +void QGLContextPrivate::setCurrentFbo(GLuint fbo) +{ + current_fbo = fbo; + + QOpenGLContextPrivate *guiGlContextPrivate = + guiGlContext ? QOpenGLContextPrivate::get(guiGlContext) : 0; + + if (guiGlContextPrivate) + guiGlContextPrivate->qgl_current_fbo_invalid = false; +} + + /*! \fn bool QGLFormat::doubleBuffer() const diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index c4151a3d34..4cf656fd86 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -238,6 +238,8 @@ public: bool ownContext; void setupSharing(); + void refreshCurrentFbo(); + void setCurrentFbo(GLuint fbo); QGLFormat glFormat; QGLFormat reqFormat; diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index 4ef50e9334..4537f5bfae 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -472,6 +472,8 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, if (!funcs.hasOpenGLFeature(QOpenGLFunctions::Framebuffers)) return; + ctx->d_ptr->refreshCurrentFbo(); + size = sz; target = texture_target; // texture dimensions @@ -1027,7 +1029,7 @@ bool QGLFramebufferObject::bind() d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo()); d->valid = d->checkFramebufferStatus(); if (d->valid && current) - current->d_ptr->current_fbo = d->fbo(); + current->d_ptr->setCurrentFbo(d->fbo()); return d->valid; } @@ -1060,7 +1062,7 @@ bool QGLFramebufferObject::release() #endif if (current) { - current->d_ptr->current_fbo = current->d_ptr->default_fbo; + current->d_ptr->setCurrentFbo(current->d_ptr->default_fbo); d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, current->d_ptr->default_fbo); } @@ -1109,6 +1111,20 @@ QGLFramebufferObjectFormat QGLFramebufferObject::format() const Returns the contents of this framebuffer object as a QImage. + The returned image has a format of premultiplied ARGB32 or RGB32. The latter is used + only when internalTextureFormat() is set to \c GL_RGB. + + If the rendering in the framebuffer was not done with premultiplied alpha in mind, + create a wrapper QImage with a non-premultiplied format. This is necessary before + performing operations like QImage::save() because otherwise the image data would get + unpremultiplied, even though it was not premultiplied in the first place. To create + such a wrapper without performing a copy of the pixel data, do the following: + + \code + QImage fboImage(fbo.toImage()); + QImage image(fboImage.constBits(), fboImage.width(), fboImage.height(), QImage::Format_ARGB32); + \endcode + On QNX the back buffer is not preserved when a buffer swap occures. So this function might return old content. */ @@ -1173,7 +1189,7 @@ bool QGLFramebufferObject::bindDefault() if (!functions.hasOpenGLFeature(QOpenGLFunctions::Framebuffers)) return false; - ctx->d_ptr->current_fbo = ctx->d_ptr->default_fbo; + ctx->d_ptr->setCurrentFbo(ctx->d_ptr->default_fbo); functions.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_ptr->default_fbo); #ifdef QT_DEBUG } else { @@ -1320,7 +1336,12 @@ bool QGLFramebufferObject::isBound() const { Q_D(const QGLFramebufferObject); const QGLContext *current = QGLContext::currentContext(); - return current ? current->d_ptr->current_fbo == d->fbo() : false; + if (current) { + current->d_ptr->refreshCurrentFbo(); + return current->d_ptr->current_fbo == d->fbo(); + } + + return false; } /*! @@ -1400,6 +1421,8 @@ void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const Q const int ty0 = th - (targetRect.top() + targetRect.height()); const int ty1 = th - targetRect.top(); + ctx->d_ptr->refreshCurrentFbo(); + functions.glBindFramebuffer(GL_READ_FRAMEBUFFER, source ? source->handle() : 0); functions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target ? target->handle() : 0); diff --git a/src/opengl/qglpaintdevice.cpp b/src/opengl/qglpaintdevice.cpp index 40cc7bb71d..c07d0a761b 100644 --- a/src/opengl/qglpaintdevice.cpp +++ b/src/opengl/qglpaintdevice.cpp @@ -74,6 +74,8 @@ void QGLPaintDevice::beginPaint() QGLContext *ctx = context(); ctx->makeCurrent(); + ctx->d_func()->refreshCurrentFbo(); + // Record the currently bound FBO so we can restore it again // in endPaint() and bind this device's FBO // @@ -85,7 +87,7 @@ void QGLPaintDevice::beginPaint() m_previousFBO = ctx->d_func()->current_fbo; if (m_previousFBO != m_thisFBO) { - ctx->d_ptr->current_fbo = m_thisFBO; + ctx->d_func()->setCurrentFbo(m_thisFBO); ctx->contextHandle()->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_thisFBO); } @@ -102,8 +104,10 @@ void QGLPaintDevice::ensureActiveTarget() if (ctx != QGLContext::currentContext()) ctx->makeCurrent(); + ctx->d_func()->refreshCurrentFbo(); + if (ctx->d_ptr->current_fbo != m_thisFBO) { - ctx->d_ptr->current_fbo = m_thisFBO; + ctx->d_func()->setCurrentFbo(m_thisFBO); ctx->contextHandle()->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_thisFBO); } @@ -114,8 +118,11 @@ void QGLPaintDevice::endPaint() { // Make sure the FBO bound at beginPaint is re-bound again here: QGLContext *ctx = context(); + + ctx->d_func()->refreshCurrentFbo(); + if (m_previousFBO != ctx->d_func()->current_fbo) { - ctx->d_ptr->current_fbo = m_previousFBO; + ctx->d_func()->setCurrentFbo(m_previousFBO); ctx->contextHandle()->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_previousFBO); } diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp index 56bfaebe4f..63b624aea2 100644 --- a/src/opengl/qglpixelbuffer.cpp +++ b/src/opengl/qglpixelbuffer.cpp @@ -344,6 +344,8 @@ void QGLPixelBuffer::updateDynamicTexture(GLuint texture_id) const QOpenGLExtensions extensions(ctx->contextHandle()); + ctx->d_ptr->refreshCurrentFbo(); + if (d->blit_fbo) { QOpenGLFramebufferObject::blitFramebuffer(d->blit_fbo, d->fbo); extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, d->blit_fbo->handle()); diff --git a/src/platformsupport/fontdatabases/basic/basic.pri b/src/platformsupport/fontdatabases/basic/basic.pri index 88be809cd8..c2b882ed5a 100644 --- a/src/platformsupport/fontdatabases/basic/basic.pri +++ b/src/platformsupport/fontdatabases/basic/basic.pri @@ -17,6 +17,7 @@ contains(QT_CONFIG, freetype) { $$QT_FREETYPE_DIR/src/base/ftbbox.c \ $$QT_FREETYPE_DIR/src/base/ftdebug.c \ $$QT_FREETYPE_DIR/src/base/ftglyph.c \ + $$QT_FREETYPE_DIR/src/base/ftlcdfil.c \ $$QT_FREETYPE_DIR/src/base/ftinit.c \ $$QT_FREETYPE_DIR/src/base/ftmm.c \ $$QT_FREETYPE_DIR/src/base/fttype1.c \ diff --git a/src/plugins/bearer/linux_common/qofonoservice_linux.cpp b/src/plugins/bearer/linux_common/qofonoservice_linux.cpp index b2e2131a92..abbfd445a5 100644 --- a/src/plugins/bearer/linux_common/qofonoservice_linux.cpp +++ b/src/plugins/bearer/linux_common/qofonoservice_linux.cpp @@ -269,6 +269,18 @@ QStringList QOfonoDataConnectionManagerInterface::contexts() return contextList; } +PathPropertiesList QOfonoDataConnectionManagerInterface::contextsWithProperties() +{ + if (contextListProperties.isEmpty()) { + QDBusPendingReply<PathPropertiesList > reply = call(QLatin1String("GetContexts")); + reply.waitForFinished(); + if (!reply.isError()) { + contextListProperties = reply.value(); + } + } + return contextListProperties; +} + bool QOfonoDataConnectionManagerInterface::roamingAllowed() { QVariant var = getProperty(QStringLiteral("RoamingAllowed")); diff --git a/src/plugins/bearer/linux_common/qofonoservice_linux_p.h b/src/plugins/bearer/linux_common/qofonoservice_linux_p.h index 0ed00d94ff..3b97e06dd3 100644 --- a/src/plugins/bearer/linux_common/qofonoservice_linux_p.h +++ b/src/plugins/bearer/linux_common/qofonoservice_linux_p.h @@ -153,6 +153,7 @@ public: ~QOfonoDataConnectionManagerInterface(); QStringList contexts(); + PathPropertiesList contextsWithProperties(); bool roamingAllowed(); QVariant getProperty(const QString &); QString bearer(); @@ -162,6 +163,7 @@ private: QVariantMap getProperties(); QVariantMap propertiesMap; QStringList contextList; + PathPropertiesList contextListProperties; private slots: void propertyChanged(const QString &, const QDBusVariant &value); }; diff --git a/src/plugins/bearer/networkmanager/main.cpp b/src/plugins/bearer/networkmanager/main.cpp index f416bb42a6..3576ddc37c 100644 --- a/src/plugins/bearer/networkmanager/main.cpp +++ b/src/plugins/bearer/networkmanager/main.cpp @@ -66,10 +66,7 @@ QBearerEngine *QNetworkManagerEnginePlugin::create(const QString &key) const { if (key == QLatin1String("networkmanager")) { QNetworkManagerEngine *engine = new QNetworkManagerEngine; - if (engine->networkManagerAvailable()) - return engine; - else - delete engine; + return engine; } return 0; diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp index a8244f05cf..f0977b4735 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp @@ -56,29 +56,34 @@ QT_BEGIN_NAMESPACE QNetworkManagerEngine::QNetworkManagerEngine(QObject *parent) : QBearerEngineImpl(parent), - managerInterface(new QNetworkManagerInterface(this)), - systemSettings(new QNetworkManagerSettings(NM_DBUS_SERVICE, this)), - ofonoManager(new QOfonoManagerInterface(this)) + managerInterface(NULL), + systemSettings(NULL), + ofonoManager(NULL), + nmAvailable(false) { - - if (!managerInterface->isValid()) - return; - qDBusRegisterMetaType<QNmSettingsMap>(); - connect(managerInterface, SIGNAL(deviceAdded(QDBusObjectPath)), - this, SLOT(deviceAdded(QDBusObjectPath))); - connect(managerInterface, SIGNAL(deviceRemoved(QDBusObjectPath)), - this, SLOT(deviceRemoved(QDBusObjectPath))); - connect(managerInterface, SIGNAL(activationFinished(QDBusPendingCallWatcher*)), - this, SLOT(activationFinished(QDBusPendingCallWatcher*))); - connect(managerInterface, SIGNAL(propertiesChanged(QMap<QString,QVariant>)), - this, SLOT(interfacePropertiesChanged(QMap<QString,QVariant>))); - managerInterface->setConnections(); - - connect(systemSettings, SIGNAL(newConnection(QDBusObjectPath)), - this, SLOT(newConnection(QDBusObjectPath))); - systemSettings->setConnections(); + nmWatcher = new QDBusServiceWatcher(NM_DBUS_SERVICE,QDBusConnection::systemBus(), + QDBusServiceWatcher::WatchForRegistration | + QDBusServiceWatcher::WatchForUnregistration, this); + connect(nmWatcher, SIGNAL(serviceRegistered(QString)), + this, SLOT(nmRegistered(QString))); + connect(nmWatcher, SIGNAL(serviceUnregistered(QString)), + this, SLOT(nmUnRegistered(QString))); + + ofonoWatcher = new QDBusServiceWatcher("org.ofono",QDBusConnection::systemBus(), + QDBusServiceWatcher::WatchForRegistration | + QDBusServiceWatcher::WatchForUnregistration, this); + connect(ofonoWatcher, SIGNAL(serviceRegistered(QString)), + this, SLOT(ofonoRegistered(QString))); + connect(ofonoWatcher, SIGNAL(serviceUnregistered(QString)), + this, SLOT(ofonoUnRegistered(QString))); + + if (QDBusConnection::systemBus().interface()->isServiceRegistered("org.ofono")) + ofonoRegistered(); + + if (QDBusConnection::systemBus().interface()->isServiceRegistered(NM_DBUS_SERVICE)) + nmRegistered(); } QNetworkManagerEngine::~QNetworkManagerEngine() @@ -105,15 +110,13 @@ QNetworkManagerEngine::~QNetworkManagerEngine() void QNetworkManagerEngine::initialize() { - QMutexLocker locker(&mutex); + if (nmAvailable) + setupConfigurations(); +} - if (ofonoManager->isValid()) { - Q_FOREACH (const QString &modem, ofonoManager->getModems()) { - QOfonoDataConnectionManagerInterface *ofonoContextManager - = new QOfonoDataConnectionManagerInterface(modem,this); - ofonoContextManagers.insert(modem, ofonoContextManager); - } - } +void QNetworkManagerEngine::setupConfigurations() +{ + QMutexLocker locker(&mutex); // Get active connections. foreach (const QDBusObjectPath &acPath, managerInterface->activeConnections()) { @@ -151,7 +154,7 @@ void QNetworkManagerEngine::initialize() bool QNetworkManagerEngine::networkManagerAvailable() const { - return managerInterface->isValid(); + return nmAvailable; } QString QNetworkManagerEngine::getInterfaceFromId(const QString &settingsPath) @@ -180,6 +183,9 @@ void QNetworkManagerEngine::connectToId(const QString &id) const QString settingsPath = connection->connectionInterface()->path(); QString specificPath = configuredAccessPoints.key(settingsPath); + if (isConnectionActive(settingsPath)) + return; + QHashIterator<QString, QNetworkManagerInterfaceDevice*> i(interfaceDevices); while (i.hasNext()) { i.next(); @@ -229,7 +235,7 @@ void QNetworkManagerEngine::disconnectFromId(const QString &id) void QNetworkManagerEngine::requestUpdate() { - if (managerInterface->wirelessEnabled()) { + if (managerInterface && managerInterface->wirelessEnabled()) { QHashIterator<QString, QNetworkManagerInterfaceDeviceWireless *> i(wirelessDevices); while (i.hasNext()) { i.next(); @@ -282,8 +288,9 @@ void QNetworkManagerEngine::interfacePropertiesChanged(const QMap<QString, QVari if (ptr) { ptr->mutex.lock(); if (activeConnection->state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED && - ptr->state != QNetworkConfiguration::Active) { - ptr->state = QNetworkConfiguration::Active; + (ptr->state & QNetworkConfiguration::Active) != QNetworkConfiguration::Active) { + + ptr->state |= QNetworkConfiguration::Active; if (activeConnectionsList.value(id) && activeConnectionsList.value(id)->defaultRoute() && managerInterface->state() < QNetworkManagerInterface::NM_STATE_CONNECTED_GLOBAL) { @@ -339,23 +346,25 @@ void QNetworkManagerEngine::activeConnectionPropertiesChanged(const QMap<QString QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); if (ptr) { - ptr->mutex.lock(); - if (properties.value("State").toUInt() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { - QStringList devices = activeConnection->devices(); - if (!devices.isEmpty()) { - QNetworkManagerInterfaceDevice device(devices.at(0),this); - connectionInterfaces.insert(id,device.networkInterface()); - } + if (properties.contains(QStringLiteral("State"))) { + ptr->mutex.lock(); + if (properties.value("State").toUInt() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { + QStringList devices = activeConnection->devices(); + if (!devices.isEmpty()) { + QNetworkManagerInterfaceDevice device(devices.at(0),this); + connectionInterfaces.insert(id,device.networkInterface()); + } - ptr->state |= QNetworkConfiguration::Active; - ptr->mutex.unlock(); + ptr->state |= QNetworkConfiguration::Active; + ptr->mutex.unlock(); - locker.unlock(); - emit configurationChanged(ptr); - locker.relock(); - } else { - connectionInterfaces.remove(id); - ptr->mutex.unlock(); + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } else { + connectionInterfaces.remove(id); + ptr->mutex.unlock(); + } } } } @@ -403,9 +412,6 @@ void QNetworkManagerEngine::deviceAdded(const QDBusObjectPath &path) connect(wirelessDevice,SIGNAL(scanDone()),this,SLOT(scanFinished())); wirelessDevice->setConnections(); - foreach (const QDBusObjectPath &apPath, wirelessDevice->getAccessPoints()) - newAccessPoint(apPath.path()); - wirelessDevices.insert(path.path(), wirelessDevice); } @@ -518,14 +524,9 @@ void QNetworkManagerEngine::newConnection(const QDBusObjectPath &path, parseConnection(settingsPath, connection->getSettings()); // Check if connection is active. - QHashIterator<QString, QNetworkManagerConnectionActive*> i(activeConnectionsList); - while (i.hasNext()) { - i.next(); - if (i.value()->connection().path() == settingsPath) { - cpPriv->state |= QNetworkConfiguration::Active; - break; - } - } + if (isConnectionActive(settingsPath)) + cpPriv->state |= QNetworkConfiguration::Active; + if (deviceType == DEVICE_TYPE_ETHERNET) { QHashIterator<QString, QNetworkManagerInterfaceDevice*> i(interfaceDevices); while (i.hasNext()) { @@ -539,12 +540,36 @@ void QNetworkManagerEngine::newConnection(const QDBusObjectPath &path, } } } + QNetworkConfigurationPrivatePointer ptr(cpPriv); accessPointConfigurations.insert(ptr->id, ptr); locker.unlock(); emit configurationAdded(ptr); } +bool QNetworkManagerEngine::isConnectionActive(const QString &settingsPath) +{ + QHashIterator<QString, QNetworkManagerConnectionActive*> i(activeConnectionsList); + while (i.hasNext()) { + i.next(); + if (i.value()->connection().path() == settingsPath) { + if (i.value()->state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATING + || i.value()->state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { + return true; + } else { + break; + } + } + } + + QNetworkManagerSettingsConnection *settingsConnection = connectionFromId(settingsPath); + if (settingsConnection->getType() == DEVICE_TYPE_MODEM) { + return isActiveContext(settingsConnection->connectionInterface()->path()); + } + + return false; +} + void QNetworkManagerEngine::removeConnection(const QString &path) { QMutexLocker locker(&mutex); @@ -652,7 +677,6 @@ void QNetworkManagerEngine::activationFinished(QDBusPendingCallWatcher *watcher) void QNetworkManagerEngine::newAccessPoint(const QString &path) { QMutexLocker locker(&mutex); - QNetworkManagerInterfaceAccessPoint *accessPoint = new QNetworkManagerInterfaceAccessPoint(path,this); @@ -683,6 +707,9 @@ void QNetworkManagerEngine::newAccessPoint(const QString &path) ptr->mutex.lock(); QNetworkConfiguration::StateFlags flag = QNetworkConfiguration::Defined; ptr->state = (flag | QNetworkConfiguration::Discovered); + + if (isConnectionActive(settingsPath)) + ptr->state = (flag | QNetworkConfiguration::Active); ptr->mutex.unlock(); locker.unlock(); @@ -762,7 +789,6 @@ QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QStri QMutexLocker locker(&mutex); QNetworkConfigurationPrivate *cpPriv = new QNetworkConfigurationPrivate; cpPriv->name = map.value("connection").value("id").toString(); - cpPriv->isValid = true; cpPriv->id = settingsPath; cpPriv->type = QNetworkConfiguration::InternetAccessPoint; @@ -811,18 +837,46 @@ QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QStri } } else if (connectionType == QLatin1String("gsm")) { - const QString contextPath = map.value("connection").value("id").toString(); - cpPriv->name = contextName(contextPath); - cpPriv->bearerType = currentBearerType(contextPath); - - if (map.value("connection").contains("timestamp")) { - cpPriv->state |= QNetworkConfiguration::Discovered; + const QString connectionPath = map.value("connection").value("id").toString(); + cpPriv->name = contextName(connectionPath); + cpPriv->bearerType = currentBearerType(connectionPath); + + if (ofonoManager && ofonoManager->isValid()) { + const QString contextPart = connectionPath.section('/', -1); + QHashIterator<QString, QOfonoDataConnectionManagerInterface*> i(ofonoContextManagers); + while (i.hasNext()) { + i.next(); + const QString path = i.key() +"/"+contextPart; + if (isActiveContext(path)) { + cpPriv->state |= QNetworkConfiguration::Active; + break; + } + } } } return cpPriv; } +bool QNetworkManagerEngine::isActiveContext(const QString &contextPath) +{ + if (ofonoManager && ofonoManager->isValid()) { + const QString contextPart = contextPath.section('/', -1); + QHashIterator<QString, QOfonoDataConnectionManagerInterface*> i(ofonoContextManagers); + while (i.hasNext()) { + i.next(); + PathPropertiesList list = i.value()->contextsWithProperties(); + for (int i = 0; i < list.size(); ++i) { + if (list.at(i).path.path().contains(contextPart)) { + return list.at(i).properties.value(QStringLiteral("Active")).toBool(); + + } + } + } + } + return false; +} + QNetworkManagerSettingsConnection *QNetworkManagerEngine::connectionFromId(const QString &id) const { for (int i = 0; i < connections.count(); ++i) { @@ -967,53 +1021,111 @@ QNetworkConfigurationPrivatePointer QNetworkManagerEngine::defaultConfiguration( QNetworkConfiguration::BearerType QNetworkManagerEngine::currentBearerType(const QString &id) { - if (ofonoManager->isValid()) { - QString contextPart = id.section('/', -1); - - QHashIterator<QString, QOfonoDataConnectionManagerInterface*> i(ofonoContextManagers); - while (i.hasNext()) { - i.next(); - QString contextPath = i.key() +"/"+contextPart; - if (i.value()->contexts().contains(contextPath)) { - - QString bearer = i.value()->bearer(); - if (bearer == QStringLiteral("gsm")) { - return QNetworkConfiguration::Bearer2G; - } else if (bearer == QStringLiteral("edge")) { - return QNetworkConfiguration::Bearer2G; - } else if (bearer == QStringLiteral("umts")) { - return QNetworkConfiguration::BearerWCDMA; - } else if (bearer == QStringLiteral("hspa") - || bearer == QStringLiteral("hsdpa") - || bearer == QStringLiteral("hsupa")) { - return QNetworkConfiguration::BearerHSPA; - } else if (bearer == QStringLiteral("lte")) { - return QNetworkConfiguration::BearerLTE; - } + QString contextPart = id.section('/', -1); + QHashIterator<QString, QOfonoDataConnectionManagerInterface*> i(ofonoContextManagers); + while (i.hasNext()) { + i.next(); + QString contextPath = i.key() +"/"+contextPart; + + if (i.value()->contexts().contains(contextPath)) { + + QString bearer = i.value()->bearer(); + + if (bearer == QStringLiteral("gsm")) { + return QNetworkConfiguration::Bearer2G; + } else if (bearer == QStringLiteral("edge")) { + return QNetworkConfiguration::Bearer2G; + } else if (bearer == QStringLiteral("umts")) { + return QNetworkConfiguration::BearerWCDMA; + } else if (bearer == QStringLiteral("hspa") + || bearer == QStringLiteral("hsdpa") + || bearer == QStringLiteral("hsupa")) { + return QNetworkConfiguration::BearerHSPA; + } else if (bearer == QStringLiteral("lte")) { + return QNetworkConfiguration::BearerLTE; } } } + return QNetworkConfiguration::BearerUnknown; } QString QNetworkManagerEngine::contextName(const QString &path) { - if (ofonoManager->isValid()) { - QString contextPart = path.section('/', -1); - QHashIterator<QString, QOfonoDataConnectionManagerInterface*> i(ofonoContextManagers); - while (i.hasNext()) { - i.next(); - Q_FOREACH (const QString &oContext, i.value()->contexts()) { - if (oContext.contains(contextPart)) { - QOfonoConnectionContextInterface contextInterface(oContext,this); - return contextInterface.name(); - } + QString contextPart = path.section('/', -1); + QHashIterator<QString, QOfonoDataConnectionManagerInterface*> i(ofonoContextManagers); + while (i.hasNext()) { + i.next(); + PathPropertiesList list = i.value()->contextsWithProperties(); + for (int i = 0; i < list.size(); ++i) { + if (list.at(i).path.path().contains(contextPart)) { + return list.at(i).properties.value(QStringLiteral("Name")).toString(); } } } return path; } +void QNetworkManagerEngine::nmRegistered(const QString &) +{ + if (ofonoManager) { + delete ofonoManager; + ofonoManager = NULL; + } + managerInterface = new QNetworkManagerInterface(this); + systemSettings = new QNetworkManagerSettings(NM_DBUS_SERVICE, this); + + connect(managerInterface, SIGNAL(deviceAdded(QDBusObjectPath)), + this, SLOT(deviceAdded(QDBusObjectPath))); + connect(managerInterface, SIGNAL(deviceRemoved(QDBusObjectPath)), + this, SLOT(deviceRemoved(QDBusObjectPath))); + connect(managerInterface, SIGNAL(activationFinished(QDBusPendingCallWatcher*)), + this, SLOT(activationFinished(QDBusPendingCallWatcher*))); + connect(managerInterface, SIGNAL(propertiesChanged(QMap<QString,QVariant>)), + this, SLOT(interfacePropertiesChanged(QMap<QString,QVariant>))); + managerInterface->setConnections(); + + connect(systemSettings, SIGNAL(newConnection(QDBusObjectPath)), + this, SLOT(newConnection(QDBusObjectPath))); + systemSettings->setConnections(); + nmAvailable = true; + + setupConfigurations(); +} + +void QNetworkManagerEngine::nmUnRegistered(const QString &) +{ + if (systemSettings) { + delete systemSettings; + systemSettings = NULL; + } + if (managerInterface) { + delete managerInterface; + managerInterface = NULL; + } +} + +void QNetworkManagerEngine::ofonoRegistered(const QString &) +{ + if (ofonoManager) { + delete ofonoManager; + ofonoManager = NULL; + } + ofonoManager = new QOfonoManagerInterface(this); + if (ofonoManager && ofonoManager->isValid()) { + Q_FOREACH (const QString &modem, ofonoManager->getModems()) { + QOfonoDataConnectionManagerInterface *ofonoContextManager + = new QOfonoDataConnectionManagerInterface(modem,this); + ofonoContextManagers.insert(modem, ofonoContextManager); + } + } +} + +void QNetworkManagerEngine::ofonoUnRegistered(const QString &) +{ + ofonoContextManagers.clear(); +} + QT_END_NAMESPACE #endif // QT_NO_DBUS diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h index 671ed80dab..da6af14c00 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h @@ -109,6 +109,12 @@ private Q_SLOTS: void wiredCarrierChanged(bool); + void nmRegistered(const QString &serviceName = QString()); + void nmUnRegistered(const QString &serviceName = QString()); + + void ofonoRegistered(const QString &serviceName = QString()); + void ofonoUnRegistered(const QString &serviceName = QString()); + private: QNetworkConfigurationPrivate *parseConnection(const QString &settingsPath, const QNmSettingsMap &map); @@ -132,6 +138,13 @@ private: QNetworkConfiguration::BearerType currentBearerType(const QString &id); QString contextName(const QString &path); + bool isConnectionActive(const QString &settingsPath); + QDBusServiceWatcher *ofonoWatcher; + QDBusServiceWatcher *nmWatcher; + + bool isActiveContext(const QString &contextPath); + bool nmAvailable; + void setupConfigurations(); }; QT_END_NAMESPACE diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp index dc3b71ec8e..fad94f069d 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp @@ -688,6 +688,15 @@ QNetworkManagerInterfaceDeviceWireless::QNetworkManagerInterfaceDeviceWireless(c QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS), QLatin1String("PropertiesChanged"), this,SLOT(propertiesSwap(QMap<QString,QVariant>))); + + QDBusPendingReply<QList<QDBusObjectPath> > reply + = d->connectionInterface->asyncCall(QLatin1String("GetAccessPoints")); + + QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(reply); + connect(callWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(accessPointsFinished(QDBusPendingCallWatcher*))); + + d->valid = true; } @@ -749,6 +758,19 @@ bool QNetworkManagerInterfaceDeviceWireless::setConnections() return allOk; } +void QNetworkManagerInterfaceDeviceWireless::accessPointsFinished(QDBusPendingCallWatcher *watcher) +{ + QDBusPendingReply<QList<QDBusObjectPath> > reply(*watcher); + watcher->deleteLater(); + if (!reply.isError()) { + accessPointsList = reply.value(); + } + + for (int i = 0; i < accessPointsList.size(); i++) { + Q_EMIT accessPointAdded(accessPointsList.at(i).path()); + } +} + QDBusInterface *QNetworkManagerInterfaceDeviceWireless::connectionInterface() const { return d->connectionInterface; diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h index da909c443a..e645159d71 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h @@ -369,6 +369,8 @@ private Q_SLOTS: void slotAccessPointAdded(QDBusObjectPath); void slotAccessPointRemoved(QDBusObjectPath); + void accessPointsFinished(QDBusPendingCallWatcher *watcher); + private: QNetworkManagerInterfaceDeviceWirelessPrivate *d; QVariantMap propertyMap; diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index 791b0805d0..251fe9485c 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -323,17 +323,22 @@ NSMenuItem *QCocoaMenuItem::sync() text += QLatin1String(" (") + accel.toString(QKeySequence::NativeText) + QLatin1String(")"); QString finalString = qt_mac_removeMnemonics(text); + bool useAttributedTitle = false; // Cocoa Font and title if (m_font.resolve()) { NSFont *customMenuFont = [NSFont fontWithName:QCFString::toNSString(m_font.family()) size:m_font.pointSize()]; - NSArray *keys = [NSArray arrayWithObjects:NSFontAttributeName, nil]; - NSArray *objects = [NSArray arrayWithObjects:customMenuFont, nil]; - NSDictionary *attributes = [NSDictionary dictionaryWithObjects:objects forKeys:keys]; - NSAttributedString *str = [[[NSAttributedString alloc] initWithString:QCFString::toNSString(finalString) - attributes:attributes] autorelease]; - [m_native setAttributedTitle: str]; - } else { + if (customMenuFont) { + NSArray *keys = [NSArray arrayWithObjects:NSFontAttributeName, nil]; + NSArray *objects = [NSArray arrayWithObjects:customMenuFont, nil]; + NSDictionary *attributes = [NSDictionary dictionaryWithObjects:objects forKeys:keys]; + NSAttributedString *str = [[[NSAttributedString alloc] initWithString:QCFString::toNSString(finalString) + attributes:attributes] autorelease]; + [m_native setAttributedTitle: str]; + useAttributedTitle = true; + } + } + if (!useAttributedTitle) { [m_native setTitle: QCFString::toNSString(finalString)]; } diff --git a/src/plugins/platforms/ios/quiview_accessibility.mm b/src/plugins/platforms/ios/quiview_accessibility.mm index 6565e08302..7e1cb9a4fd 100644 --- a/src/plugins/platforms/ios/quiview_accessibility.mm +++ b/src/plugins/platforms/ios/quiview_accessibility.mm @@ -48,7 +48,7 @@ - (void)createAccessibleElement:(QAccessibleInterface *)iface { - if (!iface || iface->state().invisible) + if (!iface || iface->state().invisible || (iface->text(QAccessible::Name).isEmpty() && iface->text(QAccessible::Value).isEmpty() && iface->text(QAccessible::Description).isEmpty())) return; QAccessible::Id accessibleId = QAccessible::uniqueId(iface); UIAccessibilityElement *elem = [[QMacAccessibilityElement alloc] initWithId: accessibleId withAccessibilityContainer: self]; @@ -60,12 +60,9 @@ if (!iface) return; - if (iface->childCount() == 0) { - [self createAccessibleElement: iface]; - } else { - for (int i = 0; i < iface->childCount(); ++i) - [self createAccessibleContainer: iface->child(i)]; - } + [self createAccessibleElement: iface]; + for (int i = 0; i < iface->childCount(); ++i) + [self createAccessibleContainer: iface->child(i)]; } - (void)initAccessibility diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index cfa5914ff8..d8ccb8cd56 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -804,10 +804,8 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc, uint format = GGO_METRICS; if (ttf) format |= GGO_GLYPH_INDEX; - int res = GetGlyphOutline(hdc, glyph, format, &gMetric, 0, 0, &mat); - if (res == GDI_ERROR) { + if (GetGlyphOutline(hdc, glyph, format, &gMetric, 0, 0, &mat) == GDI_ERROR) return false; - } // #### obey scale *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y, (int)gMetric.gmBlackBoxX, (int)gMetric.gmBlackBoxY, diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index f31ecf8e03..7286b6b89b 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -471,6 +471,7 @@ public: QXcbEventReader *eventReader() const { return m_reader; } + bool canGrab() const { return m_canGrabServer; } protected: bool event(QEvent *e) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 52269bafea..3818494d99 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -92,11 +92,11 @@ QT_BEGIN_NAMESPACE -#if defined(QT_DEBUG) && defined(Q_OS_LINUX) // Find out if our parent process is gdb by looking at the 'exe' symlink under /proc,. // or, for older Linuxes, read out 'cmdline'. static bool runningUnderDebugger() { +#if defined(QT_DEBUG) && defined(Q_OS_LINUX) const QString parentProc = QLatin1String("/proc/") + QString::number(getppid()); const QFileInfo parentProcExe(parentProc + QLatin1String("/exe")); if (parentProcExe.isSymLink()) @@ -113,12 +113,15 @@ static bool runningUnderDebugger() s += c; } return s == "gdb"; -} +#else + return false; #endif +} QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char **argv) : m_services(new QGenericUnixServices) , m_instanceName(0) + , m_canGrab(true) { qRegisterMetaType<QXcbWindow*>(); #ifdef XCB_USE_XLIB @@ -126,16 +129,10 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char #endif m_nativeInterface.reset(new QXcbNativeInterface); - bool canGrab = true; - #if defined(QT_DEBUG) && defined(Q_OS_LINUX) - canGrab = !runningUnderDebugger(); - #endif - static bool canNotGrabEnv = qgetenv("QT_XCB_NO_GRAB_SERVER").length(); - if (canNotGrabEnv) - canGrab = false; - // Parse arguments const char *displayName = 0; + bool noGrabArg = false; + bool doGrabArg = false; if (argc) { int j = 1; for (int i = 1; i < argc; i++) { @@ -146,13 +143,35 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char displayName = argv[++i]; else if (arg == "-name" && i < argc - 1) m_instanceName = argv[++i]; + else if (arg == "-nograb") + noGrabArg = true; + else if (arg == "-dograb") + doGrabArg = true; else argv[j++] = argv[i]; } argc = j; } // argc - m_connections << new QXcbConnection(m_nativeInterface.data(), canGrab, displayName); + bool underDebugger = runningUnderDebugger(); + if (noGrabArg && doGrabArg && underDebugger) { + qWarning() << "Both -nograb and -dograb command line arguments specified. Please pick one. -nograb takes prcedence"; + doGrabArg = false; + } + +#if defined(QT_DEBUG) + if (!noGrabArg && !doGrabArg && underDebugger) { + qDebug("Qt: gdb: -nograb added to command-line options.\n" + "\t Use the -dograb option to enforce grabbing."); + } +#endif + m_canGrab = (!underDebugger && noGrabArg) || (underDebugger && doGrabArg); + + static bool canNotGrabEnv = qEnvironmentVariableIsSet("QT_XCB_NO_GRAB_SERVER"); + if (canNotGrabEnv) + m_canGrab = false; + + m_connections << new QXcbConnection(m_nativeInterface.data(), m_canGrab, displayName); for (int i = 0; i < parameters.size() - 1; i += 2) { #ifdef Q_XCB_DEBUG @@ -408,12 +427,14 @@ QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint) const case QPlatformIntegration::StartDragTime: case QPlatformIntegration::KeyboardAutoRepeatRate: case QPlatformIntegration::PasswordMaskDelay: - case QPlatformIntegration::FontSmoothingGamma: case QPlatformIntegration::StartDragVelocity: case QPlatformIntegration::UseRtlExtensions: case QPlatformIntegration::PasswordMaskCharacter: // TODO using various xcb, gnome or KDE settings break; // Not implemented, use defaults + case QPlatformIntegration::FontSmoothingGamma: + // Match Qt 4.8 text rendering, and rendering of other X11 toolkits. + return qreal(1.0); case QPlatformIntegration::StartDragDistance: { // The default (in QPlatformTheme::defaultThemeHint) is 10 pixels, but // on a high-resolution screen it makes sense to increase it. diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index ffb068ecb3..db6ad541ea 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -117,6 +117,7 @@ private: mutable QByteArray m_wmClass; const char *m_instanceName; + bool m_canGrab; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 5d3206b097..85af8ee1d2 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2170,6 +2170,9 @@ void QXcbWindow::updateSyncRequestCounter() bool QXcbWindow::setKeyboardGrabEnabled(bool grab) { + if (grab && !connection()->canGrab()) + return false; + if (!grab) { xcb_ungrab_keyboard(xcb_connection(), XCB_TIME_CURRENT_TIME); return true; @@ -2185,6 +2188,9 @@ bool QXcbWindow::setKeyboardGrabEnabled(bool grab) bool QXcbWindow::setMouseGrabEnabled(bool grab) { + if (grab && !connection()->canGrab()) + return false; + if (!grab) { xcb_ungrab_pointer(xcb_connection(), XCB_TIME_CURRENT_TIME); return true; diff --git a/src/widgets/accessible/simplewidgets.cpp b/src/widgets/accessible/simplewidgets.cpp index ade5cfe3dc..41692d11bd 100644 --- a/src/widgets/accessible/simplewidgets.cpp +++ b/src/widgets/accessible/simplewidgets.cpp @@ -414,12 +414,14 @@ QString QAccessibleDisplay::text(QAccessible::Text t) const if (qobject_cast<QLabel*>(object())) { QLabel *label = qobject_cast<QLabel*>(object()); str = label->text(); +#ifndef QT_NO_TEXTHTMLPARSER if (label->textFormat() == Qt::RichText || (label->textFormat() == Qt::AutoText && Qt::mightBeRichText(str))) { QTextDocument doc; doc.setHtml(str); str = doc.toPlainText(); } +#endif if (label->buddy()) str = qt_accStripAmp(str); #ifndef QT_NO_LCDNUMBER diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp index 300e2f492b..03f22a270f 100644 --- a/src/widgets/graphicsview/qgraphicsitem.cpp +++ b/src/widgets/graphicsview/qgraphicsitem.cpp @@ -2447,7 +2447,12 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, Items are visible by default; it is unnecessary to call setVisible() on a new item. - \sa isVisible(), show(), hide() + \note An item with opacity set to 0 will still be considered visible, + although it will be treated like an invisible item: mouse events will pass + through it, it will not be included in the items returned by + QGraphicsView::items(), and so on. However, the item will retain the focus. + + \sa isVisible(), show(), hide(), setOpacity() */ void QGraphicsItem::setVisible(bool visible) { @@ -2715,7 +2720,11 @@ qreal QGraphicsItem::effectiveOpacity() const with the parent: ItemIgnoresParentOpacity and ItemDoesntPropagateOpacityToChildren. - \sa opacity(), effectiveOpacity() + \note Setting the opacity of an item to 0 will not make the item invisible + (according to isVisible()), but the item will be treated like an invisible + one. See the documentation of setVisible() for more information. + + \sa opacity(), effectiveOpacity(), setVisible() */ void QGraphicsItem::setOpacity(qreal opacity) { @@ -9782,6 +9791,7 @@ QVariant QGraphicsPixmapItem::extension(const QVariant &variant) const using textWidth(). \note In order to align HTML text in the center, the item's text width must be set. + Otherwise, you can call adjustSize() after setting the item's text. \image graphicsview-textitem.png diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 8f6c5d748c..82b9fec37f 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -53,6 +53,7 @@ #include "qtranslator.h" #include "qvariant.h" #include "qwidget.h" +#include "qgraphicssceneevent.h" #include "private/qdnd_p.h" #include "private/qguiapplication_p.h" #include "qcolormap.h" @@ -2286,6 +2287,31 @@ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool return w; } +Qt::MouseEventSource QApplicationPrivate::mouseEventSource(const QEvent *e) +{ + switch (e->type()) { + case QEvent::NonClientAreaMouseButtonDblClick: + case QEvent::NonClientAreaMouseButtonPress: + case QEvent::NonClientAreaMouseButtonRelease: + case QEvent::NonClientAreaMouseMove: + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + return static_cast<const QMouseEvent *>(e)->source(); +#ifndef QT_NO_GRAPHICSVIEW + case QEvent::GraphicsSceneMouseDoubleClick: + case QEvent::GraphicsSceneMousePress: + case QEvent::GraphicsSceneMouseRelease: + case QEvent::GraphicsSceneMouseMove: + return static_cast<const QGraphicsSceneMouseEvent *>(e)->source(); +#endif // !QT_NO_GRAPHICSVIEW + default: + break; + } + return Qt::MouseEventNotSynthesized; +} + /*! \fn void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave, const QPointF &globalPosF) \internal @@ -4230,8 +4256,9 @@ bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy) return true; } -void QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent) +bool QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent) { + bool containsPress = false; for (int i = 0; i < touchEvent->touchPoints().count(); ++i) { QTouchEvent::TouchPoint &touchPoint = touchEvent->_touchPoints[i]; @@ -4244,7 +4271,11 @@ void QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEven touchPoint.d->rect = rect; touchPoint.d->startPos = widget->mapFromGlobal(touchPoint.startScreenPos().toPoint()) + delta; touchPoint.d->lastPos = widget->mapFromGlobal(touchPoint.lastScreenPos().toPoint()) + delta; + + if (touchPoint.state() == Qt::TouchPointPressed) + containsPress = true; } + return containsPress; } void QApplicationPrivate::initializeMultitouch() @@ -4391,11 +4422,14 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, QApplication::keyboardModifiers(), it.value().first, it.value().second); - updateTouchPointsForWidget(widget, &touchEvent); + bool containsPress = updateTouchPointsForWidget(widget, &touchEvent); touchEvent.setTimestamp(timestamp); touchEvent.setWindow(window->windowHandle()); touchEvent.setTarget(widget); + if (containsPress) + widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent); + switch (touchEvent.type()) { case QEvent::TouchBegin: { diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index 156bf34194..b24b592fbe 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -168,6 +168,7 @@ public: static void setFocusWidget(QWidget *focus, Qt::FocusReason reason); static QWidget *focusNextPrevChild_helper(QWidget *toplevel, bool next, bool *wrappingOccurred = 0); + static Qt::MouseEventSource mouseEventSource(const QEvent *e); #ifndef QT_NO_GRAPHICSVIEW // Maintain a list of all scenes to ensure font and palette propagation to @@ -275,7 +276,7 @@ public: QPixmap *ignore_cursor; #endif - static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); + static bool updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); void initializeMultitouch(); void initializeMultitouch_sys(); void cleanupMultitouch(); diff --git a/src/widgets/kernel/qgesture_p.h b/src/widgets/kernel/qgesture_p.h index 183a2eba0f..26d9ede59d 100644 --- a/src/widgets/kernel/qgesture_p.h +++ b/src/widgets/kernel/qgesture_p.h @@ -80,7 +80,7 @@ class QPanGesturePrivate : public QGesturePrivate public: QPanGesturePrivate() - : acceleration(0), xVelocity(0), yVelocity(0) + : acceleration(0), xVelocity(0), yVelocity(0), pointCount(2) { } @@ -95,6 +95,7 @@ public: qreal acceleration; qreal xVelocity; qreal yVelocity; + int pointCount; // ### fixme Qt 5.5: Add accessor to QPanGesture. }; class QPinchGesturePrivate : public QGesturePrivate diff --git a/src/widgets/kernel/qgesturemanager.cpp b/src/widgets/kernel/qgesturemanager.cpp index 739e6b1870..c9af3062d3 100644 --- a/src/widgets/kernel/qgesturemanager.cpp +++ b/src/widgets/kernel/qgesturemanager.cpp @@ -63,6 +63,24 @@ QT_BEGIN_NAMESPACE +static inline int panTouchPoints() +{ + // Override by environment variable for testing. + static const char panTouchPointVariable[] = "QT_PAN_TOUCHPOINTS"; + if (qEnvironmentVariableIsSet(panTouchPointVariable)) { + bool ok; + const int result = qgetenv(panTouchPointVariable).toInt(&ok); + if (ok && result >= 1) + return result; + qWarning() << "Ignoring invalid value of " << panTouchPointVariable; + } + // Pan should use 1 finger on a touch screen and 2 fingers on touch pads etc. + // where 1 finger movements are used for mouse event synthetization. For now, + // default to 2 until all classes inheriting QScrollArea are fixed to handle it + // correctly. + return 2; +} + QGestureManager::QGestureManager(QObject *parent) : QObject(parent), state(NotGesture), m_lastCustomGestureId(Qt::CustomGesture) { @@ -73,7 +91,7 @@ QGestureManager::QGestureManager(QObject *parent) registerGestureRecognizer(new QMacPinchGestureRecognizer); registerGestureRecognizer(new QMacPanGestureRecognizer); #else - registerGestureRecognizer(new QPanGestureRecognizer); + registerGestureRecognizer(new QPanGestureRecognizer(panTouchPoints())); registerGestureRecognizer(new QPinchGestureRecognizer); registerGestureRecognizer(new QSwipeGestureRecognizer); registerGestureRecognizer(new QTapGestureRecognizer); diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index 23bb1f7050..db116b070c 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -578,12 +578,22 @@ GLuint QOpenGLWidgetPrivate::textureId() const void QOpenGLWidgetPrivate::reset() { + Q_Q(QOpenGLWidget); + + // Destroy the OpenGL resources first. These need the context to be current. + if (initialized) + q->makeCurrent(); + delete paintDevice; paintDevice = 0; delete fbo; fbo = 0; delete resolvedFbo; resolvedFbo = 0; + + if (initialized) + q->doneCurrent(); + // Delete the context first, then the surface. Slots connected to // the context's aboutToBeDestroyed() may still call makeCurrent() // to perform some cleanup. diff --git a/src/widgets/kernel/qstandardgestures.cpp b/src/widgets/kernel/qstandardgestures.cpp index 9e3cb473e5..53e5d091fa 100644 --- a/src/widgets/kernel/qstandardgestures.cpp +++ b/src/widgets/kernel/qstandardgestures.cpp @@ -38,16 +38,13 @@ #include "qwidget.h" #include "qabstractscrollarea.h" #include <qgraphicssceneevent.h> +#include <QtGui/QTouchDevice> #include "qdebug.h" #ifndef QT_NO_GESTURES QT_BEGIN_NAMESPACE -QPanGestureRecognizer::QPanGestureRecognizer() -{ -} - QGesture *QPanGestureRecognizer::create(QObject *target) { if (target && target->isWidgetType()) { @@ -62,8 +59,35 @@ QGesture *QPanGestureRecognizer::create(QObject *target) return new QPanGesture; } +static QPointF panOffset(const QList<QTouchEvent::TouchPoint> &touchPoints, int maxCount) +{ + QPointF result; + const int count = qMin(touchPoints.size(), maxCount); + for (int p = 0; p < count; ++p) + result += touchPoints.at(p).pos() - touchPoints.at(p).startPos(); + return result / qreal(count); +} + +// ### fixme: Remove this +// Use single finger pan to scroll QPlainTextEdit/QTextEdit +// by changing the number of pan points to 1 for these classes. +// This used to be Qt 4's behavior on Windows which was achieved using native +// Windows gesture recognizers for these classes. +// The other classes inheriting QScrollArea still use standard 2 finger pan. +// In the long run, they should also use single finger pan to +// scroll on touch screens, however, this requires a distinct Tap&Hold-followed-by-pan +// type gesture to avoid clashes with item view selection and DnD. + +static inline int panTouchPoints(const QTouchEvent *event, const QObject *object, + int defaultTouchPoints) +{ + return event->device()->type() == QTouchDevice::TouchScreen && object && object->parent() + && (object->parent()->inherits("QPlainTextEdit") || object->parent()->inherits("QTextEdit")) + ? 1 : defaultTouchPoints; +} + QGestureRecognizer::Result QPanGestureRecognizer::recognize(QGesture *state, - QObject *, + QObject *object, QEvent *event) { QPanGesture *q = static_cast<QPanGesture *>(state); @@ -76,18 +100,15 @@ QGestureRecognizer::Result QPanGestureRecognizer::recognize(QGesture *state, result = QGestureRecognizer::MayBeGesture; QTouchEvent::TouchPoint p = ev->touchPoints().at(0); d->lastOffset = d->offset = QPointF(); + d->pointCount = panTouchPoints(ev, object, m_pointCount); break; } case QEvent::TouchEnd: { if (q->state() != Qt::NoGesture) { const QTouchEvent *ev = static_cast<const QTouchEvent *>(event); - if (ev->touchPoints().size() == 2) { - QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); - QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); + if (ev->touchPoints().size() == d->pointCount) { d->lastOffset = d->offset; - d->offset = - QPointF(p1.pos().x() - p1.startPos().x() + p2.pos().x() - p2.startPos().x(), - p1.pos().y() - p1.startPos().y() + p2.pos().y() - p2.startPos().y()) / 2; + d->offset = panOffset(ev->touchPoints(), d->pointCount); } result = QGestureRecognizer::FinishGesture; } else { @@ -97,16 +118,12 @@ QGestureRecognizer::Result QPanGestureRecognizer::recognize(QGesture *state, } case QEvent::TouchUpdate: { const QTouchEvent *ev = static_cast<const QTouchEvent *>(event); - if (ev->touchPoints().size() >= 2) { - QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); - QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); + if (ev->touchPoints().size() >= d->pointCount) { d->lastOffset = d->offset; - d->offset = - QPointF(p1.pos().x() - p1.startPos().x() + p2.pos().x() - p2.startPos().x(), - p1.pos().y() - p1.startPos().y() + p2.pos().y() - p2.startPos().y()) / 2; + d->offset = panOffset(ev->touchPoints(), d->pointCount); if (d->offset.x() > 10 || d->offset.y() > 10 || d->offset.x() < -10 || d->offset.y() < -10) { - q->setHotSpot(p1.startScreenPos()); + q->setHotSpot(ev->touchPoints().first().startScreenPos()); result = QGestureRecognizer::TriggerGesture; } else { result = QGestureRecognizer::MayBeGesture; diff --git a/src/widgets/kernel/qstandardgestures_p.h b/src/widgets/kernel/qstandardgestures_p.h index aeabd9cc7e..15ba31f26a 100644 --- a/src/widgets/kernel/qstandardgestures_p.h +++ b/src/widgets/kernel/qstandardgestures_p.h @@ -55,11 +55,14 @@ QT_BEGIN_NAMESPACE class QPanGestureRecognizer : public QGestureRecognizer { public: - QPanGestureRecognizer(); + explicit QPanGestureRecognizer(int pointCount = 2) : m_pointCount(pointCount) {} QGesture *create(QObject *target); QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event); void reset(QGesture *state); + +private: + const int m_pointCount; }; class QPinchGestureRecognizer : public QGestureRecognizer diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 315d615d89..78eabf3c4c 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -10511,8 +10511,9 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f) QWidget *parentWithWindow = newparent ? (newparent->windowHandle() ? newparent : newparent->nativeParentWidget()) : 0; if (parentWithWindow) { - if (f & Qt::Window) { - q->windowHandle()->setTransientParent(parentWithWindow->windowHandle()); + QWidget *topLevel = parentWithWindow->window(); + if ((f & Qt::Window) && topLevel && topLevel->windowHandle()) { + q->windowHandle()->setTransientParent(topLevel->windowHandle()); q->windowHandle()->setParent(0); } else { q->windowHandle()->setTransientParent(0); diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index c1d6d879a8..71a9b1abd7 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -553,7 +553,9 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, arrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor); } else if (header->sortIndicator & QStyleOptionHeader::SortDown) { arrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor, 180); - } if (!arrow.isNull()) { + } + + if (!arrow.isNull()) { r.setSize(QSize(arrow.width()/2, arrow.height()/2)); r.moveCenter(header->rect.center()); painter->drawPixmap(r.translated(offset), arrow); diff --git a/src/widgets/styles/qwindowsxpstyle.cpp b/src/widgets/styles/qwindowsxpstyle.cpp index c18bbb3431..c1f7b599b3 100644 --- a/src/widgets/styles/qwindowsxpstyle.cpp +++ b/src/widgets/styles/qwindowsxpstyle.cpp @@ -963,7 +963,8 @@ void QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa QImage img; if (!haveCachedPixmap) { // If the pixmap is not cached, generate it! ------------------------- - buffer(w, h); // Ensure a buffer of at least (w, h) in size + if (!buffer(w, h)) // Ensure a buffer of at least (w, h) in size + return; HDC dc = bufferHDC(); // Clear the buffer @@ -2539,7 +2540,7 @@ QRect QWindowsXPStylePrivate::scrollBarGripperBounds(QStyle::State flags, const const int hSpace = theme->rect.width() - size.width(); const int vSpace = theme->rect.height() - size.height(); - const bool sufficientSpace = horizontal && hSpace > (contentsMargin.left() + contentsMargin.right()) + const bool sufficientSpace = (horizontal && hSpace > (contentsMargin.left() + contentsMargin.right())) || vSpace > contentsMargin.top() + contentsMargin.bottom(); return sufficientSpace ? QRect(theme->rect.topLeft() + QPoint(hSpace, vSpace) / 2, size) : QRect(); } diff --git a/src/widgets/widgets/qmainwindow.cpp b/src/widgets/widgets/qmainwindow.cpp index f9376a78d5..ddecea81bf 100644 --- a/src/widgets/widgets/qmainwindow.cpp +++ b/src/widgets/widgets/qmainwindow.cpp @@ -1500,6 +1500,13 @@ bool QMainWindow::event(QEvent *event) /*! \property QMainWindow::unifiedTitleAndToolBarOnMac \brief whether the window uses the unified title and toolbar look on Mac OS X + + Note that the Qt 5 implementation has several limitations compared to Qt 4: + \list + \li Use in windows with OpenGL content is not supported. This includes QGLWidget and QOpenGLWidget. + \li Using dockable or movable toolbars may result in painting errors and is not recommended + \endlist + \since 5.2 */ void QMainWindow::setUnifiedTitleAndToolBarOnMac(bool set) diff --git a/src/widgets/widgets/qmdiarea.cpp b/src/widgets/widgets/qmdiarea.cpp index 1e291f469e..3553baf68a 100644 --- a/src/widgets/widgets/qmdiarea.cpp +++ b/src/widgets/widgets/qmdiarea.cpp @@ -1511,7 +1511,7 @@ void QMdiAreaPrivate::highlightNextSubWindow(int increaseFactor) #ifndef QT_NO_RUBBERBAND if (!rubberBand) { - rubberBand = new QRubberBand(QRubberBand::Rectangle, viewport); + rubberBand = new QRubberBand(QRubberBand::Rectangle, q); // For accessibility to identify this special widget. rubberBand->setObjectName(QLatin1String("qt_rubberband")); rubberBand->setWindowFlags(rubberBand->windowFlags() | Qt::WindowStaysOnTopHint); @@ -1528,6 +1528,20 @@ void QMdiAreaPrivate::highlightNextSubWindow(int increaseFactor) Q_ASSERT(indexToHighlighted >= 0); } +void QMdiAreaPrivate::showRubberBandFor(QMdiSubWindow *subWindow) +{ + if (!subWindow || !rubberBand) + return; + + if (viewMode == QMdiArea::TabbedView) + rubberBand->setGeometry(tabBar->tabRect(childWindows.indexOf(subWindow))); + else + rubberBand->setGeometry(subWindow->geometry()); + + rubberBand->raise(); + rubberBand->show(); +} + /*! \internal \since 4.4 diff --git a/src/widgets/widgets/qmdiarea_p.h b/src/widgets/widgets/qmdiarea_p.h index 1092fd9a30..ba531adaad 100644 --- a/src/widgets/widgets/qmdiarea_p.h +++ b/src/widgets/widgets/qmdiarea_p.h @@ -248,14 +248,7 @@ public: } #ifndef QT_NO_RUBBERBAND - inline void showRubberBandFor(QMdiSubWindow *subWindow) - { - if (!subWindow || !rubberBand) - return; - rubberBand->setGeometry(subWindow->geometry()); - rubberBand->raise(); - rubberBand->show(); - } + void showRubberBandFor(QMdiSubWindow *subWindow); inline void hideRubberBand() { diff --git a/src/widgets/widgets/qplaintextedit.cpp b/src/widgets/widgets/qplaintextedit.cpp index b6a21f183a..72a556db7c 100644 --- a/src/widgets/widgets/qplaintextedit.cpp +++ b/src/widgets/widgets/qplaintextedit.cpp @@ -2042,11 +2042,13 @@ void QPlainTextEdit::mouseMoveEvent(QMouseEvent *e) d->sendControlEvent(e); if (!(e->buttons() & Qt::LeftButton)) return; - QRect visible = d->viewport->rect(); - if (visible.contains(pos)) - d->autoScrollTimer.stop(); - else if (!d->autoScrollTimer.isActive()) - d->autoScrollTimer.start(100, this); + if (e->source() == Qt::MouseEventNotSynthesized) { + const QRect visible = d->viewport->rect(); + if (visible.contains(pos)) + d->autoScrollTimer.stop(); + else if (!d->autoScrollTimer.isActive()) + d->autoScrollTimer.start(100, this); + } } /*! \reimp @@ -2055,7 +2057,7 @@ void QPlainTextEdit::mouseReleaseEvent(QMouseEvent *e) { Q_D(QPlainTextEdit); d->sendControlEvent(e); - if (d->autoScrollTimer.isActive()) { + if (e->source() == Qt::MouseEventNotSynthesized && d->autoScrollTimer.isActive()) { d->autoScrollTimer.stop(); d->ensureCursorVisible(); } diff --git a/src/widgets/widgets/qtextedit.cpp b/src/widgets/widgets/qtextedit.cpp index 2d95009eb3..7ef864139f 100644 --- a/src/widgets/widgets/qtextedit.cpp +++ b/src/widgets/widgets/qtextedit.cpp @@ -1574,11 +1574,13 @@ void QTextEdit::mouseMoveEvent(QMouseEvent *e) d->sendControlEvent(e); if (!(e->buttons() & Qt::LeftButton)) return; - QRect visible = d->viewport->rect(); - if (visible.contains(pos)) - d->autoScrollTimer.stop(); - else if (!d->autoScrollTimer.isActive()) - d->autoScrollTimer.start(100, this); + if (e->source() == Qt::MouseEventNotSynthesized) { + const QRect visible = d->viewport->rect(); + if (visible.contains(pos)) + d->autoScrollTimer.stop(); + else if (!d->autoScrollTimer.isActive()) + d->autoScrollTimer.start(100, this); + } } /*! \reimp @@ -1587,7 +1589,7 @@ void QTextEdit::mouseReleaseEvent(QMouseEvent *e) { Q_D(QTextEdit); d->sendControlEvent(e); - if (d->autoScrollTimer.isActive()) { + if (e->source() == Qt::MouseEventNotSynthesized && d->autoScrollTimer.isActive()) { d->autoScrollTimer.stop(); ensureCursorVisible(); } diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp index dfec6a14d4..8f017b7b87 100644 --- a/src/widgets/widgets/qwidgettextcontrol.cpp +++ b/src/widgets/widgets/qwidgettextcontrol.cpp @@ -1580,8 +1580,10 @@ void QWidgetTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton butto cursor.clearSelection(); } } + // Do not start selection on a mouse event synthesized from a touch event. if (!(button & Qt::LeftButton) || - !((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable))) { + !((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable)) + || QApplicationPrivate::mouseEventSource(e) != Qt::MouseEventNotSynthesized) { e->ignore(); return; } @@ -1752,6 +1754,11 @@ void QWidgetTextControlPrivate::mouseReleaseEvent(QEvent *e, Qt::MouseButton but { Q_Q(QWidgetTextControl); + if (QApplicationPrivate::mouseEventSource(e) != Qt::MouseEventNotSynthesized) { + setCursorPosition(pos); // Emulate Tap to set cursor for events synthesized from touch. + return; + } + const QTextCursor oldSelection = cursor; if (sendMouseEventToInputContext( e, QEvent::MouseButtonRelease, button, pos, modifiers, buttons, globalPos)) { |