diff options
author | Lars Knoll <lars.knoll@qt.io> | 2017-12-30 17:39:21 +0100 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-01-02 09:58:44 +0100 |
commit | 0f315adf9199efcfafa44371464ab6d1fc866774 (patch) | |
tree | 35b67591255624c670aff0579e45b2973f56fd81 /src/widgets | |
parent | 2b0eb3fac319a17dd92903106d501f0f06df871f (diff) | |
parent | 52b85212a2ec8ec5bf187f6cd00b669a45bcf0bd (diff) |
Merge remote-tracking branch 'origin/5.10' into dev
Conflicts:
.qmake.conf
sc/corelib/io/qfsfileengine_p.h
src/corelib/io/qstorageinfo_unix.cpp
src/platformsupport/eglconvenience/qeglpbuffer_p.h
src/platformsupport/input/libinput/qlibinputkeyboard.cpp
src/platformsupport/input/libinput/qlibinputpointer.cpp
src/plugins/platforms/cocoa/qcocoamenu.mm
src/plugins/platforms/ios/qiosscreen.h
src/plugins/platforms/ios/qioswindow.h
src/plugins/platforms/ios/quiview.mm
src/printsupport/dialogs/qpagesetupdialog_unix_p.h
src/printsupport/dialogs/qprintpreviewdialog.cpp
src/printsupport/widgets/qcupsjobwidget_p.h
src/widgets/widgets/qmenu.cpp
tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp
Change-Id: Iecb4883122efe97ef0ed850271e6c51bab568e9c
Diffstat (limited to 'src/widgets')
-rw-r--r-- | src/widgets/dialogs/qfileinfogatherer.cpp | 35 | ||||
-rw-r--r-- | src/widgets/dialogs/qfileinfogatherer_p.h | 3 | ||||
-rw-r--r-- | src/widgets/dialogs/qfilesystemmodel.cpp | 7 | ||||
-rw-r--r-- | src/widgets/dialogs/qwizard_win.cpp | 2 | ||||
-rw-r--r-- | src/widgets/doc/qtwidgets.qdocconf | 4 | ||||
-rw-r--r-- | src/widgets/itemviews/qheaderview.cpp | 23 | ||||
-rw-r--r-- | src/widgets/itemviews/qtreeview.cpp | 3 | ||||
-rw-r--r-- | src/widgets/kernel/qgesturemanager_p.h | 4 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget.cpp | 281 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget_p.h | 10 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetwindow.cpp | 7 | ||||
-rw-r--r-- | src/widgets/styles/qfusionstyle.cpp | 39 | ||||
-rw-r--r-- | src/widgets/styles/qstylesheetstyle.cpp | 2 | ||||
-rw-r--r-- | src/widgets/widgets/qabstractscrollarea.cpp | 25 | ||||
-rw-r--r-- | src/widgets/widgets/qabstractscrollarea_p.h | 1 | ||||
-rw-r--r-- | src/widgets/widgets/qmenu.cpp | 3 | ||||
-rw-r--r-- | src/widgets/widgets/qwidgetresizehandler.cpp | 2 |
17 files changed, 272 insertions, 179 deletions
diff --git a/src/widgets/dialogs/qfileinfogatherer.cpp b/src/widgets/dialogs/qfileinfogatherer.cpp index 710ee611b9..aef13a563f 100644 --- a/src/widgets/dialogs/qfileinfogatherer.cpp +++ b/src/widgets/dialogs/qfileinfogatherer.cpp @@ -196,7 +196,7 @@ void QFileInfoGatherer::fetchExtendedInformation(const QString &path, const QStr */ void QFileInfoGatherer::updateFile(const QString &filePath) { - QString dir = filePath.mid(0, filePath.lastIndexOf(QDir::separator())); + QString dir = filePath.mid(0, filePath.lastIndexOf(QLatin1Char('/'))); QString fileName = filePath.mid(dir.length() + 1); fetchExtendedInformation(dir, QStringList(fileName)); } @@ -267,19 +267,19 @@ QExtendedInformation QFileInfoGatherer::getInfo(const QFileInfo &fileInfo) const info.icon = m_iconProvider->icon(fileInfo); info.displayType = m_iconProvider->type(fileInfo); #ifndef QT_NO_FILESYSTEMWATCHER - // ### Not ready to listen all modifications - #if 0 - // Enable the next two commented out lines to get updates when the file sizes change... + // ### Not ready to listen all modifications by default + static const bool watchFiles = qEnvironmentVariableIsSet("QT_FILESYSTEMMODEL_WATCH_FILES"); + if (watchFiles) { if (!fileInfo.exists() && !fileInfo.isSymLink()) { - info.size = -1; - //watcher->removePath(fileInfo.absoluteFilePath()); + watcher->removePath(fileInfo.absoluteFilePath()); } else { - if (!fileInfo.absoluteFilePath().isEmpty() && fileInfo.exists() && fileInfo.isReadable() - && !watcher->files().contains(fileInfo.absoluteFilePath())) { - //watcher->addPath(fileInfo.absoluteFilePath()); + const QString path = fileInfo.absoluteFilePath(); + if (!path.isEmpty() && fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable() + && !watcher->files().contains(path)) { + watcher->addPath(path); } } - #endif + } #endif #ifdef Q_OS_WIN @@ -329,14 +329,15 @@ void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &fil QVector<QPair<QString, QFileInfo> > updatedFiles; QStringList filesToCheck = files; - QString itPath = QDir::fromNativeSeparators(files.isEmpty() ? path : QLatin1String("")); - QDirIterator dirIt(itPath, QDir::AllEntries | QDir::System | QDir::Hidden); QStringList allFiles; - while (!abort.load() && dirIt.hasNext()) { - dirIt.next(); - fileInfo = dirIt.fileInfo(); - allFiles.append(fileInfo.fileName()); - fetch(fileInfo, base, firstTime, updatedFiles, path); + if (files.isEmpty()) { + QDirIterator dirIt(path, QDir::AllEntries | QDir::System | QDir::Hidden); + while (!abort.load() && dirIt.hasNext()) { + dirIt.next(); + fileInfo = dirIt.fileInfo(); + allFiles.append(fileInfo.fileName()); + fetch(fileInfo, base, firstTime, updatedFiles, path); + } } if (!allFiles.isEmpty()) emit newListOfFiles(path, allFiles); diff --git a/src/widgets/dialogs/qfileinfogatherer_p.h b/src/widgets/dialogs/qfileinfogatherer_p.h index 1e97cc3558..bb13d4eb01 100644 --- a/src/widgets/dialogs/qfileinfogatherer_p.h +++ b/src/widgets/dialogs/qfileinfogatherer_p.h @@ -84,7 +84,8 @@ public: bool operator ==(const QExtendedInformation &fileInfo) const { return mFileInfo == fileInfo.mFileInfo && displayType == fileInfo.displayType - && permissions() == fileInfo.permissions(); + && permissions() == fileInfo.permissions() + && lastModified() == fileInfo.lastModified(); } #ifndef QT_NO_FSFILEENGINE diff --git a/src/widgets/dialogs/qfilesystemmodel.cpp b/src/widgets/dialogs/qfilesystemmodel.cpp index f88ac71cf3..2b79831a74 100644 --- a/src/widgets/dialogs/qfilesystemmodel.cpp +++ b/src/widgets/dialogs/qfilesystemmodel.cpp @@ -260,7 +260,10 @@ QModelIndex QFileSystemModel::index(int row, int column, const QModelIndex &pare Q_ASSERT(parentNode); // now get the internal pointer for the index - const QString &childName = parentNode->visibleChildren.at(d->translateVisibleLocation(parentNode, row)); + const int i = d->translateVisibleLocation(parentNode, row); + if (i >= parentNode->visibleChildren.size()) + return QModelIndex(); + const QString &childName = parentNode->visibleChildren.at(i); const QFileSystemModelPrivate::QFileSystemNode *indexNode = parentNode->children.value(childName); Q_ASSERT(indexNode); @@ -744,7 +747,7 @@ QVariant QFileSystemModel::data(const QModelIndex &index, int role) const break; case Qt::TextAlignmentRole: if (index.column() == 1) - return Qt::AlignRight; + return QVariant(Qt::AlignTrailing | Qt::AlignVCenter); break; case FilePermissions: int p = permissions(index); diff --git a/src/widgets/dialogs/qwizard_win.cpp b/src/widgets/dialogs/qwizard_win.cpp index 6ca4541980..e7b4870e35 100644 --- a/src/widgets/dialogs/qwizard_win.cpp +++ b/src/widgets/dialogs/qwizard_win.cpp @@ -260,7 +260,7 @@ static bool getCaptionQFont(int dpi, QFont *result) QPlatformNativeInterface *ni = QGuiApplication::platformNativeInterface(); return ni && QMetaObject::invokeMethod(ni, "logFontToQFont", Qt::DirectConnection, Q_RETURN_ARG(QFont, *result), - Q_ARG(const void *, &logFont), + Q_ARG(const void*, &logFont), Q_ARG(int, dpi)); } diff --git a/src/widgets/doc/qtwidgets.qdocconf b/src/widgets/doc/qtwidgets.qdocconf index a49eb439af..88957b0f94 100644 --- a/src/widgets/doc/qtwidgets.qdocconf +++ b/src/widgets/doc/qtwidgets.qdocconf @@ -48,4 +48,6 @@ imagedirs += images \ navigation.landingpage = "Qt Widgets" navigation.cppclassespage = "Qt Widgets C++ Classes" manifestmeta.highlighted.names = "QtWidgets/Calendar Widget Example" \ - "QtWidgets/Simple Tree Model Example" + "QtWidgets/Editable Tree Model Example" \ + "QtWidgets/Address Book Example" \ + "QtWidgets/Application Example" diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index abd5997ea1..3555c276ac 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -2331,18 +2331,20 @@ void QHeaderView::paintEvent(QPaintEvent *e) d->prepareSectionSelected(); // clear and resize the bit array QRect currentSectionRect; - int logical; const int width = d->viewport->width(); const int height = d->viewport->height(); + const int rtlHorizontalOffset = d->reverse() ? 1 : 0; for (int i = start; i <= end; ++i) { if (d->isVisualIndexHidden(i)) continue; painter.save(); - logical = logicalIndex(i); + const int logical = logicalIndex(i); if (d->orientation == Qt::Horizontal) { - currentSectionRect.setRect(sectionViewportPosition(logical), 0, sectionSize(logical), height); + currentSectionRect.setRect(sectionViewportPosition(logical) + rtlHorizontalOffset, + 0, sectionSize(logical), height); } else { - currentSectionRect.setRect(0, sectionViewportPosition(logical), width, sectionSize(logical)); + currentSectionRect.setRect(0, sectionViewportPosition(logical), + width, sectionSize(logical)); } currentSectionRect.translate(offset); @@ -2800,9 +2802,9 @@ void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logical if (first && last) opt.position = QStyleOptionHeader::OnlyOneSection; else if (first) - opt.position = QStyleOptionHeader::Beginning; + opt.position = d->reverse() ? QStyleOptionHeader::End : QStyleOptionHeader::Beginning; else if (last) - opt.position = QStyleOptionHeader::End; + opt.position = d->reverse() ? QStyleOptionHeader::Beginning : QStyleOptionHeader::End; else opt.position = QStyleOptionHeader::Middle; opt.orientation = d->orientation; @@ -3181,6 +3183,15 @@ void QHeaderViewPrivate::setupSectionIndicator(int section, int position) QRect rect(0, 0, w, h); QPainter painter(&pm); + const QVariant variant = model->headerData(section, orientation, + Qt::FontRole); + if (variant.isValid() && variant.canConvert<QFont>()) { + const QFont sectionFont = qvariant_cast<QFont>(variant); + painter.setFont(sectionFont); + } else { + painter.setFont(q->font()); + } + painter.setOpacity(0.75); q->paintSection(&painter, rect, section); painter.end(); diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp index 6ea180dcf2..03e0441390 100644 --- a/src/widgets/itemviews/qtreeview.cpp +++ b/src/widgets/itemviews/qtreeview.cpp @@ -237,9 +237,6 @@ void QTreeView::setModel(QAbstractItemModel *model) // QAbstractItemView connects to a private slot disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(_q_rowsRemoved(QModelIndex,int,int))); - // do header layout after the tree - disconnect(d->model, SIGNAL(layoutChanged()), - d->header, SLOT(_q_layoutChanged())); // QTreeView has a public slot for this connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(rowsRemoved(QModelIndex,int,int))); diff --git a/src/widgets/kernel/qgesturemanager_p.h b/src/widgets/kernel/qgesturemanager_p.h index e57652afba..3df80bab55 100644 --- a/src/widgets/kernel/qgesturemanager_p.h +++ b/src/widgets/kernel/qgesturemanager_p.h @@ -59,6 +59,8 @@ #ifndef QT_NO_GESTURES +#include <functional> + QT_BEGIN_NAMESPACE class QBasicTimer; @@ -112,7 +114,7 @@ private: ObjectGesture(QObject *o, const Qt::GestureType &g) : object(o), gesture(g) { } inline bool operator<(const ObjectGesture &rhs) const { - if (object < rhs.object) + if (std::less<QObject *>{}(object, rhs.object)) return true; if (object == rhs.object) return gesture < rhs.gesture; diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index c5eea1c514..5eab2d1038 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -126,15 +126,6 @@ QT_BEGIN_NAMESPACE -static bool qt_enable_backingstore = true; -#if 0 // Used to be included in Qt4 for Q_WS_X11 -// for compatibility with Qt 4.0 -Q_WIDGETS_EXPORT void qt_x11_set_global_double_buffer(bool enable) -{ - qt_enable_backingstore = enable; -} -#endif - #if 0 // Used to be included in Qt4 for Q_WS_MAC bool qt_mac_clearDirtyOnWidgetInsideDrawWidget = false; #endif @@ -145,11 +136,6 @@ static inline bool qRectIntersects(const QRect &r1, const QRect &r2) qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom())); } -static inline bool hasBackingStoreSupport() -{ - return true; -} - #if 0 // Used to be included in Qt4 for Q_WS_MAC # define QT_NO_PAINT_DEBUG #endif @@ -1200,6 +1186,7 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f) q->setAttribute(Qt::WA_QuitOnClose); // might be cleared in adjustQuitOnCloseAttribute() adjustQuitOnCloseAttribute(); + q->setAttribute(Qt::WA_ContentsMarginsRespectsSafeArea); q->setAttribute(Qt::WA_WState_Hidden); //give potential windows a bigger "pre-initial" size; create_sys() will give them a new size later @@ -1352,8 +1339,7 @@ void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow) // a real toplevel window needs a backing store if (isWindow() && windowType() != Qt::Desktop) { d->topData()->backingStoreTracker.destroy(); - if (hasBackingStoreSupport()) - d->topData()->backingStoreTracker.create(this); + d->topData()->backingStoreTracker.create(this); } d->setModal_sys(); @@ -1425,8 +1411,6 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO Q_UNUSED(initializeWindow); Q_UNUSED(destroyOldWindow); - Qt::WindowFlags flags = data.window_flags; - if (!q->testAttribute(Qt::WA_NativeWindow) && !q->isWindow()) return; // we only care about real toplevels @@ -1444,12 +1428,19 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO win->setProperty(propertyName, q->property(propertyName)); } + Qt::WindowFlags &flags = data.window_flags; + +#if defined(Q_OS_IOS) || defined(Q_OS_TVOS) + if (q->testAttribute(Qt::WA_ContentsMarginsRespectsSafeArea)) + flags |= Qt::MaximizeUsingFullscreenGeometryHint; +#endif + if (q->testAttribute(Qt::WA_ShowWithoutActivating)) win->setProperty("_q_showWithoutActivating", QVariant(true)); if (q->testAttribute(Qt::WA_MacAlwaysShowToolWindow)) win->setProperty("_q_macAlwaysShowToolWindow", QVariant(true)); setNetWmWindowTypes(true); // do nothing if none of WA_X11NetWmWindowType* is set - win->setFlags(data.window_flags); + win->setFlags(flags); fixPosIncludesFrame(); if (q->testAttribute(Qt::WA_Moved) || !QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowManagement)) @@ -2312,7 +2303,7 @@ bool QWidgetPrivate::paintOnScreen() const return true; } - return !qt_enable_backingstore; + return false; #endif } @@ -5490,11 +5481,11 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP setSystemClip(pdev->paintEngine(), pdev->devicePixelRatioF(), rgn.translated(offset)); QPainter p(pdev); p.translate(offset); - context.painter = &p; + context.painter = context.sharedPainter = &p; graphicsEffect->draw(&p); setSystemClip(pdev->paintEngine(), 1, QRegion()); } else { - context.painter = sharedPainter; + context.painter = context.sharedPainter = sharedPainter; if (sharedPainter->worldTransform() != sourced->lastEffectTransform) { sourced->invalidateCache(); sourced->lastEffectTransform = sharedPainter->worldTransform(); @@ -5980,9 +5971,9 @@ void QWidgetPrivate::resolveLocale() Q_Q(const QWidget); if (!q->testAttribute(Qt::WA_SetLocale)) { - setLocale_helper(q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation) - ? QLocale() - : q->parentWidget()->locale()); + QWidget *parent = q->parentWidget(); + setLocale_helper(!parent || (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation)) + ? QLocale() : parent->locale()); } } @@ -7585,21 +7576,7 @@ void QWidget::setContentsMargins(int left, int top, int right, int bottom) d->rightmargin = right; d->bottommargin = bottom; - if (QLayout *l=d->layout) - l->update(); //force activate; will do updateGeometry - else - updateGeometry(); - - if (isVisible()) { - update(); - QResizeEvent e(data->crect.size(), data->crect.size()); - QApplication::sendEvent(this, &e); - } else { - setAttribute(Qt::WA_PendingResizeEvent, true); - } - - QEvent e(QEvent::ContentsRectChange); - QApplication::sendEvent(this, &e); + d->updateContentsRect(); } /*! @@ -7624,6 +7601,27 @@ void QWidget::setContentsMargins(const QMargins &margins) margins.right(), margins.bottom()); } +void QWidgetPrivate::updateContentsRect() +{ + Q_Q(QWidget); + + if (layout) + layout->update(); //force activate; will do updateGeometry + else + q->updateGeometry(); + + if (q->isVisible()) { + q->update(); + QResizeEvent e(q->data->crect.size(), q->data->crect.size()); + QApplication::sendEvent(q, &e); + } else { + q->setAttribute(Qt::WA_PendingResizeEvent, true); + } + + QEvent e(QEvent::ContentsRectChange); + QApplication::sendEvent(q, &e); +} + /*! Returns the widget's contents margins for \a left, \a top, \a right, and \a bottom. @@ -7632,15 +7630,22 @@ void QWidget::setContentsMargins(const QMargins &margins) */ void QWidget::getContentsMargins(int *left, int *top, int *right, int *bottom) const { - Q_D(const QWidget); + QMargins m = contentsMargins(); if (left) - *left = d->leftmargin; + *left = m.left(); if (top) - *top = d->topmargin; + *top = m.top(); if (right) - *right = d->rightmargin; + *right = m.right(); if (bottom) - *bottom = d->bottommargin; + *bottom = m.bottom(); +} + +// FIXME: Move to qmargins.h for next minor Qt release +QMargins operator|(const QMargins &m1, const QMargins &m2) +{ + return QMargins(qMax(m1.left(), m2.left()), qMax(m1.top(), m2.top()), + qMax(m1.right(), m2.right()), qMax(m1.bottom(), m2.bottom())); } /*! @@ -7653,10 +7658,11 @@ void QWidget::getContentsMargins(int *left, int *top, int *right, int *bottom) c QMargins QWidget::contentsMargins() const { Q_D(const QWidget); - return QMargins(d->leftmargin, d->topmargin, d->rightmargin, d->bottommargin); + QMargins userMargins(d->leftmargin, d->topmargin, d->rightmargin, d->bottommargin); + return testAttribute(Qt::WA_ContentsMarginsRespectsSafeArea) ? + userMargins | d->safeAreaMargins() : userMargins; } - /*! Returns the area inside the widget's margins. @@ -7664,14 +7670,87 @@ QMargins QWidget::contentsMargins() const */ QRect QWidget::contentsRect() const { - Q_D(const QWidget); - return QRect(QPoint(d->leftmargin, d->topmargin), - QPoint(data->crect.width() - 1 - d->rightmargin, - data->crect.height() - 1 - d->bottommargin)); - + return rect() - contentsMargins(); } +QMargins QWidgetPrivate::safeAreaMargins() const +{ + Q_Q(const QWidget); + QWidget *nativeWidget = q->window(); + if (!nativeWidget->windowHandle()) + return QMargins(); + + QPlatformWindow *platformWindow = nativeWidget->windowHandle()->handle(); + if (!platformWindow) + return QMargins(); + QMargins safeAreaMargins = platformWindow->safeAreaMargins(); + + if (!q->isWindow()) { + // In theory the native parent widget already has a contents rect reflecting + // the safe area of that widget, but we can't be sure that the widget or child + // widgets of that widget have respected the contents rect when setting their + // geometry, so we need to manually compute the safe area. + + // Unless the native widget doesn't have any margins, in which case there's + // nothing for us to compute. + if (safeAreaMargins.isNull()) + return QMargins(); + + // Or, if one of our ancestors are in a layout that does not have WA_LayoutOnEntireRect + // set, then we know that the layout has already taken care of placing us inside the + // safe area, by taking the contents rect of its parent widget into account. + const QWidget *assumedSafeWidget = nullptr; + for (const QWidget *w = q; w != nativeWidget; w = w->parentWidget()) { + QWidget *parentWidget = w->parentWidget(); + if (parentWidget->testAttribute(Qt::WA_LayoutOnEntireRect)) + continue; // Layout not going to help us + + QLayout *layout = parentWidget->layout(); + if (!layout) + continue; + + if (layout->geometry().isNull()) + continue; // Layout hasn't been activated yet + + if (layout->indexOf(const_cast<QWidget *>(w)) < 0) + continue; // Widget is not in layout + + assumedSafeWidget = w; + break; + } + +#if !defined(QT_DEBUG) + if (assumedSafeWidget) { + // We found a layout that we assume will take care of keeping us within the safe area + // For debug builds we still map the safe area using the fallback logic, so that we + // can detect any misbehaving layouts. + return QMargins(); + } +#endif + + // In all other cases we need to map the safe area of the native parent to the widget. + // This depends on the widget being positioned and sized already, which means the initial + // layout will be wrong, but the layout will then adjust itself. + QPoint topLeftMargins = q->mapFrom(nativeWidget, QPoint(safeAreaMargins.left(), safeAreaMargins.top())); + QRect widgetRect = q->isVisible() ? q->visibleRegion().boundingRect() : q->rect(); + QPoint bottomRightMargins = widgetRect.bottomRight() - q->mapFrom(nativeWidget, + nativeWidget->rect().bottomRight() - QPoint(safeAreaMargins.right(), safeAreaMargins.bottom())); + + // Margins should never be negative + safeAreaMargins = QMargins(qMax(0, topLeftMargins.x()), qMax(0, topLeftMargins.y()), + qMax(0, bottomRightMargins.x()), qMax(0, bottomRightMargins.y())); + + if (!safeAreaMargins.isNull() && assumedSafeWidget) { + QLayout *layout = assumedSafeWidget->parentWidget()->layout(); + qWarning() << layout << "is laying out" << assumedSafeWidget + << "outside of the contents rect of" << layout->parentWidget(); + return QMargins(); // Return empty margin to visually highlight the error + } + } + + return safeAreaMargins; +} /*! \fn void QWidget::customContextMenuRequested(const QPoint &pos) @@ -10931,25 +11010,7 @@ void QWidget::repaint(int x, int y, int w, int h) void QWidget::repaint(const QRect &rect) { Q_D(QWidget); - - if (testAttribute(Qt::WA_WState_ConfigPending)) { - update(rect); - return; - } - - if (!isVisible() || !updatesEnabled() || rect.isEmpty()) - return; - - if (hasBackingStoreSupport()) { - QTLWExtra *tlwExtra = window()->d_func()->maybeTopData(); - if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) { - tlwExtra->inRepaint = true; - tlwExtra->backingStoreTracker->markDirty(rect, this, QWidgetBackingStore::UpdateNow); - tlwExtra->inRepaint = false; - } - } else { - d->repaint_sys(rect); - } + d->repaint(rect); } /*! @@ -10960,24 +11021,22 @@ void QWidget::repaint(const QRect &rect) void QWidget::repaint(const QRegion &rgn) { Q_D(QWidget); + d->repaint(rgn); +} - if (testAttribute(Qt::WA_WState_ConfigPending)) { - update(rgn); - return; - } +template <typename T> +void QWidgetPrivate::repaint(T r) +{ + Q_Q(QWidget); - if (!isVisible() || !updatesEnabled() || rgn.isEmpty()) + if (!q->isVisible() || !q->updatesEnabled() || r.isEmpty()) return; - if (hasBackingStoreSupport()) { - QTLWExtra *tlwExtra = window()->d_func()->maybeTopData(); - if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) { - tlwExtra->inRepaint = true; - tlwExtra->backingStoreTracker->markDirty(rgn, this, QWidgetBackingStore::UpdateNow); - tlwExtra->inRepaint = false; - } - } else { - d->repaint_sys(rgn); + QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); + if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) { + tlwExtra->inRepaint = true; + tlwExtra->backingStoreTracker->markDirty(r, q, QWidgetBackingStore::UpdateNow); + tlwExtra->inRepaint = false; } } @@ -11018,26 +11077,8 @@ void QWidget::update() */ void QWidget::update(const QRect &rect) { - if (!isVisible() || !updatesEnabled()) - return; - - QRect r = rect & QWidget::rect(); - - if (r.isEmpty()) - return; - - if (testAttribute(Qt::WA_WState_InPaintEvent)) { - QApplication::postEvent(this, new QUpdateLaterEvent(r)); - return; - } - - if (hasBackingStoreSupport()) { - QTLWExtra *tlwExtra = window()->d_func()->maybeTopData(); - if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) - tlwExtra->backingStoreTracker->markDirty(r, this); - } else { - d_func()->repaint_sys(r); - } + Q_D(QWidget); + d->update(rect); } /*! @@ -11047,29 +11088,33 @@ void QWidget::update(const QRect &rect) */ void QWidget::update(const QRegion &rgn) { - if (!isVisible() || !updatesEnabled()) + Q_D(QWidget); + d->update(rgn); +} + +template <typename T> +void QWidgetPrivate::update(T r) +{ + Q_Q(QWidget); + + if (!q->isVisible() || !q->updatesEnabled()) return; - QRegion r = rgn & QWidget::rect(); + T clipped = r & q->rect(); - if (r.isEmpty()) + if (clipped.isEmpty()) return; - if (testAttribute(Qt::WA_WState_InPaintEvent)) { - QApplication::postEvent(this, new QUpdateLaterEvent(r)); + if (q->testAttribute(Qt::WA_WState_InPaintEvent)) { + QApplication::postEvent(q, new QUpdateLaterEvent(clipped)); return; } - if (hasBackingStoreSupport()) { - QTLWExtra *tlwExtra = window()->d_func()->maybeTopData(); - if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) - tlwExtra->backingStoreTracker->markDirty(r, this); - } else { - d_func()->repaint_sys(r); - } + QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); + if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) + tlwExtra->backingStoreTracker->markDirty(clipped, q); } - /*! \internal diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index 26f8b53392..a9c73c6a26 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -344,6 +344,13 @@ public: void setSharedPainter(QPainter *painter); QWidgetBackingStore *maybeBackingStore() const; QWidgetWindow *windowHandle() const; + + template <typename T> + void repaint(T t); + + template <typename T> + void update(T t); + void init(QWidget *desktopWidget, Qt::WindowFlags f); void create_sys(WId window, bool initializeWindow, bool destroyOldWindow); void createRecursively(); @@ -516,6 +523,9 @@ public: void setLayoutItemMargins(int left, int top, int right, int bottom); void setLayoutItemMargins(QStyle::SubElement element, const QStyleOption *opt = 0); + void updateContentsRect(); + QMargins safeAreaMargins() const; + // aboutToDestroy() is called just before the contents of // QWidget::destroy() is executed. It's used to signal QWidget // sub-classes that their internals are about to be released. diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index ac32c32e12..d5a18b525b 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -99,6 +99,13 @@ public: #if QT_CONFIG(opengl) QOpenGLContext *shareContext() const override; #endif + + void processSafeAreaMarginsChanged() override + { + Q_Q(QWidgetWindow); + if (QWidget *widget = q->widget()) + QWidgetPrivate::get(widget)->updateContentsRect(); + } }; QRectF QWidgetWindowPrivate::closestAcceptableGeometry(const QRectF &rect) const diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index c01fb9e0db..80196a39a2 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -763,7 +763,7 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, painter->drawRect(rect); QColor checkMarkColor = option->palette.text().color().darker(120); - const int checkMarkPadding = QStyleHelper::dpiScaled(3); + const int checkMarkPadding = 1 + rect.width() * 0.2; // at least one pixel padding if (checkbox->state & State_NoChange) { gradient = QLinearGradient(rect.topLeft(), rect.bottomLeft()); @@ -777,18 +777,20 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, painter->drawRect(rect.adjusted(checkMarkPadding, checkMarkPadding, -checkMarkPadding, -checkMarkPadding)); } else if (checkbox->state & (State_On)) { - QPen checkPen = QPen(checkMarkColor, QStyleHelper::dpiScaled(1.8)); + qreal penWidth = QStyleHelper::dpiScaled(1.8); + penWidth = qMax(penWidth , 0.18 * rect.height()); + penWidth = qMin(penWidth , 0.30 * rect.height()); + QPen checkPen = QPen(checkMarkColor, penWidth); checkMarkColor.setAlpha(210); - painter->translate(-1, 0.5); + painter->translate(-0.8, 0.5); painter->setPen(checkPen); painter->setBrush(Qt::NoBrush); - painter->translate(0.2, 0.0); // Draw checkmark QPainterPath path; - path.moveTo(2 + checkMarkPadding, rect.height() / 2.0); + path.moveTo(1.33 * checkMarkPadding, rect.height() / 2.0); path.lineTo(rect.width() / 2.0, rect.height() - checkMarkPadding); - path.lineTo(rect.width() - checkMarkPadding - 0.5, checkMarkPadding); + path.lineTo(rect.width() - checkMarkPadding * 0.92, checkMarkPadding); painter->drawPath(path.translated(rect.topLeft())); } } @@ -1558,9 +1560,9 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio bool enabled = menuItem->state & State_Enabled; bool ignoreCheckMark = false; - int checkcol = qMax<int>(menuItem->maxIconWidth, QStyleHelper::dpiScaled(20)); - const int margin = QStyleHelper::dpiScaled(4); - + const int checkColHOffset = windowsItemHMargin + windowsItemFrame - 1; + int checkcol = qMax(menuItem->rect.height() * 0.7, + qMax(menuItem->maxIconWidth * 1.0, dpiScaled(17))); // icon checkbox's highlihgt column width if ( #if QT_CONFIG(combobox) qobject_cast<const QComboBox*>(widget) || @@ -1570,10 +1572,9 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio if (!ignoreCheckMark) { // Check - const int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget); - const int indicatorHeight = proxy()->pixelMetric(PM_IndicatorHeight, option, widget); - QRect checkRect(option->rect.left() + indicatorWidth / 2, - option->rect.center().y() - indicatorHeight / 2 + 1, indicatorWidth, indicatorHeight); + const int boxMargin = dpiScaled(4); + const int boxWidth = checkcol - 2 * boxMargin; + QRect checkRect(option->rect.left() + boxMargin + checkColHOffset, option->rect.center().y() - boxWidth/2 + 1, boxWidth, boxWidth); checkRect = visualRect(menuItem->direction, menuItem->rect, checkRect); if (checkable) { if (menuItem->checkType & QStyleOptionMenuItem::Exclusive) { @@ -1585,7 +1586,8 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio QPalette::ColorRole textRole = !enabled ? QPalette::Text: selected ? QPalette::HighlightedText : QPalette::ButtonText; painter->setBrush(option->palette.brush( option->palette.currentColorGroup(), textRole)); - painter->drawEllipse(checkRect.adjusted(margin, margin, -margin, -margin)); + const int adjustment = checkRect.height() * 0.3; + painter->drawEllipse(checkRect.adjusted(adjustment, adjustment, -adjustment, -adjustment)); } } else { // Check box @@ -1614,7 +1616,7 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio QPainter *p = painter; QRect vCheckRect = visualRect(opt->direction, menuitem->rect, - QRect(menuitem->rect.x() + margin, menuitem->rect.y(), + QRect(menuitem->rect.x() + checkColHOffset, menuitem->rect.y(), checkcol, menuitem->rect.height())); if (!menuItem->icon.isNull()) { QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal; @@ -1665,11 +1667,10 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio discol = menuitem->palette.text().color(); p->setPen(discol); } - const int lm = QStyleHelper::dpiScaled(windowsItemFrame + windowsItemHMargin + 2) + checkcol; - const int rm = QStyleHelper::dpiScaled(windowsRightBorder + 1) + tab; - const int xpos = menuitem->rect.x() + lm; + int xm = checkColHOffset + checkcol + windowsItemHMargin; + int xpos = menuitem->rect.x() + xm; - QRect textRect(xpos, y + windowsItemVMargin, w - lm - rm, h - 2 * windowsItemVMargin); + QRect textRect(xpos, y + windowsItemVMargin, w - xm - windowsRightBorder - tab + 1, h - 2 * windowsItemVMargin); QRect vTextRect = visualRect(opt->direction, menuitem->rect, textRect); QStringRef s(&menuitem->text); if (!s.isEmpty()) { // draw text diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 4e4576940a..14f81afe83 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -3657,7 +3657,7 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q if ((pseudo == PseudoElement_MenuSeparator) && subRule.hasDrawable()) { subRule.drawRule(p, opt->rect); } else if ((pseudo == PseudoElement_Item) - && (allRules.hasBox() || allRules.hasBorder() + && (allRules.hasBox() || allRules.hasBorder() || subRule.hasFont || (allRules.background() && !allRules.background()->pixmap.isNull()))) { subRule.drawRule(p, opt->rect); if (subRule.hasBackground()) { diff --git a/src/widgets/widgets/qabstractscrollarea.cpp b/src/widgets/widgets/qabstractscrollarea.cpp index 249ebd35d3..c6d66bafd4 100644 --- a/src/widgets/widgets/qabstractscrollarea.cpp +++ b/src/widgets/widgets/qabstractscrollarea.cpp @@ -334,16 +334,27 @@ void QAbstractScrollAreaPrivate::setSingleFingerPanEnabled(bool on) void QAbstractScrollAreaPrivate::layoutChildren() { + bool needH = false; + bool needV = false; + layoutChildren_helper(&needH, &needV); + // Call a second time if one scrollbar was needed and not the other to + // check if it needs to readjust accordingly + if (needH != needV) + layoutChildren_helper(&needH, &needV); +} + +void QAbstractScrollAreaPrivate::layoutChildren_helper(bool *needHorizontalScrollbar, bool *needVerticalScrollbar) +{ Q_Q(QAbstractScrollArea); bool htransient = hbar->style()->styleHint(QStyle::SH_ScrollBar_Transient, 0, hbar); - bool needh = (hbarpolicy != Qt::ScrollBarAlwaysOff) && ((hbarpolicy == Qt::ScrollBarAlwaysOn && !htransient) - || ((hbarpolicy == Qt::ScrollBarAsNeeded || htransient) - && hbar->minimum() < hbar->maximum() && !hbar->sizeHint().isEmpty())); + bool needh = *needHorizontalScrollbar || ((hbarpolicy != Qt::ScrollBarAlwaysOff) && ((hbarpolicy == Qt::ScrollBarAlwaysOn && !htransient) + || ((hbarpolicy == Qt::ScrollBarAsNeeded || htransient) + && hbar->minimum() < hbar->maximum() && !hbar->sizeHint().isEmpty()))); bool vtransient = vbar->style()->styleHint(QStyle::SH_ScrollBar_Transient, 0, vbar); - bool needv = (vbarpolicy != Qt::ScrollBarAlwaysOff) && ((vbarpolicy == Qt::ScrollBarAlwaysOn && !vtransient) - || ((vbarpolicy == Qt::ScrollBarAsNeeded || vtransient) - && vbar->minimum() < vbar->maximum() && !vbar->sizeHint().isEmpty())); + bool needv = *needVerticalScrollbar || ((vbarpolicy != Qt::ScrollBarAlwaysOff) && ((vbarpolicy == Qt::ScrollBarAlwaysOn && !vtransient) + || ((vbarpolicy == Qt::ScrollBarAsNeeded || vtransient) + && vbar->minimum() < vbar->maximum() && !vbar->sizeHint().isEmpty()))); QStyleOption opt(0); opt.init(q); @@ -522,6 +533,8 @@ void QAbstractScrollAreaPrivate::layoutChildren() viewportRect.adjust(left, top, -right, -bottom); viewport->setGeometry(QStyle::visualRect(opt.direction, opt.rect, viewportRect)); // resize the viewport last + *needHorizontalScrollbar = needh; + *needVerticalScrollbar = needv; } /*! diff --git a/src/widgets/widgets/qabstractscrollarea_p.h b/src/widgets/widgets/qabstractscrollarea_p.h index 251e563724..732a2ab40d 100644 --- a/src/widgets/widgets/qabstractscrollarea_p.h +++ b/src/widgets/widgets/qabstractscrollarea_p.h @@ -95,6 +95,7 @@ public: void init(); void layoutChildren(); + void layoutChildren_helper(bool *needHorizontalScrollbar, bool *needVerticalScrollbar); // ### Fix for 4.4, talk to Bjoern E or Girish. virtual void scrollBarPolicyChanged(Qt::Orientation, Qt::ScrollBarPolicy) {} bool canStartScrollingAt( const QPoint &startPos ); diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index 64c4fc5666..4796ed43d3 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -902,8 +902,7 @@ void QMenuPrivate::adjustMenuScreen(const QPoint &p) // The windowHandle must point to the screen where the menu will be shown. // The (item) size calculations depend on the menu screen, // so a wrong screen would often cause wrong sizes (on high DPI) - const QScreen *primaryScreen = QApplication::primaryScreen(); - const QScreen *currentScreen = q->windowHandle() ? q->windowHandle()->screen() : primaryScreen; + const QScreen *currentScreen = q->windowHandle() ? q->windowHandle()->screen() : nullptr; QScreen *actualScreen = QGuiApplication::screenAt(p); if (actualScreen && currentScreen != actualScreen) { if (!q->windowHandle()) // Try to create a window handle if not created. diff --git a/src/widgets/widgets/qwidgetresizehandler.cpp b/src/widgets/widgets/qwidgetresizehandler.cpp index d4f14ad1d4..45010d1768 100644 --- a/src/widgets/widgets/qwidgetresizehandler.cpp +++ b/src/widgets/widgets/qwidgetresizehandler.cpp @@ -121,7 +121,7 @@ bool QWidgetResizeHandler::eventFilter(QObject *o, QEvent *ee) break; const QRect widgetRect = widget->rect().marginsAdded(QMargins(range, range, range, range)); const QPoint cursorPoint = widget->mapFromGlobal(e->globalPos()); - if (!widgetRect.contains(cursorPoint) || mode == Center || mode == Nowhere) + if (!widgetRect.contains(cursorPoint) || mode == Nowhere) return false; if (e->button() == Qt::LeftButton) { #if 0 // Used to be included in Qt4 for Q_WS_X11 |