From 9def501433e80e1a45c0d7888b9ceba4e32ca1fa Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Mon, 18 Apr 2016 23:27:12 +0200 Subject: [PATCH 01/20] QString: Avoid searching for a needle which is longer than the hay Avoid incurring the cost of converting the latin1 data in that case. Several existing QString unit tests excercise the new code path. Task-number: QTBUG-52617 Change-Id: I27256d9e7db34f09543e244a79d754ff7932f0d0 Reviewed-by: Thiago Macieira --- src/corelib/tools/qstring.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 10d3441d2c..983d1213d9 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -10005,6 +10005,9 @@ static inline int qt_find_latin1_string(const QChar *haystack, int size, QLatin1String needle, int from, Qt::CaseSensitivity cs) { + if (size < needle.size()) + return -1; + const char *latin1 = needle.latin1(); int len = needle.size(); QVarLengthArray s(len); From 072485048fc8360b822e35b4cc43b0728e04cc1b Mon Sep 17 00:00:00 2001 From: Vyacheslav Grigoryev Date: Mon, 4 Apr 2016 01:03:20 +0300 Subject: [PATCH 02/20] QHeaderView: fixing selection of reordered rows and columns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old code incorrectly calculated visual region for a selection (specified by QItemSelection object) in case of reordered / swapped rows or columns. It used the leftmost and rightmost (upmost and downmost for vertical mode) logical indexes directly. However some middle logical index (in case of reorder) may be the leftmost or rightmost visual index. In such cases the repainting didn't work properly. This fix first checks whether reordering / swapping is in use. If it isn't (ie visual=logical) we use code similar to the old code. Otherwise the new code scans all selected logical indexes, translates them into visual ones and gets the correct leftmost and rightmost indexes. [ChangeLog][QtWidgets][QHeaderView] Fixed a repainting issue when items had been reordered. Task-number: QTBUG-50171 Change-Id: If6afabebf445cf32a8e0afe262b6ee149e7c4b2b Reviewed-by: Thorbjørn Lund Martsum --- src/widgets/itemviews/qheaderview.cpp | 114 +++++++++++------- .../itemviews/qheaderview/tst_qheaderview.cpp | 20 +++ 2 files changed, 90 insertions(+), 44 deletions(-) diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index f04d580030..46684d325c 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -2957,31 +2957,43 @@ QRegion QHeaderView::visualRegionForSelection(const QItemSelection &selection) c { Q_D(const QHeaderView); const int max = d->modelSectionCount(); + if (d->orientation == Qt::Horizontal) { - int left = max; - int right = 0; - int rangeLeft, rangeRight; + int logicalLeft = max; + int logicalRight = 0; - for (int i = 0; i < selection.count(); ++i) { - QItemSelectionRange r = selection.at(i); - if (r.parent().isValid() || !r.isValid()) - continue; // we only know about toplevel items and we don't want invalid ranges - // FIXME an item inside the range may be the leftmost or rightmost - rangeLeft = visualIndex(r.left()); - if (rangeLeft == -1) // in some cases users may change the selections - continue; // before we have a chance to do the layout - rangeRight = visualIndex(r.right()); - if (rangeRight == -1) // in some cases users may change the selections - continue; // before we have a chance to do the layout - if (rangeLeft < left) - left = rangeLeft; - if (rangeRight > right) - right = rangeRight; + if (d->visualIndices.empty()) { + // If no reordered sections, skip redundant visual-to-logical transformations + for (int i = 0; i < selection.count(); ++i) { + const QItemSelectionRange &r = selection.at(i); + if (r.parent().isValid() || !r.isValid()) + continue; // we only know about toplevel items and we don't want invalid ranges + if (r.left() < logicalLeft) + logicalLeft = r.left(); + if (r.right() > logicalRight) + logicalRight = r.right(); + } + } else { + int left = max; + int right = 0; + for (int i = 0; i < selection.count(); ++i) { + const QItemSelectionRange &r = selection.at(i); + if (r.parent().isValid() || !r.isValid()) + continue; // we only know about toplevel items and we don't want invalid ranges + for (int k = r.left(); k <= r.right(); ++k) { + int visual = visualIndex(k); + if (visual == -1) // in some cases users may change the selections + continue; // before we have a chance to do the layout + if (visual < left) + left = visual; + if (visual > right) + right = visual; + } + } + logicalLeft = logicalIndex(left); + logicalRight = logicalIndex(right); } - int logicalLeft = logicalIndex(left); - int logicalRight = logicalIndex(right); - if (logicalLeft < 0 || logicalLeft >= count() || logicalRight < 0 || logicalRight >= count()) return QRegion(); @@ -2992,32 +3004,46 @@ QRegion QHeaderView::visualRegionForSelection(const QItemSelection &selection) c return QRect(leftPos, 0, rightPos - leftPos, height()); } // orientation() == Qt::Vertical - int top = max; - int bottom = 0; - int rangeTop, rangeBottom; + int logicalTop = max; + int logicalBottom = 0; - for (int i = 0; i < selection.count(); ++i) { - QItemSelectionRange r = selection.at(i); - if (r.parent().isValid() || !r.isValid()) - continue; // we only know about toplevel items - // FIXME an item inside the range may be the leftmost or rightmost - rangeTop = visualIndex(r.top()); - if (rangeTop == -1) // in some cases users may change the selections - continue; // before we have a chance to do the layout - rangeBottom = visualIndex(r.bottom()); - if (rangeBottom == -1) // in some cases users may change the selections - continue; // before we have a chance to do the layout - if (rangeTop < top) - top = rangeTop; - if (rangeBottom > bottom) - bottom = rangeBottom; + if (d->visualIndices.empty()) { + // If no reordered sections, skip redundant visual-to-logical transformations + for (int i = 0; i < selection.count(); ++i) { + const QItemSelectionRange &r = selection.at(i); + if (r.parent().isValid() || !r.isValid()) + continue; // we only know about toplevel items and we don't want invalid ranges + if (r.top() < logicalTop) + logicalTop = r.top(); + if (r.bottom() > logicalBottom) + logicalBottom = r.bottom(); + } + } else { + int top = max; + int bottom = 0; + + for (int i = 0; i < selection.count(); ++i) { + const QItemSelectionRange &r = selection.at(i); + if (r.parent().isValid() || !r.isValid()) + continue; // we only know about toplevel items and we don't want invalid ranges + for (int k = r.top(); k <= r.bottom(); ++k) { + int visual = visualIndex(k); + if (visual == -1) // in some cases users may change the selections + continue; // before we have a chance to do the layout + if (visual < top) + top = visual; + if (visual > bottom) + bottom = visual; + } + } + + logicalTop = logicalIndex(top); + logicalBottom = logicalIndex(bottom); } - int logicalTop = logicalIndex(top); - int logicalBottom = logicalIndex(bottom); - - if (logicalTop == -1 || logicalBottom == -1) - return QRect(); + if (logicalTop < 0 || logicalTop >= count() || + logicalBottom < 0 || logicalBottom >= count()) + return QRegion(); int topPos = sectionViewportPosition(logicalTop); int bottomPos = sectionViewportPosition(logicalBottom) + sectionSize(logicalBottom); diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp index 55fcf04846..4736aa5c12 100644 --- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp +++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp @@ -77,6 +77,7 @@ public: void testEvent(); void testhorizontalOffset(); void testverticalOffset(); + void testVisualRegionForSelection(); friend class tst_QHeaderView; }; @@ -211,6 +212,7 @@ private slots: void QTBUG8650_crashOnInsertSections(); void QTBUG12268_hiddenMovedSectionSorting(); void QTBUG14242_hideSectionAutoSize(); + void QTBUG50171_visualRegionForSwappedItems(); void ensureNoIndexAtLength(); void offsetConsistent(); @@ -2282,6 +2284,24 @@ void tst_QHeaderView::QTBUG14242_hideSectionAutoSize() QCOMPARE(calced_length, afterlength); } +void tst_QHeaderView::QTBUG50171_visualRegionForSwappedItems() +{ + protected_QHeaderView headerView(Qt::Horizontal); + QtTestModel model; + model.rows = 2; + model.cols = 3; + headerView.setModel(&model); + headerView.swapSections(1, 2); + headerView.hideSection(0); + headerView.testVisualRegionForSelection(); +} + +void protected_QHeaderView::testVisualRegionForSelection() +{ + QRegion r = visualRegionForSelection(QItemSelection(model()->index(1, 0), model()->index(1, 2))); + QCOMPARE(r.boundingRect().contains(QRect(1, 1, length() - 2, 1)), true); +} + void tst_QHeaderView::ensureNoIndexAtLength() { QTableView qtv; From 5b54c352edbc597ec5283bc9cfdd77906350161f Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 21 Apr 2016 10:02:17 +0200 Subject: [PATCH 03/20] Cocoa integration - add a protection against dangling pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport watcher-sentinel trick (QPointer->QObject) from dev. Task-number: QTBUG-42059 Change-Id: I9b2c7cde635c2ed9a3f667f216da62870d0b5ccb Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qcocoawindow.h | 6 ++++++ src/plugins/platforms/cocoa/qcocoawindow.mm | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 05e6cf3c9e..e60ca196ac 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -66,6 +66,7 @@ typedef NSWindow QCocoaNSWindow; QCocoaWindow *_platformWindow; BOOL _grabbingMouse; BOOL _releaseOnMouseUp; + QPointer _watcher; } @property (nonatomic, readonly) QCocoaNSWindow *window; @@ -315,6 +316,11 @@ public: // for QNSView }; QHash m_contentBorderAreas; // identifer -> uppper/lower QHash m_enabledContentBorderAreas; // identifer -> enabled state (true/false) + + // This object is tracked by a 'watcher' + // object in a window helper, preventing use of dangling + // pointers. + QObject sentinel; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index e4cd57a115..12e85c5205 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -94,6 +94,7 @@ static bool isMouseEvent(NSEvent *ev) // make sure that m_nsWindow stays valid until the // QCocoaWindow is deleted by Qt. [_window setReleasedWhenClosed:NO]; + _watcher = &_platformWindow->sentinel; } return self; @@ -102,7 +103,7 @@ static bool isMouseEvent(NSEvent *ev) - (void)handleWindowEvent:(NSEvent *)theEvent { QCocoaWindow *pw = self.platformWindow; - if (pw && pw->m_forwardWindow) { + if (_watcher && pw && pw->m_forwardWindow) { if (theEvent.type == NSLeftMouseUp || theEvent.type == NSLeftMouseDragged) { QNSView *forwardView = pw->m_qtView; if (theEvent.type == NSLeftMouseUp) { @@ -141,7 +142,7 @@ static bool isMouseEvent(NSEvent *ev) if (!self.window.delegate) return; // Already detached, pending NSAppKitDefined event - if (pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { + if (_watcher && pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { NSPoint loc = [theEvent locationInWindow]; NSRect windowFrame = [self.window convertRectFromScreen:[self.window frame]]; NSRect contentFrame = [[self.window contentView] frame]; @@ -157,6 +158,7 @@ static bool isMouseEvent(NSEvent *ev) - (void)detachFromPlatformWindow { _platformWindow = 0; + _watcher.clear(); [self.window.delegate release]; self.window.delegate = nil; } From ccfe33dc670a1491d9e1daa2ae17f5fe30484276 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 21 Apr 2016 11:22:32 +0200 Subject: [PATCH 04/20] QWidget::grab(): Use device pixel ratio. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Return pixmaps with device pixel ratio similar to QScreen::grabWindow(), cf c0963486ce689e778d59dafd26d36d8ef9e3ee74. Adapt kernel tests accordingly. Task-number: QTBUG-52137 Change-Id: I9ce276d5e2d87ae0d39c8639267d1ac283fed854 Reviewed-by: Morten Johan Sørvig --- src/widgets/kernel/qwidget.cpp | 4 +++- .../widgets/kernel/qwidget/tst_qwidget.cpp | 21 ++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index c57ca41815..48334cd169 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -5234,7 +5234,9 @@ QPixmap QWidget::grab(const QRect &rectangle) if (!r.intersects(rect())) return QPixmap(); - QPixmap res(r.size()); + const qreal dpr = devicePixelRatioF(); + QPixmap res((QSizeF(r.size()) * dpr).toSize()); + res.setDevicePixelRatio(dpr); if (!d->isOpaque) res.fill(Qt::transparent); d->render(&res, QPoint(), QRegion(r), renderFlags); diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 1c2a74109f..b9fe40e64c 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -3035,8 +3035,23 @@ protected: QSize sizeHint() const { return QSize(500, 500); } }; +// Scale to remove devicePixelRatio should scaling be active. +static QPixmap grabFromWidget(QWidget *w, const QRect &rect) +{ + QPixmap pixmap = w->grab(rect); + const qreal devicePixelRatio = pixmap.devicePixelRatioF(); + if (!qFuzzyCompare(devicePixelRatio, qreal(1))) { + pixmap = pixmap.scaled((QSizeF(pixmap.size()) / devicePixelRatio).toSize(), + Qt::KeepAspectRatio, Qt::SmoothTransformation); + pixmap.setDevicePixelRatio(1); + } + return pixmap; +} + void tst_QWidget::testContentsPropagation() { + if (!qFuzzyCompare(qApp->devicePixelRatio(), qreal(1))) + QSKIP("This test does not work with scaling."); ContentsPropagationWidget widget; widget.setFixedSize(500, 500); widget.setContentsPropagation(false); @@ -9208,7 +9223,7 @@ void tst_QWidget::rectOutsideCoordinatesLimit_task144779() QPixmap correct(main.size()); correct.fill(Qt::green); - const QPixmap mainPixmap = main.grab(QRect(QPoint(0, 0), QSize(-1, -1))); + const QPixmap mainPixmap = grabFromWidget(&main, QRect(QPoint(0, 0), QSize(-1, -1))); QTRY_COMPARE(mainPixmap.toImage().convertToFormat(QImage::Format_RGB32), correct.toImage().convertToFormat(QImage::Format_RGB32)); @@ -9672,10 +9687,10 @@ void tst_QWidget::grab() p.drawTiledPixmap(0, 0, 128, 128, pal.brush(QPalette::Window).texture(), 0, 0); p.end(); - QPixmap actual = widget.grab(QRect(64, 64, 64, 64)); + QPixmap actual = grabFromWidget(&widget, QRect(64, 64, 64, 64)); QVERIFY(lenientCompare(actual, expected)); - actual = widget.grab(QRect(64, 64, -1, -1)); + actual = grabFromWidget(&widget, QRect(64, 64, -1, -1)); QVERIFY(lenientCompare(actual, expected)); // Make sure a widget that is not yet shown is grabbed correctly. From 9442b3a1c3655ffc2fe0b80541259ff72b6192c9 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 20 Apr 2016 09:09:29 +0200 Subject: [PATCH 05/20] Windows QPA/GL: Avoid crash in GL driver. QWindowsStaticOpenGLContext::doCreate(): Invoke QWindowsOpenGLTester::supportedRenderers() only when needed; specifically, do not unnecessarily call it when GLES/SW renderer is specified. Amends change b4c8e1517455becb138876c08b3bdd880a80770d. Task-number: QTBUG-49541 Task-number: QTBUG-52693 Change-Id: I58d1c584d194f8e7fee35ee16b77575f86d3c22e Reviewed-by: Laszlo Agocs --- src/plugins/platforms/windows/qwindowsintegration.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index bf238c3e77..3966a4cd77 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -345,13 +345,11 @@ QWindowsWindow *QWindowsIntegration::createPlatformWindowHelper(QWindow *window, QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::doCreate() { #if defined(QT_OPENGL_DYNAMIC) - const QWindowsOpenGLTester::Renderers supportedRenderers = QWindowsOpenGLTester::supportedRenderers(); - QWindowsOpenGLTester::Renderer requestedRenderer = QWindowsOpenGLTester::requestedRenderer(); switch (requestedRenderer) { case QWindowsOpenGLTester::DesktopGl: if (QWindowsStaticOpenGLContext *glCtx = QOpenGLStaticContext::create()) { - if ((supportedRenderers & QWindowsOpenGLTester::DisableRotationFlag) + if ((QWindowsOpenGLTester::supportedRenderers() & QWindowsOpenGLTester::DisableRotationFlag) && !QWindowsScreen::setOrientationPreference(Qt::LandscapeOrientation)) { qCWarning(lcQpaGl, "Unable to disable rotation."); } @@ -377,6 +375,7 @@ QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::doCreate() break; } + const QWindowsOpenGLTester::Renderers supportedRenderers = QWindowsOpenGLTester::supportedRenderers(); if (supportedRenderers & QWindowsOpenGLTester::DesktopGl) { if (QWindowsStaticOpenGLContext *glCtx = QOpenGLStaticContext::create()) { if ((supportedRenderers & QWindowsOpenGLTester::DisableRotationFlag) From eb786d600cf0b994089dacd7e2ed9a02b1ac0552 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 4 Nov 2015 16:36:14 +0100 Subject: [PATCH 06/20] Fusion style: Observe text alignment of QGroupBox. Take alignment into account in QFusionStyle::subControlRect(). Task-number: QTBUG-49068 Change-Id: Ia8f2d06c46b24761bff537247bbadd3323e41fa9 Reviewed-by: Alessandro Portale --- src/widgets/styles/qfusionstyle.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index 8405b5ce97..5978140f6c 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -3418,12 +3418,28 @@ QRect QFusionStyle::subControlRect(ComplexControl control, const QStyleOptionCom QSize textSize = option->fontMetrics.boundingRect(groupBox->text).size() + QSize(2, 2); int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget); int indicatorHeight = proxy()->pixelMetric(PM_IndicatorHeight, option, widget); + + const int width = textSize.width() + + (option->subControls & QStyle::SC_GroupBoxCheckBox ? indicatorWidth + 5 : 0); + rect = QRect(); + + if (option->rect.width() > width) { + switch (groupBox->textAlignment & Qt::AlignHorizontal_Mask) { + case Qt::AlignHCenter: + rect.moveLeft((option->rect.width() - width) / 2); + break; + case Qt::AlignRight: + rect.moveLeft(option->rect.width() - width); + break; + } + } + if (subControl == SC_GroupBoxCheckBox) { rect.setWidth(indicatorWidth); rect.setHeight(indicatorHeight); rect.moveTop(textSize.height() > indicatorHeight ? (textSize.height() - indicatorHeight) / 2 : 0); - rect.moveLeft(1); + rect.translate(1, 0); } else if (subControl == SC_GroupBoxLabel) { rect.setSize(textSize); rect.moveTop(1); From ea64dc9a113a850334fbf47ca2cdc3b447945c25 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Fri, 15 Apr 2016 13:49:25 +0200 Subject: [PATCH 07/20] qlockfile_unix - code cleanup Coverity's CID 157687: QCache::insert, indeed, can delete (immediately) the object we're trying to insert. While this never happens actually in qlockfile_unix since we have max cost 10 and insert with cost 1, the code does not look good and Coverity is not happy. Change-Id: I16a428017bf86e151afe5256906e4cab1ef4044a Reviewed-by: Joerg Bornemann --- src/corelib/io/qlockfile_unix.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp index bcef84206e..f23a232fb8 100644 --- a/src/corelib/io/qlockfile_unix.cpp +++ b/src/corelib/io/qlockfile_unix.cpp @@ -139,12 +139,14 @@ static bool fcntlWorksAfterFlock(const QString &fn) if (fcntlOK.isDestroyed()) return QLockFilePrivate::checkFcntlWorksAfterFlock(fn); bool *worksPtr = fcntlOK->object(fn); - if (!worksPtr) { - worksPtr = new bool(QLockFilePrivate::checkFcntlWorksAfterFlock(fn)); - fcntlOK->insert(fn, worksPtr); - } + if (worksPtr) + return *worksPtr; - return *worksPtr; + const bool val = QLockFilePrivate::checkFcntlWorksAfterFlock(fn); + worksPtr = new bool(val); + fcntlOK->insert(fn, worksPtr); + + return val; } static bool setNativeLocks(const QString &fileName, int fd) From e27fae353ca9a2d4d5054d32bb3a2622ccf9d889 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Thu, 14 Apr 2016 18:57:14 +0300 Subject: [PATCH 08/20] QFileSystemModel: fix updating QFileInfo for a node after a file rename Use the correct parent path for the renamed file when creating QFileInfo. It must be a path to the parent directory, not to the root directory of the model. Modify tst_QFileSystemModel::setData() to test renames in subdirs of the root directory of the model. Change-Id: I69d9e3a937616857a81617791ed118af3f6eea05 Task-number: QTBUG-52561 Reviewed-by: Friedemann Kleint Reviewed-by: Lars Knoll --- src/widgets/dialogs/qfilesystemmodel.cpp | 8 +++-- .../qfilesystemmodel/tst_qfilesystemmodel.cpp | 34 ++++++++++++++++--- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/widgets/dialogs/qfilesystemmodel.cpp b/src/widgets/dialogs/qfilesystemmodel.cpp index d23737f130..9bf5a502c3 100644 --- a/src/widgets/dialogs/qfilesystemmodel.cpp +++ b/src/widgets/dialogs/qfilesystemmodel.cpp @@ -849,9 +849,11 @@ bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, in if (newName == idx.data().toString()) return true; + const QString parentPath = filePath(parent(idx)); + if (newName.isEmpty() || QDir::toNativeSeparators(newName).contains(QDir::separator()) - || !QDir(filePath(parent(idx))).rename(oldName, newName)) { + || !QDir(parentPath).rename(oldName, newName)) { #ifndef QT_NO_MESSAGEBOX QMessageBox::information(0, QFileSystemModel::tr("Invalid filename"), QFileSystemModel::tr("The name \"%1\" can not be used.

Try using another name, with fewer characters or no punctuations marks.") @@ -878,7 +880,7 @@ bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, in parentNode->visibleChildren.removeAt(visibleLocation); QFileSystemModelPrivate::QFileSystemNode * oldValue = parentNode->children.value(oldName); parentNode->children[newName] = oldValue; - QFileInfo info(d->rootDir, newName); + QFileInfo info(parentPath, newName); oldValue->fileName = newName; oldValue->parent = parentNode; #ifndef QT_NO_FILESYSTEMWATCHER @@ -890,7 +892,7 @@ bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, in parentNode->visibleChildren.insert(visibleLocation, newName); d->delayedSort(); - emit fileRenamed(filePath(idx.parent()), oldName, newName); + emit fileRenamed(parentPath, oldName, newName); } return true; } diff --git a/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp b/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp index d370a647b4..19b1d0e7c8 100644 --- a/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp +++ b/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp @@ -697,6 +697,7 @@ void tst_QFileSystemModel::nameFilters() } void tst_QFileSystemModel::setData_data() { + QTest::addColumn("subdirName"); QTest::addColumn("files"); QTest::addColumn("oldFileName"); QTest::addColumn("newFileName"); @@ -706,7 +707,15 @@ void tst_QFileSystemModel::setData_data() << QDir::temp().absolutePath() + '/' + "a" << false; */ - QTest::newRow("in current dir") << (QStringList() << "a" << "b" << "c") + QTest::newRow("in current dir") + << QString() + << (QStringList() << "a" << "b" << "c") + << "a" + << "d" + << true; + QTest::newRow("in subdir") + << "s" + << (QStringList() << "a" << "b" << "c") << "a" << "d" << true; @@ -715,15 +724,25 @@ void tst_QFileSystemModel::setData_data() void tst_QFileSystemModel::setData() { QSignalSpy spy(model, SIGNAL(fileRenamed(QString,QString,QString))); - QString tmp = flatDirTestPath; + QFETCH(QString, subdirName); QFETCH(QStringList, files); QFETCH(QString, oldFileName); QFETCH(QString, newFileName); QFETCH(bool, success); + QString tmp = flatDirTestPath; + if (!subdirName.isEmpty()) { + QDir dir(tmp); + QVERIFY(dir.mkdir(subdirName)); + tmp.append('/' + subdirName); + } QVERIFY(createFiles(tmp, files)); - QModelIndex root = model->setRootPath(tmp); - QTRY_COMPARE(model->rowCount(root), files.count()); + QModelIndex tmpIdx = model->setRootPath(flatDirTestPath); + if (!subdirName.isEmpty()) { + tmpIdx = model->index(tmp); + model->fetchMore(tmpIdx); + } + QTRY_COMPARE(model->rowCount(tmpIdx), files.count()); QModelIndex idx = model->index(tmp + '/' + oldFileName); QCOMPARE(idx.isValid(), true); @@ -731,16 +750,21 @@ void tst_QFileSystemModel::setData() model->setReadOnly(false); QCOMPARE(model->setData(idx, newFileName), success); + model->setReadOnly(true); if (success) { QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QCOMPARE(model->data(idx, QFileSystemModel::FileNameRole).toString(), newFileName); + QCOMPARE(model->fileInfo(idx).filePath(), tmp + '/' + newFileName); QCOMPARE(model->index(arguments.at(0).toString()), model->index(tmp)); QCOMPARE(arguments.at(1).toString(), oldFileName); QCOMPARE(arguments.at(2).toString(), newFileName); QCOMPARE(QFile::rename(tmp + '/' + newFileName, tmp + '/' + oldFileName), true); } - QTRY_COMPARE(model->rowCount(root), files.count()); + QTRY_COMPARE(model->rowCount(tmpIdx), files.count()); + // cleanup + if (!subdirName.isEmpty()) + QVERIFY(QDir(tmp).removeRecursively()); } void tst_QFileSystemModel::sortPersistentIndex() From a9e7bf9ffd1012979db7fb07e5a2c91b00dc700e Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Mon, 18 Apr 2016 16:30:43 +0200 Subject: [PATCH 09/20] _q_networkSessionStateChanged - fix weird logic a != A || a != B looks suspiciously wrong. Found, unfortunately, only by Coverity (CIDs 152247, 152249). Change-Id: Ia7ec810dde2a3a33ae6fc5644a4eebf279dcffe8 Reviewed-by: Edward Welbourne Reviewed-by: Timur Pocheptsov --- src/network/access/qnetworkreplyhttpimpl.cpp | 2 +- src/network/access/qnetworkreplyimpl.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 3120f29c03..94235a48dd 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -1950,7 +1950,7 @@ void QNetworkReplyHttpImplPrivate::_q_networkSessionConnected() void QNetworkReplyHttpImplPrivate::_q_networkSessionStateChanged(QNetworkSession::State sessionState) { if (sessionState == QNetworkSession::Disconnected - && (state != Idle || state != Reconnecting)) { + && state != Idle && state != Reconnecting) { error(QNetworkReplyImpl::NetworkSessionFailedError, QCoreApplication::translate("QNetworkReply", "Network session error.")); finished(); diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 86896c2eca..00dd4cbe52 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -319,7 +319,7 @@ void QNetworkReplyImplPrivate::_q_networkSessionConnected() void QNetworkReplyImplPrivate::_q_networkSessionStateChanged(QNetworkSession::State sessionState) { if (sessionState == QNetworkSession::Disconnected - && (state != Idle || state != Reconnecting)) { + && state != Idle && state != Reconnecting) { error(QNetworkReplyImpl::NetworkSessionFailedError, QCoreApplication::translate("QNetworkReply", "Network session error.")); finished(); From 1b9d082bb88e561400d2614c0507f53da478d975 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Mon, 28 Mar 2016 19:43:08 +0200 Subject: [PATCH 10/20] dbus: make QDBusArgumentPrivate destructor virtual Make the destructor of QDBusArgumentPrivate virtual as it may store other types (QDBusDemarshaller). Suggested by Thiago. Fixes a "new-delete-type-mismatch" error reported by AddressSanitizer. Task-number: QTBUG-52176 Change-Id: I9ac19050840530ca9cae893b10093185d31e0448 Reviewed-by: Thiago Macieira Reviewed-by: Marc Mutz Reviewed-by: David Faure --- src/dbus/qdbusargument_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dbus/qdbusargument_p.h b/src/dbus/qdbusargument_p.h index 28a3380fab..377cdf395b 100644 --- a/src/dbus/qdbusargument_p.h +++ b/src/dbus/qdbusargument_p.h @@ -66,7 +66,7 @@ public: inline QDBusArgumentPrivate(int flags = 0) : message(0), ref(1), capabilities(flags) { } - ~QDBusArgumentPrivate(); + virtual ~QDBusArgumentPrivate(); static bool checkRead(QDBusArgumentPrivate *d); static bool checkReadAndDetach(QDBusArgumentPrivate *&d); From c511466d747d99ee76465cfe90ce594fa1f27469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C5=82a=C5=BCej=20Szczygie=C5=82?= Date: Thu, 14 Apr 2016 17:00:23 +0200 Subject: [PATCH 11/20] xcb: Properly process enter/leave events Ignore enter/leave events when there is a window under mouse button. Unset window under mouse button if other window is grabbed. Smarter ignoring (un)grab ancestor enter/leave event. Ignore ungrab inferior leave event. Amends: b9f76db30d261421e4da58f29053181af04ceb4d Task-number: QTBUG-46576 Task-number: QTBUG-51573 Task-number: QTBUG-52332 Task-number: QTBUG-52488 Change-Id: I8d926309aa60bb8929728691c31ecf93d1e299ad Reviewed-by: Dmitry Shachnev Reviewed-by: Laszlo Agocs Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbconnection.cpp | 6 ++ src/plugins/platforms/xcb/qxcbconnection.h | 3 + src/plugins/platforms/xcb/qxcbwindow.cpp | 72 +++++++++++++++----- 3 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 135c763dc1..edfaf2b015 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -560,6 +560,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra , m_buttons(0) , m_focusWindow(0) , m_mouseGrabber(0) + , m_mousePressWindow(0) , m_clientLeader(0) , m_systemTrayTracker(0) , m_glIntegration(Q_NULLPTR) @@ -1367,6 +1368,11 @@ void QXcbConnection::setFocusWindow(QXcbWindow *w) void QXcbConnection::setMouseGrabber(QXcbWindow *w) { m_mouseGrabber = w; + m_mousePressWindow = Q_NULLPTR; +} +void QXcbConnection::setMousePressWindow(QXcbWindow *w) +{ + m_mousePressWindow = w; } void QXcbConnection::grabServer() diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 86af5dc9c5..7ba95887ff 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -475,6 +475,8 @@ public: void setFocusWindow(QXcbWindow *); QXcbWindow *mouseGrabber() const { return m_mouseGrabber; } void setMouseGrabber(QXcbWindow *); + QXcbWindow *mousePressWindow() const { return m_mousePressWindow; } + void setMousePressWindow(QXcbWindow *); QByteArray startupId() const { return m_startupId; } void setStartupId(const QByteArray &nextId) { m_startupId = nextId; } @@ -658,6 +660,7 @@ private: QXcbWindow *m_focusWindow; QXcbWindow *m_mouseGrabber; + QXcbWindow *m_mousePressWindow; xcb_window_t m_clientLeader; QByteArray m_startupId; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index d1c3d7039f..226507f7a0 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -616,8 +616,12 @@ QXcbWindow::~QXcbWindow() { if (window()->type() != Qt::ForeignWindow) destroy(); - else if (connection()->mouseGrabber() == this) - connection()->setMouseGrabber(Q_NULLPTR); + else { + if (connection()->mouseGrabber() == this) + connection()->setMouseGrabber(Q_NULLPTR); + if (connection()->mousePressWindow() == this) + connection()->setMousePressWindow(Q_NULLPTR); + } } void QXcbWindow::destroy() @@ -875,6 +879,16 @@ void QXcbWindow::hide() if (connection()->mouseGrabber() == this) connection()->setMouseGrabber(Q_NULLPTR); + if (QPlatformWindow *w = connection()->mousePressWindow()) { + // Unset mousePressWindow when it (or one of its parents) is unmapped + while (w) { + if (w == this) { + connection()->setMousePressWindow(Q_NULLPTR); + break; + } + w = w->parent(); + } + } m_mapped = false; @@ -2214,6 +2228,8 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in return; } + connection()->setMousePressWindow(this); + handleMouseEvent(timestamp, local, global, modifiers, source); } @@ -2228,19 +2244,44 @@ void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x, return; } + if (connection()->buttons() == Qt::NoButton) + connection()->setMousePressWindow(Q_NULLPTR); + handleMouseEvent(timestamp, local, global, modifiers, source); } -static bool ignoreLeaveEvent(quint8 mode, quint8 detail) +static inline bool doCheckUnGrabAncestor(QXcbConnection *conn) { - return (mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) // Check for AwesomeWM - || detail == XCB_NOTIFY_DETAIL_VIRTUAL - || detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL; + /* Checking for XCB_NOTIFY_MODE_GRAB and XCB_NOTIFY_DETAIL_ANCESTOR prevents unwanted + * enter/leave events on AwesomeWM on mouse button press. It also ignores duplicated + * enter/leave events on Alt+Tab switching on some WMs with XInput2 events. + * Without XInput2 events the (Un)grabAncestor cannot be checked when mouse button is + * not pressed, otherwise (e.g. on Alt+Tab) it can igonre important enter/leave events. + */ + if (conn) { + const bool mouseButtonsPressed = (conn->buttons() != Qt::NoButton); +#ifdef XCB_USE_XINPUT22 + return mouseButtonsPressed || (conn->isAtLeastXI22() && conn->xi2MouseEvents()); +#else + return mouseButtonsPressed; +#endif + } + return true; } -static bool ignoreEnterEvent(quint8 mode, quint8 detail) +static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn = Q_NULLPTR) { - return ((mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) // Check for AwesomeWM + return ((doCheckUnGrabAncestor(conn) + && mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) + || (mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_INFERIOR) + || detail == XCB_NOTIFY_DETAIL_VIRTUAL + || detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL); +} + +static bool ignoreEnterEvent(quint8 mode, quint8 detail, QXcbConnection *conn = Q_NULLPTR) +{ + return ((doCheckUnGrabAncestor(conn) + && mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) || (mode != XCB_NOTIFY_MODE_NORMAL && mode != XCB_NOTIFY_MODE_UNGRAB) || detail == XCB_NOTIFY_DETAIL_VIRTUAL || detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL); @@ -2274,9 +2315,7 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in const QPoint global = QPoint(root_x, root_y); - if (ignoreEnterEvent(mode, detail) - || (connection()->buttons() != Qt::NoButton - && QGuiApplicationPrivate::lastCursorPosition != global)) + if (ignoreEnterEvent(mode, detail, connection()) || connection()->mousePressWindow()) return; const QPoint local(event_x, event_y); @@ -2288,11 +2327,7 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y, { connection()->setTime(timestamp); - const QPoint global(root_x, root_y); - - if (ignoreLeaveEvent(mode, detail) - || (connection()->buttons() != Qt::NoButton - && QGuiApplicationPrivate::lastCursorPosition != global)) + if (ignoreLeaveEvent(mode, detail, connection()) || connection()->mousePressWindow()) return; EnterEventChecker checker; @@ -2315,6 +2350,11 @@ void QXcbWindow::handleMotionNotifyEvent(int event_x, int event_y, int root_x, i { QPoint local(event_x, event_y); QPoint global(root_x, root_y); + + // "mousePressWindow" can be NULL i.e. if a window will be grabbed or umnapped, so set it again here + if (connection()->buttons() != Qt::NoButton && connection()->mousePressWindow() == Q_NULLPTR) + connection()->setMousePressWindow(this); + handleMouseEvent(timestamp, local, global, modifiers, source); } From 21b3e2265a06a6bf45ef63f7da3b9dc609c47c31 Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Fri, 8 Apr 2016 10:46:36 +0300 Subject: [PATCH 12/20] QAbstractSocket:waitForReadyRead(): fix handling UDP Allow sockets in bound state to wait for notifications. Task-number: QTBUG-52449 Change-Id: I5c02bd61db68abca652312d4d59023963b05b3c5 Reviewed-by: Timur Pocheptsov --- src/network/socket/qabstractsocket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index e60c821da6..9fd659376d 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -2150,7 +2150,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs) } do { - if (state() != ConnectedState) + if (state() != ConnectedState && state() != BoundState) return false; bool readyToRead = false; From 84a49594d0bde29668fb66187ac1ef2c842393a3 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 20 Apr 2016 14:09:08 +0200 Subject: [PATCH 13/20] Windows/tst_QTcpServer: Suppress crash notification of crashingServer. Suppress message dialog of the test helper as does QTestlib. Task-number: QTBUG-52714 Change-Id: I5efd7d72f77c7689500ecaccf46f1f9dfb312140 Reviewed-by: Timur Pocheptsov --- .../auto/network/socket/qtcpserver/crashingServer/main.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp b/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp index b53842e6ca..2b00af218a 100644 --- a/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp +++ b/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp @@ -34,9 +34,16 @@ #include #include +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) && defined(Q_CC_MSVC) +# include +#endif int main(int argc, char *argv[]) { + // Windows: Suppress crash notification dialog. +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) && defined(Q_CC_MSVC) + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); +#endif QCoreApplication app(argc, argv); QTcpServer server; From 759b3f49c52c69f0a3ea2df014afbd3259e2bb83 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 20 Apr 2016 09:27:18 +0200 Subject: [PATCH 14/20] OpenGL/contextinfo-Example: Add command line options and status label. Add command line options to be able to set the QCoreApplication attributes that influence Open GL context creation and add a status label at the bottom that displays it besides the QT_OPENGL environment variable. Task-number: QTBUG-52693 Change-Id: Id9793292596e0feb3da5220fde2e5b2e495f87ff Reviewed-by: Laszlo Agocs --- examples/opengl/contextinfo/main.cpp | 9 +++++++++ examples/opengl/contextinfo/widget.cpp | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/examples/opengl/contextinfo/main.cpp b/examples/opengl/contextinfo/main.cpp index 0a75e10b29..8451551b7b 100644 --- a/examples/opengl/contextinfo/main.cpp +++ b/examples/opengl/contextinfo/main.cpp @@ -43,6 +43,15 @@ int main(int argc, char **argv) { + for (int i = 1; i < argc; ++i) { + if (!qstrcmp(argv[i], "-g")) + QCoreApplication::setAttribute(Qt::AA_UseOpenGLES); + else if (!qstrcmp(argv[i], "-s")) + QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL); + else if (!qstrcmp(argv[i], "-d")) + QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL); + } + QApplication app(argc, argv); Widget w; diff --git a/examples/opengl/contextinfo/widget.cpp b/examples/opengl/contextinfo/widget.cpp index 2d36fe4265..fb2caa6796 100644 --- a/examples/opengl/contextinfo/widget.cpp +++ b/examples/opengl/contextinfo/widget.cpp @@ -50,10 +50,12 @@ #include #include #include +#include #include #include #include #include +#include struct Version { const char *str; @@ -225,6 +227,24 @@ Widget::Widget(QWidget *parent) m_renderWindowContainer = new QWidget; addRenderWindow(); + QString description; + QTextStream str(&description); + str << "Qt " << QT_VERSION_STR << ' ' << QGuiApplication::platformName(); + const char *openGlVariables[] = + {"QT_ANGLE_PLATFORM", "QT_OPENGL", "QT_OPENGL_BUGLIST", "QT_OPENGL_DLL"}; + const size_t variableCount = sizeof(openGlVariables) / sizeof(openGlVariables[0]); + for (size_t v = 0; v < variableCount; ++v) { + if (qEnvironmentVariableIsSet(openGlVariables[v])) + str << ' ' << openGlVariables[v] << '=' << qgetenv(openGlVariables[v]); + } + if (QCoreApplication::testAttribute(Qt::AA_UseOpenGLES)) + str << " Qt::AA_UseOpenGLES"; + if (QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL)) + str << " Qt::AA_UseSoftwareOpenGL"; + if (QCoreApplication::testAttribute(Qt::AA_UseDesktopOpenGL)) + str << " Qt::AA_UseSoftwareOpenGL"; + layout->addWidget(new QLabel(description)); + setLayout(layout); } From ab83912c7900805987f7efe38cee2c60baf5f315 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 5 Apr 2016 11:26:20 +0200 Subject: [PATCH 15/20] Windows/QProcess::startDetached(): Fall back to ShellExecuteEx() for UAC prompt. When running a process that requires elevated privileges (such as regedt32 or an installer), the Win32 API CreateProcess fails with error ERROR_ELEVATION_REQUIRED. Fall back to ShellExecuteEx() using the verb "runas" in that case, bringing up the UAC prompt. Task-number: QTBUG-7645 Change-Id: Iee82a86a30f78c5a49246d2c0d4566306f3afc71 Reviewed-by: Oliver Wolff Reviewed-by: Joerg Bornemann --- src/corelib/io/qprocess_win.cpp | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index e7cd9d9a17..7e9cffe129 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -808,8 +809,45 @@ bool QProcessPrivate::waitForWrite(int msecs) return false; } +// Use ShellExecuteEx() to trigger an UAC prompt when CreateProcess()fails +// with ERROR_ELEVATION_REQUIRED. +static bool startDetachedUacPrompt(const QString &programIn, const QStringList &arguments, + const QString &workingDir, qint64 *pid) +{ + typedef BOOL (WINAPI *ShellExecuteExType)(SHELLEXECUTEINFOW *); + + static const ShellExecuteExType shellExecuteEx = // XP ServicePack 1 onwards. + reinterpret_cast(QSystemLibrary::resolve(QLatin1String("shell32"), + "ShellExecuteExW")); + if (!shellExecuteEx) + return false; + + const QString args = qt_create_commandline(QString(), arguments); // needs arguments only + SHELLEXECUTEINFOW shellExecuteExInfo; + memset(&shellExecuteExInfo, 0, sizeof(SHELLEXECUTEINFOW)); + shellExecuteExInfo.cbSize = sizeof(SHELLEXECUTEINFOW); + shellExecuteExInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE | SEE_MASK_FLAG_NO_UI; + shellExecuteExInfo.lpVerb = L"runas"; + const QString program = QDir::toNativeSeparators(programIn); + shellExecuteExInfo.lpFile = reinterpret_cast(program.utf16()); + if (!args.isEmpty()) + shellExecuteExInfo.lpParameters = reinterpret_cast(args.utf16()); + if (!workingDir.isEmpty()) + shellExecuteExInfo.lpDirectory = reinterpret_cast(workingDir.utf16()); + shellExecuteExInfo.nShow = SW_SHOWNORMAL; + + if (!shellExecuteEx(&shellExecuteExInfo)) + return false; + if (pid) + *pid = qint64(GetProcessId(shellExecuteExInfo.hProcess)); + CloseHandle(shellExecuteExInfo.hProcess); + return true; +} + bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir, qint64 *pid) { + static const DWORD errorElevationRequired = 740; + QString args = qt_create_commandline(program, arguments); bool success = false; PROCESS_INFORMATION pinfo; @@ -829,6 +867,8 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a CloseHandle(pinfo.hProcess); if (pid) *pid = pinfo.dwProcessId; + } else if (GetLastError() == errorElevationRequired) { + success = startDetachedUacPrompt(program, arguments, workingDir, pid); } return success; From d9c187b3900b8bf0237e694e3c5287179362257e Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Fri, 15 Apr 2016 12:05:58 +0200 Subject: [PATCH 16/20] winrt: emit application activation Previously the user only got informed about the application getting inactive or hidden, but not when the application was reactivated again. This can cause problems with applications using for instance a camera as that gets disabled when not being active and never return to a active state again. Change-Id: I5c1d8750db8e75043ecf261616a0bc98434a3863 Reviewed-by: Friedemann Kleint Reviewed-by: Andrew Knight Reviewed-by: Oliver Wolff --- src/plugins/platforms/winrt/qwinrtscreen.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index ad89cb005c..7fe8362817 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -1132,6 +1132,8 @@ HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args return S_OK; } + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); + // Activate topWindow if (!d->visibleWindows.isEmpty()) { Qt::FocusReason focusReason = activationState == CoreWindowActivationState_PointerActivated From 16fa29352b7402c82624d6367231f67de836d17e Mon Sep 17 00:00:00 2001 From: David Faure Date: Fri, 22 Apr 2016 13:51:31 +0200 Subject: [PATCH 17/20] QMimeDatabase: fix mimeTypeForUrl for mailto URLs The "path" of a mailto URL isn't a file, so we shouldn't try to do glob-based matching. I was getting application/x-ms-dos-executable for a .com domain and application/x-perl for a .pl domain... Change-Id: Ifc346c3bba83ba1a8476db3202492f4c2e4d52bb Reviewed-by: Friedemann Kleint Reviewed-by: Oswald Buddenhagen Reviewed-by: Thiago Macieira --- src/corelib/mimetypes/qmimedatabase.cpp | 2 +- .../auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/corelib/mimetypes/qmimedatabase.cpp b/src/corelib/mimetypes/qmimedatabase.cpp index fd11dbc787..cf6abbd5cb 100644 --- a/src/corelib/mimetypes/qmimedatabase.cpp +++ b/src/corelib/mimetypes/qmimedatabase.cpp @@ -515,7 +515,7 @@ QMimeType QMimeDatabase::mimeTypeForUrl(const QUrl &url) const return mimeTypeForFile(url.toLocalFile()); const QString scheme = url.scheme(); - if (scheme.startsWith(QLatin1String("http"))) + if (scheme.startsWith(QLatin1String("http")) || scheme == QLatin1String("mailto")) return mimeTypeForName(d->defaultMimeType()); return mimeTypeForFile(url.path()); diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp index 1b4dc020f2..bbc086b048 100644 --- a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp +++ b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp @@ -518,6 +518,8 @@ void tst_QMimeDatabase::mimeTypeForUrl() QVERIFY(db.mimeTypeForUrl(QUrl::fromEncoded("http://foo/bar.png")).isDefault()); // HTTP can't know before downloading QCOMPARE(db.mimeTypeForUrl(QUrl::fromEncoded("ftp://foo/bar.png")).name(), QString::fromLatin1("image/png")); QCOMPARE(db.mimeTypeForUrl(QUrl::fromEncoded("ftp://foo/bar")).name(), QString::fromLatin1("application/octet-stream")); // unknown extension + QCOMPARE(db.mimeTypeForUrl(QUrl("mailto:something@example.com")).name(), QString::fromLatin1("application/octet-stream")); // unknown + QCOMPARE(db.mimeTypeForUrl(QUrl("mailto:something@polish.pl")).name(), QString::fromLatin1("application/octet-stream")); // unknown, NOT perl ;) } void tst_QMimeDatabase::mimeTypeForData_data() From 721d7d383df512bc4dea79b85601d01df576117f Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 14 Apr 2016 22:57:11 -0700 Subject: [PATCH 18/20] QMessagePattern: Fix indentation and use QVector for a large struct struct BacktraceParams is too big (more than one pointer), so using it with QList is inefficient. Let's use QVector instead. Change-Id: Id75834dab9ed466e94c7ffff144572c1eb3fb0e5 Reviewed-by: Marc Mutz Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/global/qlogging.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 86b9597609..6cd2d7914b 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -986,15 +986,18 @@ struct QMessagePattern { #endif #ifdef QLOGGING_HAVE_BACKTRACE struct BacktraceParams { - QString backtraceSeparator; - int backtraceDepth; + QString backtraceSeparator; + int backtraceDepth; }; - QList backtraceArgs; // backtrace argumens in sequence of %{backtrace + QVector backtraceArgs; // backtrace argumens in sequence of %{backtrace #endif bool fromEnvironment; static QBasicMutex mutex; }; +#ifdef QLOGGING_HAVE_BACKTRACE +Q_DECLARE_TYPEINFO(QMessagePattern::BacktraceParams, Q_MOVABLE_TYPE); +#endif QBasicMutex QMessagePattern::mutex; From 2fe10c8dd02c7a9f37a0993f144f7988618943f0 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 4 Nov 2015 15:14:43 +0100 Subject: [PATCH 19/20] QWindowsVistaStyle: Fix CE_MenuBarItem with QStyleSheetStyle. Do not paint over CE_MenuBarItem when the palette is set to transparent by QStyleSheetStyle. Task-number: QTBUG-49115 Change-Id: Ib364017179d0852490daad094361eae0ead4fd5f Reviewed-by: Andy Shaw --- src/widgets/styles/qwindowsvistastyle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/styles/qwindowsvistastyle.cpp b/src/widgets/styles/qwindowsvistastyle.cpp index 5e47c3267f..971fb1be7c 100644 --- a/src/widgets/styles/qwindowsvistastyle.cpp +++ b/src/widgets/styles/qwindowsvistastyle.cpp @@ -1143,7 +1143,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption if (!proxy()->styleHint(SH_UnderlineShortcut, mbi, widget)) alignment |= Qt::TextHideMnemonic; - if (widget) { // Not needed for QtQuick Controls + if (widget && mbi->palette.color(QPalette::Window) != Qt::transparent) { // Not needed for QtQuick Controls //The rect adjustment is a workaround for the menu not really filling its background. XPThemeData theme(widget, painter, QWindowsXPStylePrivate::MenuTheme, From 072f5b513e486e884ea7fa4a1cac9aedf3846374 Mon Sep 17 00:00:00 2001 From: Volker Krause Date: Fri, 22 Apr 2016 11:34:07 +0200 Subject: [PATCH 20/20] Also update filter rules if there is a custom filter installed. This is relevant if the custom filter passes through some categories to the previous one (which might be the default one). In this case changes to the filter rules never took effect. Change-Id: I1a3ab569857d43621ce5df4e690c6e64e6bc7a66 Reviewed-by: Kai Koehne --- src/corelib/io/qloggingregistry.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp index b53e251102..a9ac38c6a6 100644 --- a/src/corelib/io/qloggingregistry.cpp +++ b/src/corelib/io/qloggingregistry.cpp @@ -359,9 +359,6 @@ void QLoggingRegistry::setApiRules(const QString &content) */ void QLoggingRegistry::updateRules() { - if (categoryFilter != defaultCategoryFilter) - return; - rules = qtConfigRules + configRules + apiRules + envRules; foreach (QLoggingCategory *cat, categories.keys())