diff options
Diffstat (limited to 'src/widgets/kernel/qwidgetwindow.cpp')
-rw-r--r-- | src/widgets/kernel/qwidgetwindow.cpp | 169 |
1 files changed, 88 insertions, 81 deletions
diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 7756893369..ce9bb44b45 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -27,9 +27,8 @@ Q_WIDGETS_EXPORT QWidget *qt_button_down = nullptr; // widget got last button-do // popup control QWidget *qt_popup_down = nullptr; // popup that contains the pressed widget -extern int openPopupCount; bool qt_popup_down_closed = false; // qt_popup_down has been closed -bool qt_replay_popup_mouse_event = false; + extern bool qt_try_modal(QWidget *widget, QEvent::Type type); class QWidgetWindowPrivate : public QWindowPrivate @@ -39,21 +38,25 @@ public: void setVisible(bool visible) override { Q_Q(QWidgetWindow); + qCDebug(lcWidgetShowHide) << "Setting visibility of" << q->widget() + << "to" << visible << "via QWidgetWindowPrivate"; + if (QWidget *widget = q->widget()) { - // Check if the widget was already hidden, as this indicates it was done - // explicitly and not because the parent window in this case made it hidden. - // In which case do not automatically show the widget when the parent - // window is shown. - const bool wasExplicitShowHide = widget->testAttribute(Qt::WA_WState_ExplicitShowHide); - const bool wasHidden = widget->testAttribute(Qt::WA_WState_Hidden); - QWidgetPrivate::get(widget)->setVisible(visible); - if (wasExplicitShowHide) { - widget->setAttribute(Qt::WA_WState_ExplicitShowHide, wasExplicitShowHide); - widget->setAttribute(Qt::WA_WState_Hidden, wasHidden); - } - } else { - QWindowPrivate::setVisible(visible); + // If the widget's visible state is already matching the new QWindow + // visible state we assume the widget has already synced up. + if (visible != widget->isVisible()) + QWidgetPrivate::get(widget)->setVisible(visible); } + + // If we end up calling QWidgetPrivate::setVisible() above, we will + // in most cases recurse back into setNativeWindowVisibility() to + // update the QWindow state. But during QWidget::destroy() this is + // not the case, as Qt::WA_WState_Created has been unset by the time + // we check if we should call hide_helper(). We handle this case, as + // well as the cases where we don't call QWidgetPrivate::setVisible(), + // by syncing up the QWindow state here if needed. + if (q->isVisible() != visible) + QWindowPrivate::setVisible(visible); } QWindow *eventReceiver() override { @@ -73,6 +76,39 @@ public: widget->focusWidget()->clearFocus(); } + void setFocusToTarget(FocusTarget target, Qt::FocusReason reason) override + { + Q_Q(QWidgetWindow); + QWidget *widget = q->widget(); + if (!widget) + return; + QWidget *newFocusWidget = nullptr; + + switch (target) { + case FocusTarget::First: + newFocusWidget = q->getFocusWidget(QWidgetWindow::FirstFocusWidget); + break; + case FocusTarget::Last: + newFocusWidget = q->getFocusWidget(QWidgetWindow::LastFocusWidget); + break; + case FocusTarget::Next: { + QWidget *focusWidget = widget->focusWidget() ? widget->focusWidget() : widget; + newFocusWidget = focusWidget->nextInFocusChain() ? focusWidget->nextInFocusChain() : focusWidget; + break; + } + case FocusTarget::Prev: { + QWidget *focusWidget = widget->focusWidget() ? widget->focusWidget() : widget; + newFocusWidget = focusWidget->previousInFocusChain() ? focusWidget->previousInFocusChain() : focusWidget; + break; + } + default: + break; + } + + if (newFocusWidget) + newFocusWidget->setFocus(reason); + } + QRectF closestAcceptableGeometry(const QRectF &rect) const override; void processSafeAreaMarginsChanged() override @@ -124,8 +160,8 @@ QWidgetWindow::QWidgetWindow(QWidget *widget) updateObjectName(); if (!QCoreApplication::testAttribute(Qt::AA_ForceRasterWidgets)) { QSurface::SurfaceType type = QSurface::RasterSurface; - q_evaluateRhiConfig(m_widget, nullptr, &type); - setSurfaceType(type); + if (q_evaluateRhiConfig(m_widget, nullptr, &type)) + setSurfaceType(type); } connect(widget, &QObject::objectNameChanged, this, &QWidgetWindow::updateObjectName); @@ -134,6 +170,21 @@ QWidgetWindow::QWidgetWindow(QWidget *widget) QWidgetWindow::~QWidgetWindow() { + if (!m_widget) + return; + + QTLWExtra *topData = QWidgetPrivate::get(m_widget)->topData(); + Q_ASSERT(topData); + + // The QPlaformBackingStore may hold a reference to the window, + // so the backingstore needs to be deleted first. + topData->repaintManager.reset(nullptr); + delete topData->backingStore; + topData->backingStore = nullptr; + topData->widgetTextures.clear(); + + // Too late to do anything beyond this point + topData->window = nullptr; } #if QT_CONFIG(accessibility) @@ -170,6 +221,9 @@ QObject *QWidgetWindow::focusObject() const void QWidgetWindow::setNativeWindowVisibility(bool visible) { Q_D(QWidgetWindow); + qCDebug(lcWidgetShowHide) << "Setting visibility of" << this + << "to" << visible << "via QWidgetWindow::setNativeWindowVisibility"; + // Call base class setVisible() implementation to run the QWindow // visibility logic. Don't call QWidgetWindowPrivate::setVisible() // since that will recurse back into QWidget code. @@ -450,16 +504,13 @@ void QWidgetWindow::handleNonClientAreaMouseEvent(QMouseEvent *e) void QWidgetWindow::handleMouseEvent(QMouseEvent *event) { - static const QEvent::Type contextMenuTrigger = - QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ContextMenuOnMouseRelease).toBool() ? - QEvent::MouseButtonRelease : QEvent::MouseButtonPress; if (QApplicationPrivate::inPopupMode()) { QPointer<QWidget> activePopupWidget = QApplication::activePopupWidget(); - QPoint mapped = event->position().toPoint(); + QPointF mapped = event->position(); if (activePopupWidget != m_widget) - mapped = activePopupWidget->mapFromGlobal(event->globalPosition().toPoint()); + mapped = activePopupWidget->mapFromGlobal(event->globalPosition()); bool releaseAfter = false; - QWidget *popupChild = activePopupWidget->childAt(mapped); + QWidget *popupChild = activePopupWidget->childAt(mapped.toPoint()); if (activePopupWidget != qt_popup_down) { qt_button_down = nullptr; @@ -480,21 +531,18 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) break; // nothing for mouse move } - int oldOpenPopupCount = openPopupCount; - if (activePopupWidget->isEnabled()) { // deliver event - qt_replay_popup_mouse_event = false; QPointer<QWidget> receiver = activePopupWidget; - QPoint widgetPos = mapped; + QPointF widgetPos = mapped; if (qt_button_down) receiver = qt_button_down; else if (popupChild) receiver = popupChild; if (receiver != activePopupWidget) - widgetPos = receiver->mapFromGlobal(event->globalPosition().toPoint()); + widgetPos = receiver->mapFromGlobal(event->globalPosition()); - const bool reallyUnderMouse = activePopupWidget->rect().contains(mapped); + const bool reallyUnderMouse = activePopupWidget->rect().contains(mapped.toPoint()); const bool underMouse = activePopupWidget->underMouse(); if (underMouse != reallyUnderMouse) { if (reallyUnderMouse) { @@ -536,57 +584,6 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) } } - if (QApplication::activePopupWidget() != activePopupWidget - && qt_replay_popup_mouse_event - && QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::ReplayMousePressOutsidePopup).toBool()) { - if (m_widget->windowType() != Qt::Popup) - qt_button_down = nullptr; - if (event->type() == QEvent::MouseButtonPress) { - // the popup disappeared, replay the mouse press event - QWidget *w = QApplication::widgetAt(event->globalPosition().toPoint()); - if (w && !QApplicationPrivate::isBlockedByModal(w)) { - // activate window of the widget under mouse pointer - if (!w->isActiveWindow()) { - w->activateWindow(); - w->window()->raise(); - } - - if (auto win = qt_widget_private(w)->windowHandle(QWidgetPrivate::WindowHandleMode::Closest)) { - const QRect globalGeometry = win->isTopLevel() - ? win->geometry() - : QRect(win->mapToGlobal(QPoint(0, 0)), win->size()); - if (globalGeometry.contains(event->globalPosition().toPoint())) { - // Use postEvent() to ensure the local QEventLoop terminates when called from QMenu::exec() - const QPoint localPos = win->mapFromGlobal(event->globalPosition().toPoint()); - QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonPress, localPos, localPos, event->globalPosition().toPoint(), - event->button(), event->buttons(), event->modifiers(), event->source()); - QCoreApplicationPrivate::setEventSpontaneous(e, true); - e->setTimestamp(event->timestamp()); - QCoreApplication::postEvent(win, e); - } - } - } - } - qt_replay_popup_mouse_event = false; -#ifndef QT_NO_CONTEXTMENU - } else if (event->type() == contextMenuTrigger - && event->button() == Qt::RightButton - && (openPopupCount == oldOpenPopupCount)) { - QWidget *receiver = activePopupWidget; - if (qt_button_down) - receiver = qt_button_down; - else if (popupChild) - receiver = popupChild; - const QPoint localPos = receiver->mapFromGlobal(event->globalPosition().toPoint()); - QContextMenuEvent e(QContextMenuEvent::Mouse, localPos, event->globalPosition().toPoint(), event->modifiers()); - QApplication::forwardEvent(receiver, &e, event); - } -#else - Q_UNUSED(contextMenuTrigger); - Q_UNUSED(oldOpenPopupCount); - } -#endif - if (releaseAfter) { qt_button_down = nullptr; qt_popup_down_closed = false; @@ -616,6 +613,11 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) if (!receiver) return; + if (d_func()->isPopup() && receiver->window()->windowHandle() != this) { + receiver = widget; + mapped = event->position().toPoint(); + } + if ((event->type() != QEvent::MouseButtonPress) || !QMutableSinglePointEvent::from(event)->isDoubleClick()) { // The preceding statement excludes MouseButtonPress events which caused @@ -629,7 +631,8 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) event->setAccepted(translated.isAccepted()); } #ifndef QT_NO_CONTEXTMENU - if (event->type() == contextMenuTrigger && event->button() == Qt::RightButton + if (event->type() == QGuiApplicationPrivate::contextMenuEventType() + && event->button() == Qt::RightButton && m_widget->rect().contains(event->position().toPoint())) { QContextMenuEvent e(QContextMenuEvent::Mouse, mapped, event->globalPosition().toPoint(), event->modifiers()); QGuiApplication::forwardEvent(receiver, &e, event); @@ -807,6 +810,10 @@ void QWidgetWindow::handleResizeEvent(QResizeEvent *event) void QWidgetWindow::closeEvent(QCloseEvent *event) { Q_D(QWidgetWindow); + if (qt_popup_down == m_widget) { + qt_popup_down = nullptr; + qt_popup_down_closed = true; + } bool accepted = m_widget->d_func()->handleClose(d->inClose ? QWidgetPrivate::CloseWithEvent : QWidgetPrivate::CloseWithSpontaneousEvent); event->setAccepted(accepted); |