summaryrefslogtreecommitdiffstats
path: root/src/widgets/kernel/qwidgetwindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/kernel/qwidgetwindow.cpp')
-rw-r--r--src/widgets/kernel/qwidgetwindow.cpp463
1 files changed, 264 insertions, 199 deletions
diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp
index 904067afda..c5b045c8db 100644
--- a/src/widgets/kernel/qwidgetwindow.cpp
+++ b/src/widgets/kernel/qwidgetwindow.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qwindow_p.h"
#include "qwidgetwindow_p.h"
@@ -43,7 +7,7 @@
#include "private/qwidget_p.h"
#include "private/qapplication_p.h"
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
#include <QtGui/qaccessible.h>
#endif
#include <private/qwidgetrepaintmanager_p.h>
@@ -55,6 +19,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
Q_WIDGETS_EXPORT extern bool qt_tab_all_widgets();
Q_WIDGETS_EXPORT QWidget *qt_button_down = nullptr; // widget got last button-down
@@ -62,6 +28,7 @@ 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);
@@ -72,18 +39,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 wasHidden = widget->testAttribute(Qt::WA_WState_Hidden);
- QWidgetPrivate::get(widget)->setVisible(visible);
- if (!wasHidden)
- widget->setAttribute(Qt::WA_WState_ExplicitShowHide, false);
- } 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 {
@@ -103,10 +77,40 @@ public:
widget->focusWidget()->clearFocus();
}
+ void setFocusToTarget(QWindowPrivate::FocusTarget target) 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();
+ }
+
QRectF closestAcceptableGeometry(const QRectF &rect) const override;
-#if QT_CONFIG(opengl)
- QOpenGLContext *shareContext() const override;
-#endif
void processSafeAreaMarginsChanged() override
{
@@ -114,7 +118,9 @@ public:
if (QWidget *widget = q->widget())
QWidgetPrivate::get(widget)->updateContentsRect();
}
- bool allowClickThrough(const QPoint &) const override;
+
+ bool participatesInLastWindowClosed() const override;
+ bool treatAsVisible() const override;
};
QRectF QWidgetWindowPrivate::closestAcceptableGeometry(const QRectF &rect) const
@@ -146,35 +152,43 @@ QRectF QWidgetWindowPrivate::closestAcceptableGeometry(const QRectF &rect) const
return result;
}
-#if QT_CONFIG(opengl)
-QOpenGLContext *QWidgetWindowPrivate::shareContext() const
-{
- Q_Q(const QWidgetWindow);
- const QWidgetPrivate *widgetPrivate = QWidgetPrivate::get(q->widget());
- return widgetPrivate->shareContext();
-}
-#endif // opengl
+bool q_evaluateRhiConfig(const QWidget *w, QPlatformBackingStoreRhiConfig *outConfig, QSurface::SurfaceType *outType);
QWidgetWindow::QWidgetWindow(QWidget *widget)
: QWindow(*new QWidgetWindowPrivate(), nullptr)
, m_widget(widget)
{
updateObjectName();
- // Enable QOpenGLWidget/QQuickWidget children if the platform plugin supports it,
- // and the application developer has not explicitly disabled it.
- if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RasterGLSurface)
- && !QCoreApplication::testAttribute(Qt::AA_ForceRasterWidgets)) {
- setSurfaceType(QSurface::RasterGLSurface);
+ if (!QCoreApplication::testAttribute(Qt::AA_ForceRasterWidgets)) {
+ QSurface::SurfaceType type = QSurface::RasterSurface;
+ q_evaluateRhiConfig(m_widget, nullptr, &type);
+ setSurfaceType(type);
}
+
connect(widget, &QObject::objectNameChanged, this, &QWidgetWindow::updateObjectName);
- connect(this, SIGNAL(screenChanged(QScreen*)), this, SLOT(handleScreenChange()));
+ connect(this, &QWidgetWindow::screenChanged, this, &QWidgetWindow::handleScreenChange);
}
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;
}
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
QAccessibleInterface *QWidgetWindow::accessibleRoot() const
{
if (m_widget)
@@ -208,6 +222,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.
@@ -224,36 +241,20 @@ static inline bool shouldBePropagatedToWidget(QEvent *event)
case QEvent::DynamicPropertyChange:
case QEvent::ChildAdded:
case QEvent::ChildRemoved:
+ case QEvent::Paint:
+ case QEvent::Close: // Propagated manually in closeEvent
return false;
default:
return true;
}
}
-bool QWidgetWindowPrivate::allowClickThrough(const QPoint &) const
-{
- return true;
-}
-
bool QWidgetWindow::event(QEvent *event)
{
if (!m_widget)
return QWindow::event(event);
- if (m_widget->testAttribute(Qt::WA_DontShowOnScreen)) {
- // \a event is uninteresting for QWidgetWindow, the event was probably
- // generated before WA_DontShowOnScreen was set
- if (!shouldBePropagatedToWidget(event))
- return true;
- return QCoreApplication::forwardEvent(m_widget, event);
- }
-
switch (event->type()) {
- case QEvent::Close:
- handleCloseEvent(static_cast<QCloseEvent *>(event));
- QWindow::event(event);
- return true;
-
case QEvent::Enter:
case QEvent::Leave:
handleEnterLeaveEvent(event);
@@ -265,7 +266,7 @@ bool QWidgetWindow::event(QEvent *event)
handleFocusInEvent(static_cast<QFocusEvent *>(event));
Q_FALLTHROUGH();
case QEvent::FocusOut: {
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
QAccessible::State state;
state.active = true;
QAccessibleStateChangeEvent ev(m_widget, state);
@@ -383,6 +384,10 @@ bool QWidgetWindow::event(QEvent *event)
m_widget->repaint();
return true;
+ case QEvent::DevicePixelRatioChange:
+ handleDevicePixelRatioChange();
+ break;
+
default:
break;
}
@@ -397,14 +402,13 @@ QPointer<QWidget> qt_last_mouse_receiver = nullptr;
void QWidgetWindow::handleEnterLeaveEvent(QEvent *event)
{
-#if !defined(Q_OS_OSX) && !defined(Q_OS_IOS) // Cocoa tracks popups
// Ignore all enter/leave events from QPA if we are not on the first-level context menu.
// This prevents duplicated events on most platforms. Fake events will be delivered in
// QWidgetWindow::handleMouseEvent(QMouseEvent *). Make an exception whether the widget
// is already under mouse - let the mouse leave.
if (QApplicationPrivate::inPopupMode() && m_widget != QApplication::activePopupWidget() && !m_widget->underMouse())
return;
-#endif
+
if (event->type() == QEvent::Leave) {
QWidget *enter = nullptr;
// Check from window system event queue if the next queued enter targets a window
@@ -413,7 +417,7 @@ void QWidgetWindow::handleEnterLeaveEvent(QEvent *event)
QWindowSystemInterfacePrivate::EnterEvent *systemEvent =
static_cast<QWindowSystemInterfacePrivate::EnterEvent *>
(QWindowSystemInterfacePrivate::peekWindowSystemEvent(QWindowSystemInterfacePrivate::Enter));
- const QPointF globalPosF = systemEvent ? systemEvent->globalPos : QGuiApplicationPrivate::lastCursorPosition;
+ const QPointF globalPosF = systemEvent ? systemEvent->globalPos : QPointF(QGuiApplicationPrivate::lastCursorPosition);
if (systemEvent) {
if (QWidgetWindow *enterWindow = qobject_cast<QWidgetWindow *>(systemEvent->enter))
{
@@ -444,7 +448,7 @@ void QWidgetWindow::handleEnterLeaveEvent(QEvent *event)
}
} else {
const QEnterEvent *ee = static_cast<QEnterEvent *>(event);
- QWidget *child = m_widget->childAt(ee->pos());
+ QWidget *child = m_widget->childAt(ee->position().toPoint());
QWidget *receiver = child ? child : m_widget.data();
QWidget *leave = nullptr;
if (QApplicationPrivate::inPopupMode() && receiver == m_widget
@@ -453,7 +457,7 @@ void QWidgetWindow::handleEnterLeaveEvent(QEvent *event)
// action on first-level menu.
leave = qt_last_mouse_receiver;
}
- QApplicationPrivate::dispatchEnterLeave(receiver, leave, ee->screenPos());
+ QApplicationPrivate::dispatchEnterLeave(receiver, leave, ee->globalPosition());
qt_last_mouse_receiver = receiver;
}
}
@@ -505,12 +509,12 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ContextMenuOnMouseRelease).toBool() ?
QEvent::MouseButtonRelease : QEvent::MouseButtonPress;
if (QApplicationPrivate::inPopupMode()) {
- QWidget *activePopupWidget = QApplication::activePopupWidget();
- QPoint mapped = event->pos();
+ QPointer<QWidget> activePopupWidget = QApplication::activePopupWidget();
+ QPointF mapped = event->position();
if (activePopupWidget != m_widget)
- mapped = activePopupWidget->mapFromGlobal(event->globalPos());
+ 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;
@@ -522,6 +526,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
case QEvent::MouseButtonDblClick:
qt_button_down = popupChild;
qt_popup_down = activePopupWidget;
+ qt_popup_down_closed = false;
break;
case QEvent::MouseButtonRelease:
releaseAfter = true;
@@ -536,38 +541,39 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
// 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->globalPos());
+ widgetPos = receiver->mapFromGlobal(event->globalPosition());
-#if !defined(Q_OS_OSX) && !defined(Q_OS_IOS) // Cocoa tracks popups
- 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) {
- const QPoint receiverMapped = receiver->mapFromGlobal(event->screenPos().toPoint());
+ const QPoint receiverMapped = receiver->mapFromGlobal(event->globalPosition().toPoint());
// Prevent negative mouse position on enter event - this event
// should be properly handled in "handleEnterLeaveEvent()".
if (receiverMapped.x() >= 0 && receiverMapped.y() >= 0) {
- QApplicationPrivate::dispatchEnterLeave(receiver, nullptr, event->screenPos());
+ QApplicationPrivate::dispatchEnterLeave(receiver, nullptr, event->globalPosition());
qt_last_mouse_receiver = receiver;
}
} else {
- QApplicationPrivate::dispatchEnterLeave(nullptr, qt_last_mouse_receiver, event->screenPos());
+ QApplicationPrivate::dispatchEnterLeave(nullptr, qt_last_mouse_receiver, event->globalPosition());
qt_last_mouse_receiver = receiver;
receiver = activePopupWidget;
}
}
-#endif
- if ((event->type() != QEvent::MouseButtonPress)
- || !(event->flags().testFlag(Qt::MouseEventCreatedDoubleClick))) {
- QMouseEvent e(event->type(), widgetPos, event->windowPos(), event->screenPos(),
- event->button(), event->buttons(), event->modifiers(), event->source());
+ if ((event->type() != QEvent::MouseButtonPress) || !(QMutableSinglePointEvent::from(event)->isDoubleClick())) {
+ // if the widget that was pressed is gone, then deliver move events without buttons
+ const auto buttons = event->type() == QEvent::MouseMove && qt_popup_down_closed
+ ? Qt::NoButton : event->buttons();
+ QMouseEvent e(event->type(), widgetPos, event->scenePosition(), event->globalPosition(),
+ event->button(), buttons, event->modifiers(),
+ event->source(), event->pointingDevice());
e.setTimestamp(event->timestamp());
QApplicationPrivate::sendMouseEvent(receiver, &e, receiver, receiver->window(), &qt_button_down, qt_last_mouse_receiver);
qt_last_mouse_receiver = receiver;
@@ -592,7 +598,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
qt_button_down = nullptr;
if (event->type() == QEvent::MouseButtonPress) {
// the popup disappeared, replay the mouse press event
- QWidget *w = QApplication::widgetAt(event->globalPos());
+ QWidget *w = QApplication::widgetAt(event->globalPosition().toPoint());
if (w && !QApplicationPrivate::isBlockedByModal(w)) {
// activate window of the widget under mouse pointer
if (!w->isActiveWindow()) {
@@ -604,10 +610,10 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
const QRect globalGeometry = win->isTopLevel()
? win->geometry()
: QRect(win->mapToGlobal(QPoint(0, 0)), win->size());
- if (globalGeometry.contains(event->globalPos())) {
+ 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->globalPos());
- QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonPress, localPos, localPos, event->globalPos(),
+ 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());
@@ -624,31 +630,34 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
QWidget *receiver = activePopupWidget;
if (qt_button_down)
receiver = qt_button_down;
- else if(popupChild)
+ else if (popupChild)
receiver = popupChild;
- QContextMenuEvent e(QContextMenuEvent::Mouse, mapped, event->globalPos(), event->modifiers());
+ 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)
+ Q_UNUSED(contextMenuTrigger);
+ Q_UNUSED(oldOpenPopupCount);
}
#endif
if (releaseAfter) {
qt_button_down = nullptr;
+ qt_popup_down_closed = false;
qt_popup_down = nullptr;
}
return;
}
+ qt_popup_down_closed = false;
// modal event handling
if (QApplicationPrivate::instance()->modalState() && !qt_try_modal(m_widget, event->type()))
return;
// which child should have it?
- QWidget *widget = m_widget->childAt(event->pos());
- QPoint mapped = event->pos();
+ QWidget *widget = m_widget->childAt(event->position().toPoint());
+ QPoint mapped = event->position().toPoint();
if (!widget)
widget = m_widget;
@@ -657,18 +666,18 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
if (event->type() == QEvent::MouseButtonPress && initialPress)
qt_button_down = widget;
- QWidget *receiver = QApplicationPrivate::pickMouseReceiver(m_widget, event->windowPos().toPoint(), &mapped, event->type(), event->buttons(),
+ QWidget *receiver = QApplicationPrivate::pickMouseReceiver(m_widget, event->scenePosition().toPoint(), &mapped, event->type(), event->buttons(),
qt_button_down, widget);
if (!receiver)
return;
- if ((event->type() != QEvent::MouseButtonPress)
- || !(event->flags().testFlag(Qt::MouseEventCreatedDoubleClick))) {
+ if ((event->type() != QEvent::MouseButtonPress) || !QMutableSinglePointEvent::from(event)->isDoubleClick()) {
// The preceding statement excludes MouseButtonPress events which caused
// creation of a MouseButtonDblClick event. QTBUG-25831
- QMouseEvent translated(event->type(), mapped, event->windowPos(), event->screenPos(),
- event->button(), event->buttons(), event->modifiers(), event->source());
+ QMouseEvent translated(event->type(), mapped, event->scenePosition(), event->globalPosition(),
+ event->button(), event->buttons(), event->modifiers(),
+ event->source(), event->pointingDevice());
translated.setTimestamp(event->timestamp());
QApplicationPrivate::sendMouseEvent(receiver, &translated, widget, m_widget,
&qt_button_down, qt_last_mouse_receiver);
@@ -676,9 +685,11 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
}
#ifndef QT_NO_CONTEXTMENU
if (event->type() == contextMenuTrigger && event->button() == Qt::RightButton
- && m_widget->rect().contains(event->pos())) {
- QContextMenuEvent e(QContextMenuEvent::Mouse, mapped, event->globalPos(), event->modifiers());
+ && m_widget->rect().contains(event->position().toPoint())) {
+ QContextMenuEvent e(QContextMenuEvent::Mouse, mapped, event->globalPosition().toPoint(), event->modifiers());
QGuiApplication::forwardEvent(receiver, &e, event);
+ if (e.isAccepted())
+ event->accept();
}
#endif
}
@@ -686,14 +697,14 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
void QWidgetWindow::handleTouchEvent(QTouchEvent *event)
{
if (event->type() == QEvent::TouchCancel) {
- QApplicationPrivate::translateTouchCancel(event->device(), event->timestamp());
+ QApplicationPrivate::translateTouchCancel(event->pointingDevice(), event->timestamp());
event->accept();
} else if (QApplicationPrivate::inPopupMode()) {
// Ignore touch events for popups. This will cause QGuiApplication to synthesise mouse
// events instead, which QWidgetWindow::handleMouseEvent will forward correctly:
event->ignore();
} else {
- event->setAccepted(QApplicationPrivate::translateRawTouchEvent(m_widget, event->device(), event->touchPoints(), event->timestamp()));
+ event->setAccepted(QApplicationPrivate::translateRawTouchEvent(m_widget, event));
}
}
@@ -718,6 +729,9 @@ bool QWidgetWindow::updateSize()
bool changed = false;
if (m_widget->testAttribute(Qt::WA_OutsideWSRange))
return changed;
+ if (m_widget->testAttribute(Qt::WA_DontShowOnScreen))
+ return changed;
+
if (m_widget->data->crect.size() != geometry().size()) {
changed = true;
m_widget->data->crect.setSize(geometry().size());
@@ -727,44 +741,45 @@ bool QWidgetWindow::updateSize()
return changed;
}
-bool QWidgetWindow::updatePos()
-{
- bool changed = false;
- if (m_widget->testAttribute(Qt::WA_OutsideWSRange))
- return changed;
- if (m_widget->data->crect.topLeft() != geometry().topLeft()) {
- changed = true;
- m_widget->data->crect.moveTopLeft(geometry().topLeft());
- }
- updateMargins();
- return changed;
-}
-
void QWidgetWindow::updateMargins()
{
- const QMargins margins = frameMargins();
+ // QTBUG-79147 (Windows): Bail out on resize events after closing a dialog
+ // and destroying the platform window which would clear the margins.
QTLWExtra *te = m_widget->d_func()->topData();
+ if (te->window == nullptr || te->window->handle() == nullptr)
+ return;
+ const QMargins margins = frameMargins();
te->posIncludesFrame= false;
te->frameStrut.setCoords(margins.left(), margins.top(), margins.right(), margins.bottom());
m_widget->data->fstrut_dirty = false;
}
-static void sendScreenChangeRecursively(QWidget *widget)
+static void sendChangeRecursively(QWidget *widget, QEvent::Type type)
{
- QEvent e(QEvent::ScreenChangeInternal);
+ QEvent e(type);
QCoreApplication::sendEvent(widget, &e);
QWidgetPrivate *d = QWidgetPrivate::get(widget);
for (int i = 0; i < d->children.size(); ++i) {
QWidget *w = qobject_cast<QWidget *>(d->children.at(i));
if (w)
- sendScreenChangeRecursively(w);
+ sendChangeRecursively(w, type);
}
}
void QWidgetWindow::handleScreenChange()
{
// Send an event recursively to the widget and its children.
- sendScreenChangeRecursively(m_widget);
+ sendChangeRecursively(m_widget, QEvent::ScreenChangeInternal);
+
+ // Invalidate the backing store buffer and repaint immediately.
+ if (screen())
+ repaintWindow();
+}
+
+void QWidgetWindow::handleDevicePixelRatioChange()
+{
+ // Send an event recursively to the widget and its children.
+ sendChangeRecursively(m_widget, QEvent::DevicePixelRatioChange);
// Invalidate the backing store buffer and repaint immediately.
if (screen())
@@ -777,7 +792,7 @@ void QWidgetWindow::repaintWindow()
return;
QTLWExtra *tlwExtra = m_widget->window()->d_func()->maybeTopData();
- if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore)
+ if (tlwExtra && tlwExtra->backingStore)
tlwExtra->repaintManager->markDirty(m_widget->rect(), m_widget,
QWidgetRepaintManager::UpdateNow, QWidgetRepaintManager::BufferInvalid);
}
@@ -800,32 +815,82 @@ void QWidgetWindow::updateNormalGeometry()
void QWidgetWindow::handleMoveEvent(QMoveEvent *event)
{
- if (updatePos())
- QGuiApplication::forwardEvent(m_widget, event);
+ if (m_widget->testAttribute(Qt::WA_OutsideWSRange))
+ return;
+ if (m_widget->testAttribute(Qt::WA_DontShowOnScreen))
+ return;
+
+ auto oldPosition = m_widget->data->crect.topLeft();
+ auto newPosition = geometry().topLeft();
+
+ if (!m_widget->isWindow()) {
+ if (auto *nativeParent = m_widget->nativeParentWidget())
+ newPosition = m_widget->parentWidget()->mapFrom(nativeParent, newPosition);
+ }
+
+ bool changed = newPosition != oldPosition;
+
+ if (changed)
+ m_widget->data->crect.moveTopLeft(newPosition);
+
+ updateMargins(); // FIXME: Only do when changed?
+
+ if (changed) {
+ QMoveEvent widgetEvent(newPosition, oldPosition);
+ QGuiApplication::forwardEvent(m_widget, &widgetEvent, event);
+ }
}
void QWidgetWindow::handleResizeEvent(QResizeEvent *event)
{
- QSize oldSize = m_widget->data->crect.size();
+ auto oldRect = m_widget->rect();
if (updateSize()) {
QGuiApplication::forwardEvent(m_widget, event);
if (m_widget->d_func()->shouldPaintOnScreen()) {
- QRegion updateRegion(geometry());
+ QRegion dirtyRegion = m_widget->rect();
if (m_widget->testAttribute(Qt::WA_StaticContents))
- updateRegion -= QRect(0, 0, oldSize.width(), oldSize.height());
- m_widget->d_func()->syncBackingStore(updateRegion);
+ dirtyRegion -= oldRect;
+ m_widget->d_func()->syncBackingStore(dirtyRegion);
} else {
m_widget->d_func()->syncBackingStore();
}
}
}
-void QWidgetWindow::handleCloseEvent(QCloseEvent *event)
+void QWidgetWindow::closeEvent(QCloseEvent *event)
+{
+ Q_D(QWidgetWindow);
+ bool accepted = m_widget->d_func()->handleClose(d->inClose ? QWidgetPrivate::CloseWithEvent
+ : QWidgetPrivate::CloseWithSpontaneousEvent);
+ event->setAccepted(accepted);
+}
+
+bool QWidgetWindowPrivate::participatesInLastWindowClosed() const
+{
+ Q_Q(const QWidgetWindow);
+
+ // For historical reasons WA_QuitOnClose has been closely tied
+ // to the lastWindowClosed signal, since the default behavior
+ // is to quit the application after emitting lastWindowClosed.
+ // ### Qt 7: Rename this attribute, or decouple behavior.
+ if (!q->widget()->testAttribute(Qt::WA_QuitOnClose))
+ return false;
+
+ return QWindowPrivate::participatesInLastWindowClosed();
+}
+
+bool QWidgetWindowPrivate::treatAsVisible() const
{
- bool is_closing = m_widget->d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent);
- event->setAccepted(is_closing);
+ Q_Q(const QWidgetWindow);
+
+ // Widget windows may have Qt::WA_DontShowOnScreen, in which case the
+ // QQWidget will be visible, but the corresponding QWindow will not.
+ // Since the lastWindowClosed logic relies on checking whether the
+ // closed window was visible, and if there are any remaining visible
+ // windows, we need to reflect the QWidget state, not the QWindow one.
+ return q->widget()->isVisible();
}
#if QT_CONFIG(wheelevent)
@@ -836,30 +901,27 @@ void QWidgetWindow::handleWheelEvent(QWheelEvent *event)
return;
QWidget *rootWidget = m_widget;
- QPoint pos = event->position().toPoint();
+ QPointF pos = event->position();
// Use proper popup window for wheel event. Some QPA sends the wheel
// event to the root menu, so redirect it to the proper popup window.
QWidget *activePopupWidget = QApplication::activePopupWidget();
if (activePopupWidget && activePopupWidget != m_widget) {
rootWidget = activePopupWidget;
- pos = rootWidget->mapFromGlobal(event->globalPosition().toPoint());
+ pos = rootWidget->mapFromGlobal(event->globalPosition());
}
// which child should have it?
- QWidget *widget = rootWidget->childAt(pos);
+ QWidget *widget = rootWidget->childAt(pos.toPoint());
if (!widget)
widget = rootWidget;
- QPoint mapped = widget->mapFrom(rootWidget, pos);
+ QPointF mapped = widget->mapFrom(rootWidget, pos);
-#if QT_DEPRECATED_SINCE(5, 0)
- QWheelEvent translated(mapped, event->globalPos(), event->pixelDelta(), event->angleDelta(), event->delta(), event->orientation(), event->buttons(), event->modifiers(), event->phase(), event->source(), event->inverted());
-#else
- QWheelEvent translated(QPointF(mapped), event->globalPosition(), event->pixelDelta(), event->angleDelta(),
- event->buttons(), event->modifiers(), event->phase(), event->inverted(), event->source());
-#endif
+ QWheelEvent translated(mapped, event->globalPosition(), event->pixelDelta(), event->angleDelta(),
+ event->buttons(), event->modifiers(), event->phase(), event->inverted(),
+ event->source(), event->pointingDevice());
translated.setTimestamp(event->timestamp());
QGuiApplication::forwardEvent(widget, &translated, event);
}
@@ -884,16 +946,16 @@ void QWidgetWindow::handleDragEnterEvent(QDragEnterEvent *event, QWidget *widget
{
Q_ASSERT(m_dragTarget == nullptr);
if (!widget)
- widget = findDnDTarget(m_widget, event->pos());
+ widget = findDnDTarget(m_widget, event->position().toPoint());
if (!widget) {
event->ignore();
return;
}
m_dragTarget = widget;
- const QPoint mapped = widget->mapFromGlobal(m_widget->mapToGlobal(event->pos()));
+ const QPoint mapped = widget->mapFromGlobal(m_widget->mapToGlobal(event->position().toPoint()));
QDragEnterEvent translated(mapped, event->possibleActions(), event->mimeData(),
- event->mouseButtons(), event->keyboardModifiers());
+ event->buttons(), event->modifiers());
QGuiApplication::forwardEvent(m_dragTarget, &translated, event);
event->setAccepted(translated.isAccepted());
event->setDropAction(translated.dropAction());
@@ -901,18 +963,19 @@ void QWidgetWindow::handleDragEnterEvent(QDragEnterEvent *event, QWidget *widget
void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event)
{
- QPointer<QWidget> widget = findDnDTarget(m_widget, event->pos());
+ QPointer<QWidget> widget = findDnDTarget(m_widget, event->position().toPoint());
if (!widget) {
event->ignore();
if (m_dragTarget) { // Send DragLeave to previous
QDragLeaveEvent leaveEvent;
- QGuiApplication::forwardEvent(m_dragTarget, &leaveEvent, event);
+ QWidget *dragTarget = m_dragTarget;
m_dragTarget = nullptr;
+ QGuiApplication::forwardEvent(dragTarget, &leaveEvent, event);
}
} else {
- const QPoint mapped = widget->mapFromGlobal(m_widget->mapToGlobal(event->pos()));
+ const QPoint mapped = widget->mapFromGlobal(m_widget->mapToGlobal(event->position().toPoint()));
QDragMoveEvent translated(mapped, event->possibleActions(), event->mimeData(),
- event->mouseButtons(), event->keyboardModifiers());
+ event->buttons(), event->modifiers());
if (widget == m_dragTarget) { // Target widget unchanged: Send DragMove
translated.setDropAction(event->dropAction());
@@ -921,8 +984,9 @@ void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event)
} else {
if (m_dragTarget) { // Send DragLeave to previous
QDragLeaveEvent leaveEvent;
- QGuiApplication::forwardEvent(m_dragTarget, &leaveEvent, event);
+ QWidget *dragTarget = m_dragTarget;
m_dragTarget = nullptr;
+ QGuiApplication::forwardEvent(dragTarget, &leaveEvent, event);
}
// widget might have been deleted when handling the leaveEvent
if (widget) {
@@ -944,9 +1008,11 @@ void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event)
void QWidgetWindow::handleDragLeaveEvent(QDragLeaveEvent *event)
{
- if (m_dragTarget)
- QGuiApplication::forwardEvent(m_dragTarget, event);
- m_dragTarget = nullptr;
+ if (m_dragTarget) {
+ QWidget *dragTarget = m_dragTarget;
+ m_dragTarget = nullptr;
+ QGuiApplication::forwardEvent(dragTarget, event);
+ }
}
void QWidgetWindow::handleDropEvent(QDropEvent *event)
@@ -956,18 +1022,22 @@ void QWidgetWindow::handleDropEvent(QDropEvent *event)
event->ignore();
return;
}
- const QPoint mapped = m_dragTarget->mapFromGlobal(m_widget->mapToGlobal(event->pos()));
- QDropEvent translated(mapped, event->possibleActions(), event->mimeData(), event->mouseButtons(), event->keyboardModifiers());
- QGuiApplication::forwardEvent(m_dragTarget, &translated, event);
+ const QPoint mapped = m_dragTarget->mapFromGlobal(m_widget->mapToGlobal(event->position().toPoint()));
+ QDropEvent translated(mapped, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
+ QWidget *dragTarget = m_dragTarget;
+ m_dragTarget = nullptr;
+ QGuiApplication::forwardEvent(dragTarget, &translated, event);
event->setAccepted(translated.isAccepted());
event->setDropAction(translated.dropAction());
- m_dragTarget = nullptr;
}
#endif // QT_CONFIG(draganddrop)
void QWidgetWindow::handleExposeEvent(QExposeEvent *event)
{
+ if (m_widget->testAttribute(Qt::WA_DontShowOnScreen))
+ return; // Ignore for widgets that fake exposure
+
QWidgetPrivate *wPriv = m_widget->d_func();
const bool exposed = isExposed();
@@ -987,7 +1057,7 @@ void QWidgetWindow::handleExposeEvent(QExposeEvent *event)
// If the window becomes not exposed...
if (wPriv->childrenShownByExpose) {
// ... and child widgets was previously shown by the expose event - hide widgets again.
- // This is a workaround, because sometimes when window is minimized programatically,
+ // This is a workaround, because sometimes when window is minimized programmatically,
// the QPA can notify that the window is exposed after changing window state to minimized
// and then, the QPA can send next expose event with null exposed region (not exposed).
wPriv->hideChildren(true);
@@ -1003,8 +1073,8 @@ void QWidgetWindow::handleExposeEvent(QExposeEvent *event)
m_widget->setAttribute(Qt::WA_Mapped);
for (QWidget *p = m_widget->parentWidget(); p && !p->testAttribute(Qt::WA_Mapped); p = p->parentWidget())
p->setAttribute(Qt::WA_Mapped);
- if (!event->region().isNull())
- wPriv->syncBackingStore(event->region());
+ if (!event->m_region.isNull())
+ wPriv->syncBackingStore(event->m_region);
} else {
m_widget->setAttribute(Qt::WA_Mapped, false);
}
@@ -1038,11 +1108,7 @@ void QWidgetWindow::handleWindowStateChangedEvent(QWindowStateChangeEvent *event
}
}
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
bool QWidgetWindow::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
-#else
-bool QWidgetWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
-#endif
{
return m_widget->nativeEvent(eventType, message, result);
}
@@ -1055,20 +1121,19 @@ void QWidgetWindow::handleTabletEvent(QTabletEvent *event)
QWidget *widget = qt_tablet_target;
if (!widget) {
- widget = m_widget->childAt(event->pos());
- if (event->type() == QEvent::TabletPress) {
- if (!widget)
- widget = m_widget;
+ widget = m_widget->childAt(event->position().toPoint());
+ if (!widget)
+ widget = m_widget;
+ if (event->type() == QEvent::TabletPress)
qt_tablet_target = widget;
- }
}
if (widget) {
- QPointF delta = event->globalPosF() - event->globalPos();
- QPointF mapped = widget->mapFromGlobal(event->globalPos()) + delta;
- QTabletEvent ev(event->type(), mapped, event->globalPosF(), event->device(), event->pointerType(),
+ QPointF delta = event->globalPosition() - event->globalPosition().toPoint();
+ QPointF mapped = widget->mapFromGlobal(event->globalPosition().toPoint()) + delta;
+ QTabletEvent ev(event->type(), event->pointingDevice(), mapped, event->globalPosition(),
event->pressure(), event->xTilt(), event->yTilt(), event->tangentialPressure(),
- event->rotation(), event->z(), event->modifiers(), event->uniqueId(), event->button(), event->buttons());
+ event->rotation(), event->z(), event->modifiers(), event->button(), event->buttons());
ev.setTimestamp(event->timestamp());
ev.setAccepted(false);
QGuiApplication::forwardEvent(widget, &ev, event);
@@ -1091,7 +1156,7 @@ void QWidgetWindow::handleGestureEvent(QNativeGestureEvent *e)
receiver = popupFocusWidget ? popupFocusWidget : popup;
}
if (!receiver)
- receiver = QApplication::widgetAt(e->globalPos());
+ receiver = QApplication::widgetAt(e->globalPosition().toPoint());
if (!receiver)
receiver = m_widget; // last resort
@@ -1132,8 +1197,8 @@ void QWidgetWindow::updateObjectName()
{
QString name = m_widget->objectName();
if (name.isEmpty())
- name = QString::fromUtf8(m_widget->metaObject()->className()) + QLatin1String("Class");
- name += QLatin1String("Window");
+ name = QString::fromUtf8(m_widget->metaObject()->className()) + "Class"_L1;
+ name += "Window"_L1;
setObjectName(name);
}