Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwidgetwindow.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "private/qwindow_p.h"
7#include "qlayout.h"
8
9#include "private/qwidget_p.h"
10#include "private/qapplication_p.h"
11#if QT_CONFIG(accessibility)
12#include <QtGui/qaccessible.h>
13#endif
14#include <private/qwidgetrepaintmanager_p.h>
15#include <qpa/qwindowsysteminterface_p.h>
16#include <qpa/qplatformtheme.h>
17#include <qpa/qplatformwindow.h>
18#include <private/qgesturemanager_p.h>
19#include <private/qhighdpiscaling_p.h>
20
22
23using namespace Qt::StringLiterals;
24
25Q_WIDGETS_EXPORT extern bool qt_tab_all_widgets();
26
27Q_WIDGETS_EXPORT QWidget *qt_button_down = nullptr; // widget got last button-down
28
29// popup control
30QWidget *qt_popup_down = nullptr; // popup that contains the pressed widget
31bool qt_popup_down_closed = false; // qt_popup_down has been closed
32
33extern bool qt_try_modal(QWidget *widget, QEvent::Type type);
34
36{
37 Q_DECLARE_PUBLIC(QWidgetWindow)
38public:
40 {
42 qCDebug(lcWidgetShowHide) << "Setting visibility of" << q->widget()
43 << "to" << visible << "via QWidgetWindowPrivate";
44
45 if (QWidget *widget = q->widget()) {
46 // If the widget's visible state is already matching the new QWindow
47 // visible state we assume the widget has already synced up.
48 if (visible != widget->isVisible())
50 }
51
52 // If we end up calling QWidgetPrivate::setVisible() above, we will
53 // in most cases recurse back into setNativeWindowVisibility() to
54 // update the QWindow state. But during QWidget::destroy() this is
55 // not the case, as Qt::WA_WState_Created has been unset by the time
56 // we check if we should call hide_helper(). We handle this case, as
57 // well as the cases where we don't call QWidgetPrivate::setVisible(),
58 // by syncing up the QWindow state here if needed.
59 if (q->isVisible() != visible)
61 }
62
65 QWindow *w = q;
67 w = w->parent();
68 }
69 return w;
70 }
71
79
81 {
83 QWidget *widget = q->widget();
84 if (!widget)
85 return;
86
87 switch (target) {
88 case FocusTarget::Prev:
89 case FocusTarget::Next: {
92 return;
93 }
94 case FocusTarget::First:
95 case FocusTarget::Last: {
101 break;
102 }
103 default:
104 break;
105 }
106 }
107
109
112
113 QPalette windowPalette() const override
114 {
115 Q_Q(const QWidgetWindow);
116 if (const auto *widget = q->widget())
117 return widget->palette();
118 return QWindowPrivate::windowPalette();
119 }
120};
121
122QRectF QWidgetWindowPrivate::closestAcceptableGeometry(const QRectF &rect) const
123{
124 Q_Q(const QWidgetWindow);
125 const QWidget *widget = q->widget();
126 if (!widget || !widget->isWindow() || !widget->hasHeightForWidth())
127 return QRect();
128 const QSize oldSize = rect.size().toSize();
129 const QSize newSize = QLayout::closestAcceptableSize(widget, oldSize);
130 if (newSize == oldSize)
131 return QRectF();
132 const int dw = newSize.width() - oldSize.width();
133 const int dh = newSize.height() - oldSize.height();
134 QRectF result = rect;
135 const QRectF currentGeometry(widget->geometry());
136 const qreal topOffset = result.top() - currentGeometry.top();
137 const qreal bottomOffset = result.bottom() - currentGeometry.bottom();
138 if (qAbs(topOffset) > qAbs(bottomOffset))
139 result.setTop(result.top() - dh); // top edge drag
140 else
141 result.setBottom(result.bottom() + dh); // bottom edge drag
142 const qreal leftOffset = result.left() - currentGeometry.left();
143 const qreal rightOffset = result.right() - currentGeometry.right();
144 if (qAbs(leftOffset) > qAbs(rightOffset))
145 result.setLeft(result.left() - dw); // left edge drag
146 else
147 result.setRight(result.right() + dw); // right edge drag
148 return result;
149}
150
151bool q_evaluateRhiConfig(const QWidget *w, QPlatformBackingStoreRhiConfig *outConfig, QSurface::SurfaceType *outType);
152
153QWidgetWindow::QWidgetWindow(QWidget *widget)
154 : QWindow(*new QWidgetWindowPrivate(), nullptr)
155 , m_widget(widget)
156{
157 updateObjectName();
158 if (!QCoreApplication::testAttribute(Qt::AA_ForceRasterWidgets)) {
159 QSurface::SurfaceType type = QSurface::RasterSurface;
160 if (q_evaluateRhiConfig(m_widget, nullptr, &type))
161 setSurfaceType(type);
162 }
163
164 connect(widget, &QObject::objectNameChanged, this, &QWidgetWindow::updateObjectName);
165 connect(this, &QWidgetWindow::screenChanged, this, &QWidgetWindow::handleScreenChange);
166}
167
169{
170 // destroy while we are still alive
171 destroy();
172
173 if (!m_widget)
174 return;
175
176 QTLWExtra *topData = QWidgetPrivate::get(m_widget)->topData();
177 Q_ASSERT(topData);
178
179 // The QPlaformBackingStore may hold a reference to the window,
180 // so the backingstore needs to be deleted first.
181 topData->repaintManager.reset(nullptr);
182 delete topData->backingStore;
183 topData->backingStore = nullptr;
184 topData->widgetTextures.clear();
185
186 // Too late to do anything beyond this point
187 topData->window = nullptr;
188}
189
190#if QT_CONFIG(accessibility)
191QAccessibleInterface *QWidgetWindow::accessibleRoot() const
192{
193 if (m_widget)
194 return QAccessible::queryAccessibleInterface(m_widget);
195 return nullptr;
196}
197#endif
198
200{
201 QWidget *windowWidget = m_widget;
202 if (!windowWidget)
203 return nullptr;
204
205 // A window can't have a focus object if it's being destroyed.
206 if (QWidgetPrivate::get(windowWidget)->data.in_destructor)
207 return nullptr;
208
209 QWidget *widget = windowWidget->focusWidget();
210
211 if (!widget)
212 widget = windowWidget;
213
214 QObject *focusObj = QWidgetPrivate::get(widget)->focusObject();
215 if (focusObj)
216 return focusObj;
217
218 return widget;
219}
220
222{
223 Q_D(QWidgetWindow);
224 qCDebug(lcWidgetShowHide) << "Setting visibility of" << this
225 << "to" << visible << "via QWidgetWindow::setNativeWindowVisibility";
226
227 // Call base class setVisible() implementation to run the QWindow
228 // visibility logic. Don't call QWidgetWindowPrivate::setVisible()
229 // since that will recurse back into QWidget code.
230 d->QWindowPrivate::setVisible(visible);
231}
232
233void QWidgetWindow::focusNextPrevChild(QWidget *widget, bool next)
234{
235 Q_ASSERT(widget);
236 widget->focusNextPrevChild(next);
237}
238
239static inline bool shouldBePropagatedToWidget(QEvent *event)
240{
241 switch (event->type()) {
242 // Handing show events to widgets would cause them to be triggered twice
243 case QEvent::Show:
244 case QEvent::Hide:
245 case QEvent::Timer:
246 case QEvent::DynamicPropertyChange:
247 case QEvent::ChildAdded:
248 case QEvent::ChildRemoved:
249 case QEvent::Paint:
250 case QEvent::Close: // Propagated manually in closeEvent
251 return false;
252 default:
253 return true;
254 }
255}
256
257bool QWidgetWindow::event(QEvent *event)
258{
259 if (!m_widget)
260 return QWindow::event(event);
261
262 switch (event->type()) {
263 case QEvent::Enter:
264 case QEvent::Leave:
265 handleEnterLeaveEvent(event);
266 return true;
267
268 // these should not be sent to QWidget, the corresponding events
269 // are sent by QApplicationPrivate::notifyActiveWindowChange()
270 case QEvent::FocusIn:
271 handleFocusInEvent(static_cast<QFocusEvent *>(event));
272 Q_FALLTHROUGH();
273 case QEvent::FocusOut: {
274#if QT_CONFIG(accessibility)
275 QAccessible::State state;
276 state.active = true;
277 QAccessibleStateChangeEvent ev(m_widget, state);
278 QAccessible::updateAccessibility(&ev);
279#endif
280 return false; }
281
282 case QEvent::FocusAboutToChange:
283 if (QApplicationPrivate::focus_widget) {
284 if (QApplicationPrivate::focus_widget->testAttribute(Qt::WA_InputMethodEnabled))
285 QGuiApplication::inputMethod()->commit();
286
287 QGuiApplication::forwardEvent(QApplicationPrivate::focus_widget, event);
288 }
289 return true;
290
291 case QEvent::KeyPress:
292 case QEvent::KeyRelease:
293 case QEvent::ShortcutOverride:
294 handleKeyEvent(static_cast<QKeyEvent *>(event));
295 return true;
296
297 case QEvent::MouseMove:
298 case QEvent::MouseButtonPress:
299 case QEvent::MouseButtonRelease:
300 case QEvent::MouseButtonDblClick:
301 handleMouseEvent(static_cast<QMouseEvent *>(event));
302 return true;
303
304 case QEvent::NonClientAreaMouseMove:
305 case QEvent::NonClientAreaMouseButtonPress:
306 case QEvent::NonClientAreaMouseButtonRelease:
307 case QEvent::NonClientAreaMouseButtonDblClick:
308 handleNonClientAreaMouseEvent(static_cast<QMouseEvent *>(event));
309 return true;
310
311 case QEvent::TouchBegin:
312 case QEvent::TouchUpdate:
313 case QEvent::TouchEnd:
314 case QEvent::TouchCancel:
315 handleTouchEvent(static_cast<QTouchEvent *>(event));
316 return true;
317
318 case QEvent::Move:
319 handleMoveEvent(static_cast<QMoveEvent *>(event));
320 return true;
321
322 case QEvent::Resize:
323 handleResizeEvent(static_cast<QResizeEvent *>(event));
324 return true;
325
326#if QT_CONFIG(wheelevent)
327 case QEvent::Wheel:
328 handleWheelEvent(static_cast<QWheelEvent *>(event));
329 return true;
330#endif
331
332#if QT_CONFIG(draganddrop)
333 case QEvent::DragEnter:
334 handleDragEnterEvent(static_cast<QDragEnterEvent *>(event));
335 return true;
336 case QEvent::DragMove:
337 handleDragMoveEvent(static_cast<QDragMoveEvent *>(event));
338 return true;
339 case QEvent::DragLeave:
340 handleDragLeaveEvent(static_cast<QDragLeaveEvent *>(event));
341 return true;
342 case QEvent::Drop:
343 handleDropEvent(static_cast<QDropEvent *>(event));
344 return true;
345#endif
346
347 case QEvent::Expose:
348 handleExposeEvent(static_cast<QExposeEvent *>(event));
349 return true;
350
351 case QEvent::WindowStateChange:
352 QWindow::event(event); // Update QWindow::Visibility and emit signals.
353 handleWindowStateChangedEvent(static_cast<QWindowStateChangeEvent *>(event));
354 return true;
355
356 case QEvent::ThemeChange: {
357 QEvent widgetEvent(QEvent::ThemeChange);
358 QCoreApplication::forwardEvent(m_widget, &widgetEvent, event);
359 }
360 return true;
361
362#if QT_CONFIG(tabletevent)
363 case QEvent::TabletPress:
364 case QEvent::TabletMove:
365 case QEvent::TabletRelease:
366 handleTabletEvent(static_cast<QTabletEvent *>(event));
367 return true;
368#endif
369
370#ifndef QT_NO_GESTURES
371 case QEvent::NativeGesture:
372 handleGestureEvent(static_cast<QNativeGestureEvent *>(event));
373 return true;
374#endif
375
376#ifndef QT_NO_CONTEXTMENU
377 case QEvent::ContextMenu:
378 handleContextMenuEvent(static_cast<QContextMenuEvent *>(event));
379 return true;
380#endif // QT_NO_CONTEXTMENU
381
382 case QEvent::WindowBlocked:
383 qt_button_down = nullptr;
384 break;
385
386 case QEvent::UpdateRequest:
387 // This is not the same as an UpdateRequest for a QWidget. That just
388 // syncs the backing store while here we also must mark as dirty.
389 m_widget->repaint();
390 return true;
391
392 case QEvent::DevicePixelRatioChange:
393 handleDevicePixelRatioChange();
394 break;
395
396 case QEvent::SafeAreaMarginsChange:
397 QWidgetPrivate::get(m_widget)->updateContentsRect();
398 break;
399
400 default:
401 break;
402 }
403
404 if (shouldBePropagatedToWidget(event) && QCoreApplication::forwardEvent(m_widget, event))
405 return true;
406
407 return QWindow::event(event);
408}
409
411
413{
414 // Ignore all enter/leave events from QPA if we are not on the first-level context menu.
415 // This prevents duplicated events on most platforms. Fake events will be delivered in
416 // QWidgetWindow::handleMouseEvent(QMouseEvent *). Make an exception whether the widget
417 // is already under mouse - let the mouse leave.
418 if (QApplicationPrivate::inPopupMode() && m_widget != QApplication::activePopupWidget() && !m_widget->underMouse())
419 return;
420
421 if (event->type() == QEvent::Leave) {
422 QWidget *enter = nullptr;
423 // Check from window system event queue if the next queued enter targets a window
424 // in the same window hierarchy (e.g. enter a child of this window). If so,
425 // remove the enter event from queue and handle both in single dispatch.
426 QWindowSystemInterfacePrivate::EnterEvent *systemEvent =
427 static_cast<QWindowSystemInterfacePrivate::EnterEvent *>
428 (QWindowSystemInterfacePrivate::peekWindowSystemEvent(QWindowSystemInterfacePrivate::Enter));
429 const QPointF globalPosF = systemEvent ? systemEvent->globalPos : QPointF(QGuiApplicationPrivate::lastCursorPosition);
430 if (systemEvent) {
431 if (QWidgetWindow *enterWindow = qobject_cast<QWidgetWindow *>(systemEvent->enter))
432 {
433 QWindow *thisParent = this;
434 QWindow *enterParent = enterWindow;
435 while (thisParent->parent())
436 thisParent = thisParent->parent();
437 while (enterParent->parent())
438 enterParent = enterParent->parent();
439 if (thisParent == enterParent) {
440 QGuiApplicationPrivate::currentMouseWindow = enterWindow;
441 enter = enterWindow->widget();
442 QWindowSystemInterfacePrivate::removeWindowSystemEvent(systemEvent);
443 }
444 }
445 }
446 // Enter-leave between sibling widgets is ignored when there is a mousegrabber - this makes
447 // both native and non-native widgets work similarly.
448 // When mousegrabbing, leaves are only generated if leaving the parent window.
449 if (!enter || !QWidget::mouseGrabber()) {
450 // Preferred leave target is the last mouse receiver, unless it has native window,
451 // in which case it is assumed to receive it's own leave event when relevant.
452 QWidget *leave = m_widget;
453 if (qt_last_mouse_receiver && !qt_last_mouse_receiver->internalWinId())
454 leave = qt_last_mouse_receiver.data();
455 QApplicationPrivate::dispatchEnterLeave(enter, leave, globalPosF);
456 qt_last_mouse_receiver = enter;
457 }
458 } else {
459 const QEnterEvent *ee = static_cast<QEnterEvent *>(event);
460 QWidget *child = m_widget->childAt(ee->position());
461 QWidget *receiver = child ? child : m_widget.data();
462 QWidget *leave = nullptr;
463 if (QApplicationPrivate::inPopupMode() && receiver == m_widget
464 && qt_last_mouse_receiver != m_widget) {
465 // This allows to deliver the leave event to the native widget
466 // action on first-level menu.
467 leave = qt_last_mouse_receiver;
468 }
469 QApplicationPrivate::dispatchEnterLeave(receiver, leave, ee->globalPosition());
470 qt_last_mouse_receiver = receiver;
471 }
472}
473
474QWidget *QWidgetWindow::getFocusWidget(FocusWidgets fw)
475{
476 QWidget *tlw = m_widget;
477 QWidget *w = tlw->nextInFocusChain();
478
479 QWidget *last = tlw;
480
481 uint focus_flag = qt_tab_all_widgets() ? Qt::TabFocus : Qt::StrongFocus;
482
483 while (w != tlw)
484 {
485 if (((w->focusPolicy() & focus_flag) == focus_flag)
486 && w->isVisibleTo(m_widget) && w->isEnabled())
487 {
488 last = w;
489 if (fw == FirstFocusWidget)
490 break;
491 }
492 w = w->nextInFocusChain();
493 }
494
495 return last;
496}
497
498void QWidgetWindow::handleFocusInEvent(QFocusEvent *e)
499{
500 QWidget *focusWidget = nullptr;
501 if (e->reason() == Qt::BacktabFocusReason)
502 focusWidget = getFocusWidget(LastFocusWidget);
503 else if (e->reason() == Qt::TabFocusReason)
504 focusWidget = getFocusWidget(FirstFocusWidget);
505
506 if (focusWidget != nullptr)
507 focusWidget->setFocus();
508}
509
510void QWidgetWindow::handleNonClientAreaMouseEvent(QMouseEvent *e)
511{
512 QApplication::forwardEvent(m_widget, e);
513}
514
515void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
516{
517 Q_D(QWidgetWindow);
518
519 // Event delivery can potentially result in window re-creation (QTBUG-132912)
520 // so we need QPointer to avoid a dangling d below
521 QPointer<QWidgetWindow> self = this;
522
523 if (auto *activePopupWidget = QApplication::activePopupWidget()) {
524 QPointF mapped = event->position();
525 if (activePopupWidget != m_widget)
526 mapped = activePopupWidget->mapFromGlobal(event->globalPosition());
527 bool releaseAfter = false;
528 QWidget *popupChild = activePopupWidget->childAt(mapped);
529
530 if (activePopupWidget != qt_popup_down) {
531 qt_button_down = nullptr;
532 qt_popup_down = nullptr;
533 }
534
535 switch (event->type()) {
536 case QEvent::MouseButtonPress:
537 case QEvent::MouseButtonDblClick:
538 qt_button_down = popupChild;
539 qt_popup_down = activePopupWidget;
540 qt_popup_down_closed = false;
541 break;
542 case QEvent::MouseButtonRelease:
543 releaseAfter = true;
544 break;
545 default:
546 break; // nothing for mouse move
547 }
548
549 if (activePopupWidget->isEnabled()) {
550 // deliver event
551 QPointer<QWidget> receiver = activePopupWidget;
552 QPointF widgetPos = mapped;
553 if (qt_button_down)
554 receiver = qt_button_down;
555 else if (popupChild)
556 receiver = popupChild;
557 if (receiver != activePopupWidget)
558 widgetPos = receiver->mapFromGlobal(event->globalPosition());
559
560 const bool reallyUnderMouse = activePopupWidget->rect().contains(mapped.toPoint());
561 const bool underMouse = activePopupWidget->underMouse();
562 if (underMouse != reallyUnderMouse) {
563 if (reallyUnderMouse) {
564 const QPointF receiverMapped = receiver->mapFromGlobal(event->globalPosition());
565 // Prevent negative mouse position on enter event - this event
566 // should be properly handled in "handleEnterLeaveEvent()".
567 if (receiverMapped.x() >= 0 && receiverMapped.y() >= 0) {
568 QApplicationPrivate::dispatchEnterLeave(receiver, nullptr, event->globalPosition());
569 qt_last_mouse_receiver = receiver;
570 }
571 } else {
572 QApplicationPrivate::dispatchEnterLeave(nullptr, qt_last_mouse_receiver, event->globalPosition());
573 qt_last_mouse_receiver = receiver;
574 receiver = activePopupWidget;
575 }
576 }
577
578 if ((event->type() != QEvent::MouseButtonPress) || !(QMutableSinglePointEvent::isDoubleClick(event))) {
579 // if the widget that was pressed is gone, then deliver move events without buttons
580 const auto buttons = event->type() == QEvent::MouseMove && qt_popup_down_closed
581 ? Qt::NoButton : event->buttons();
582 QMouseEvent e(event->type(), widgetPos, event->scenePosition(), event->globalPosition(),
583 event->button(), buttons, event->modifiers(),
584 event->source(), event->pointingDevice());
585 e.setTimestamp(event->timestamp());
586 QApplicationPrivate::sendMouseEvent(receiver, &e, receiver, receiver->window(), &qt_button_down, qt_last_mouse_receiver);
587 qt_last_mouse_receiver = receiver;
588 }
589 } else {
590 // close disabled popups when a mouse button is pressed or released
591 switch (event->type()) {
592 case QEvent::MouseButtonPress:
593 case QEvent::MouseButtonDblClick:
594 case QEvent::MouseButtonRelease:
595 activePopupWidget->close();
596 break;
597 default:
598 break;
599 }
600 }
601
602 // Event delivery above might have destroyed this object. See QTBUG-138419.
603 if (self.isNull())
604 return;
605
606 if (QApplication::activePopupWidget() != activePopupWidget
607 && QApplicationPrivate::replayMousePress
608 && QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::ReplayMousePressOutsidePopup).toBool()) {
609 if (m_widget->windowType() != Qt::Popup)
610 qt_button_down = nullptr;
611 if (event->type() == QEvent::MouseButtonPress) {
612 // the popup disappeared: replay the mouse press event to whatever is behind it
613 QWidget *w = QApplication::widgetAt(event->globalPosition().toPoint());
614 if (w && !QApplicationPrivate::isBlockedByModal(w)) {
615 // activate window of the widget under mouse pointer
616 if (!w->isActiveWindow()) {
617 w->activateWindow();
618 w->window()->raise();
619 }
620
621 if (auto win = qt_widget_private(w)->windowHandle(QWidgetPrivate::WindowHandleMode::Closest)) {
622 const QRect globalGeometry = win->isTopLevel()
623 ? win->geometry()
624 : QRect(win->mapToGlobal(QPoint(0, 0)), win->size());
625 if (globalGeometry.contains(event->globalPosition().toPoint())) {
626 // Use postEvent() to ensure the local QEventLoop terminates when called from QMenu::exec()
627 const QPointF localPos = win->mapFromGlobal(event->globalPosition());
628 QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonPress, localPos, localPos, event->globalPosition(),
629 event->button(), event->buttons(), event->modifiers(), event->source());
630 QCoreApplicationPrivate::setEventSpontaneous(e, true);
631 e->setTimestamp(event->timestamp());
632 QCoreApplication::postEvent(win, e);
633 }
634 }
635 }
636 }
637 QApplicationPrivate::replayMousePress = false;
638#ifndef QT_NO_CONTEXTMENU
639 } else if (event->type() == QGuiApplicationPrivate::contextMenuEventType()
640 && event->button() == Qt::RightButton) {
641 QWidget *receiver = activePopupWidget;
642 if (qt_button_down)
643 receiver = qt_button_down;
644 else if (popupChild)
645 receiver = popupChild;
646 const QPoint localPos = receiver->mapFromGlobal(event->globalPosition()).toPoint();
647 QContextMenuEvent e(QContextMenuEvent::Mouse, localPos, event->globalPosition().toPoint(), event->modifiers());
648 QApplication::forwardEvent(receiver, &e, event);
649 }
650#else
651 }
652#endif
653
654 if (releaseAfter) {
655 qt_button_down = nullptr;
656 qt_popup_down_closed = false;
657 qt_popup_down = nullptr;
658 }
659 return;
660 }
661
662 qt_popup_down_closed = false;
663 // modal event handling
664 if (QApplicationPrivate::instance()->modalState() && !qt_try_modal(m_widget, event->type()))
665 return;
666
667 // which child should have it?
668 QWidget *widget = m_widget->childAt(event->position());
669 QPointF mapped = event->position();
670
671 if (!widget)
672 widget = m_widget;
673
674 const bool initialPress = event->buttons() == event->button();
675 if (event->type() == QEvent::MouseButtonPress && initialPress)
676 qt_button_down = widget;
677
678 QWidget *receiver = QApplicationPrivate::pickMouseReceiver(m_widget, event->scenePosition(), &mapped, event->type(), event->buttons(),
679 qt_button_down, widget);
680 if (!receiver)
681 return;
682
683 if (d->isPopup() && receiver->window()->windowHandle() != this) {
684 receiver = widget;
685 mapped = event->position();
686 }
687
688 if ((event->type() != QEvent::MouseButtonPress) || !QMutableSinglePointEvent::isDoubleClick(event)) {
689
690 // The preceding statement excludes MouseButtonPress events which caused
691 // creation of a MouseButtonDblClick event. QTBUG-25831
692 QMouseEvent translated(event->type(), mapped, event->scenePosition(), event->globalPosition(),
693 event->button(), event->buttons(), event->modifiers(),
694 event->source(), event->pointingDevice());
695 translated.setTimestamp(event->timestamp());
696 QApplicationPrivate::sendMouseEvent(receiver, &translated, widget, m_widget,
697 &qt_button_down, qt_last_mouse_receiver);
698 event->setAccepted(translated.isAccepted());
699 }
700
701 if (self.isNull())
702 return;
703
704#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
705 if (
706#else
707 if (event->isAccepted() &&
708#endif
709 (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease))
710 d->maybeSynthesizeContextMenuEvent(event);
711}
712
713void QWidgetWindow::handleTouchEvent(QTouchEvent *event)
714{
715 if (event->type() == QEvent::TouchCancel) {
716 QApplicationPrivate::translateTouchCancel(event->pointingDevice(), event->timestamp());
717 event->accept();
718 } else if (QApplication::activePopupWidget()) {
719 // Ignore touch events for popups. This will cause QGuiApplication to synthesise mouse
720 // events instead, which QWidgetWindow::handleMouseEvent will forward correctly:
721 event->ignore();
722 } else {
723 event->setAccepted(QApplicationPrivate::translateRawTouchEvent(m_widget, event));
724 }
725}
726
727void QWidgetWindow::handleKeyEvent(QKeyEvent *event)
728{
729 if (QApplicationPrivate::instance()->modalState() && !qt_try_modal(m_widget, event->type()))
730 return;
731
732 QObject *receiver = QWidget::keyboardGrabber();
733 if (auto *popup = QApplication::activePopupWidget(); !receiver && popup) {
734 QWidget *popupFocusWidget = popup->focusWidget();
735 receiver = popupFocusWidget ? popupFocusWidget : popup;
736 }
737 if (!receiver)
738 receiver = focusObject();
739 QGuiApplication::forwardEvent(receiver, event);
740}
741
742bool QWidgetWindow::updateSize()
743{
744 bool changed = false;
745 if (m_widget->testAttribute(Qt::WA_OutsideWSRange))
746 return changed;
747 if (m_widget->testAttribute(Qt::WA_DontShowOnScreen))
748 return changed;
749
750 if (m_widget->data->crect.size() != geometry().size()) {
751 changed = true;
752 m_widget->data->crect.setSize(geometry().size());
753 }
754
755 updateMargins();
756 return changed;
757}
758
759void QWidgetWindow::updateMargins()
760{
761 // QTBUG-79147 (Windows): Bail out on resize events after closing a dialog
762 // and destroying the platform window which would clear the margins.
763 QTLWExtra *te = m_widget->d_func()->topData();
764 if (te->window == nullptr || te->window->handle() == nullptr)
765 return;
766 const QMargins margins = frameMargins();
767 te->posIncludesFrame= false;
768 te->frameStrut.setCoords(margins.left(), margins.top(), margins.right(), margins.bottom());
769 m_widget->data->fstrut_dirty = false;
770}
771
772static void sendChangeRecursively(QWidget *widget, QEvent::Type type)
773{
774 QEvent e(type);
775 QCoreApplication::sendEvent(widget, &e);
776 QWidgetPrivate *d = QWidgetPrivate::get(widget);
777 for (int i = 0; i < d->children.size(); ++i) {
778 QWidget *w = qobject_cast<QWidget *>(d->children.at(i));
779 if (w)
780 sendChangeRecursively(w, type);
781 }
782}
783
784void QWidgetWindow::handleScreenChange()
785{
786 // Send an event recursively to the widget and its children.
787 sendChangeRecursively(m_widget, QEvent::ScreenChangeInternal);
788
789 // Invalidate the backing store buffer and schedule repaint
790 scheduleRepaint();
791}
792
793void QWidgetWindow::handleDevicePixelRatioChange()
794{
795 // Send an event recursively to the widget and its children.
796 sendChangeRecursively(m_widget, QEvent::DevicePixelRatioChange);
797
798 // Invalidate the backing store buffer and schedule repaint
799 scheduleRepaint();
800}
801
802/*
803 Schedules a repaint in response to screen or DPR changes
804
805 Normally these changes will come with a corresponding expose
806 event following the change, but to guarantee that we refresh
807 the widget based on the new properties we also schedule our
808 own repaint.
809
810 Note that we do not do a synchronous repaint here, as the system
811 hasn't asked us to repaint just yet, it just informed us about
812 the new window state.
813*/
814void QWidgetWindow::scheduleRepaint()
815{
816 if (!screen())
817 return;
818
819 if (!m_widget->isVisible() || !m_widget->updatesEnabled() || !m_widget->rect().isValid())
820 return;
821
822 QTLWExtra *tlwExtra = m_widget->window()->d_func()->maybeTopData();
823 if (tlwExtra && tlwExtra->backingStore) {
824 tlwExtra->repaintManager->markDirty(m_widget->rect(), m_widget,
825 QWidgetRepaintManager::UpdateLater, QWidgetRepaintManager::BufferInvalid);
826 }
827}
828
829// Store normal geometry used for saving application settings.
830void QWidgetWindow::updateNormalGeometry()
831{
832 QTLWExtra *tle = m_widget->d_func()->maybeTopData();
833 if (!tle)
834 return;
835 // Ask platform window, default to widget geometry.
836 QRect normalGeometry;
837 if (const QPlatformWindow *pw = handle())
838 normalGeometry = QHighDpi::fromNativePixels(pw->normalGeometry(), this);
839 if (!normalGeometry.isValid() && !(m_widget->windowState() & ~Qt::WindowActive))
840 normalGeometry = m_widget->geometry();
841 if (normalGeometry.isValid())
842 tle->normalGeometry = normalGeometry;
843}
844
845void QWidgetWindow::handleMoveEvent(QMoveEvent *event)
846{
847 if (m_widget->testAttribute(Qt::WA_OutsideWSRange))
848 return;
849 if (m_widget->testAttribute(Qt::WA_DontShowOnScreen))
850 return;
851
852 auto oldPosition = m_widget->data->crect.topLeft();
853 auto newPosition = geometry().topLeft();
854
855 if (!m_widget->isWindow()) {
856 if (auto *nativeParent = m_widget->nativeParentWidget())
857 newPosition = m_widget->parentWidget()->mapFrom(nativeParent, newPosition);
858 }
859
860 bool changed = newPosition != oldPosition;
861
862 if (changed)
863 m_widget->data->crect.moveTopLeft(newPosition);
864
865 updateMargins(); // FIXME: Only do when changed?
866
867 if (changed) {
868 QMoveEvent widgetEvent(newPosition, oldPosition);
869 QGuiApplication::forwardEvent(m_widget, &widgetEvent, event);
870 }
871}
872
873void QWidgetWindow::handleResizeEvent(QResizeEvent *event)
874{
875 auto oldRect = m_widget->rect();
876
877 if (updateSize()) {
878 QGuiApplication::forwardEvent(m_widget, event);
879
880 if (m_widget->d_func()->shouldPaintOnScreen()) {
881 QRegion dirtyRegion = m_widget->rect();
882 if (m_widget->testAttribute(Qt::WA_StaticContents))
883 dirtyRegion -= oldRect;
884 m_widget->d_func()->syncBackingStore(dirtyRegion);
885 } else {
886 m_widget->d_func()->syncBackingStore();
887 }
888 }
889}
890
891void QWidgetWindow::closeEvent(QCloseEvent *event)
892{
893 Q_D(QWidgetWindow);
894 if (qt_popup_down == m_widget) {
895 qt_popup_down = nullptr;
897 }
898 bool accepted = m_widget->d_func()->handleClose(d->inClose ? QWidgetPrivate::CloseWithEvent
899 : QWidgetPrivate::CloseWithSpontaneousEvent);
900 event->setAccepted(accepted);
901}
902
904{
905 Q_Q(const QWidgetWindow);
906
907 // For historical reasons WA_QuitOnClose has been closely tied
908 // to the lastWindowClosed signal, since the default behavior
909 // is to quit the application after emitting lastWindowClosed.
910 // ### Qt 7: Rename this attribute, or decouple behavior.
911 if (!q->widget()->testAttribute(Qt::WA_QuitOnClose))
912 return false;
913
914 return QWindowPrivate::participatesInLastWindowClosed();
915}
916
918{
919 Q_Q(const QWidgetWindow);
920
921 // Widget windows may have Qt::WA_DontShowOnScreen, in which case the
922 // QQWidget will be visible, but the corresponding QWindow will not.
923 // Since the lastWindowClosed logic relies on checking whether the
924 // closed window was visible, and if there are any remaining visible
925 // windows, we need to reflect the QWidget state, not the QWindow one.
926 return q->widget()->isVisible();
927}
928
929#if QT_CONFIG(wheelevent)
930
931void QWidgetWindow::handleWheelEvent(QWheelEvent *event)
932{
933 if (QApplicationPrivate::instance()->modalState() && !qt_try_modal(m_widget, event->type()))
934 return;
935
936 QWidget *rootWidget = m_widget;
937 QPointF pos = event->position();
938
939 // Use proper popup window for wheel event. Some QPA sends the wheel
940 // event to the root menu, so redirect it to the proper popup window.
941 QWidget *activePopupWidget = QApplication::activePopupWidget();
942 if (activePopupWidget && activePopupWidget != m_widget) {
943 rootWidget = activePopupWidget;
944 pos = rootWidget->mapFromGlobal(event->globalPosition());
945 }
946
947 // which child should have it?
948 QWidget *widget = rootWidget->childAt(pos);
949
950 if (!widget)
951 widget = rootWidget;
952
953 QPointF mapped = widget->mapFrom(rootWidget, pos);
954
955 QWheelEvent translated(mapped, event->globalPosition(), event->pixelDelta(), event->angleDelta(),
956 event->buttons(), event->modifiers(), event->phase(), event->inverted(),
957 event->source(), event->pointingDevice());
958 translated.setTimestamp(event->timestamp());
959 QGuiApplication::forwardEvent(widget, &translated, event);
960}
961
962#endif // QT_CONFIG(wheelevent)
963
964#if QT_CONFIG(draganddrop)
965
966static QWidget *findDnDTarget(QWidget *parent, const QPointF &pos)
967{
968 // Find a target widget under mouse that accepts drops (QTBUG-22987).
969 QWidget *widget = parent->childAt(pos);
970 if (!widget)
971 widget = parent;
972 for ( ; widget && !widget->isWindow() && !widget->acceptDrops(); widget = widget->parentWidget()) ;
973 if (widget && !widget->acceptDrops())
974 widget = nullptr;
975 return widget;
976}
977
978/*!
979 \internal
980
981 Sends \a event to \a widget.
982
983 Also called from dragMoveEvent(), in which case \a event is-a
984 QDragMoveEvent only, not a full QDragEnterEvent, which is why this function
985 takes \a event as a QDragMoveEvent and not, as one would expect,
986 QDragEnterEvent (downcast would be UB).
987*/
988void QWidgetWindow::handleDragEnterEvent(QDragMoveEvent *event, QWidget *widget)
989{
990 Q_ASSERT(m_dragTarget == nullptr);
991 if (!widget)
992 widget = findDnDTarget(m_widget, event->position());
993 if (!widget) {
994 event->ignore();
995 return;
996 }
997 m_dragTarget = widget;
998
999 const QPointF mapped = widget->mapFromGlobal(m_widget->mapToGlobal(event->position()));
1000 QDragEnterEvent translated(mapped, event->possibleActions(), event->mimeData(),
1001 event->buttons(), event->modifiers());
1002 QGuiApplication::forwardEvent(m_dragTarget, &translated, event);
1003 event->setAccepted(translated.isAccepted());
1004 event->setDropAction(translated.dropAction());
1005}
1006
1007void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event)
1008{
1009 QPointer<QWidget> widget = findDnDTarget(m_widget, event->position());
1010 if (!widget) {
1011 event->ignore();
1012 if (m_dragTarget) { // Send DragLeave to previous
1013 QDragLeaveEvent leaveEvent;
1014 QWidget *dragTarget = m_dragTarget;
1015 m_dragTarget = nullptr;
1016 QGuiApplication::forwardEvent(dragTarget, &leaveEvent, event);
1017 }
1018 } else {
1019 const QPointF mapped = widget->mapFromGlobal(m_widget->mapToGlobal(event->position()));
1020 QDragMoveEvent translated(mapped, event->possibleActions(), event->mimeData(),
1021 event->buttons(), event->modifiers());
1022
1023 if (widget == m_dragTarget) { // Target widget unchanged: Send DragMove
1024 translated.setDropAction(event->dropAction());
1025 translated.setAccepted(event->isAccepted());
1026 QGuiApplication::forwardEvent(m_dragTarget, &translated, event);
1027 } else {
1028 if (m_dragTarget) { // Send DragLeave to previous
1029 QDragLeaveEvent leaveEvent;
1030 QWidget *dragTarget = m_dragTarget;
1031 m_dragTarget = nullptr;
1032 QGuiApplication::forwardEvent(dragTarget, &leaveEvent, event);
1033 }
1034 // widget might have been deleted when handling the leaveEvent
1035 if (widget) {
1036 // Send DragEnter to new widget.
1037 handleDragEnterEvent(event, widget);
1038 // Handling 'DragEnter' should suffice for the application.
1039 translated.setDropAction(event->dropAction());
1040 translated.setAccepted(event->isAccepted());
1041 // The drag enter event is always immediately followed by a drag move event,
1042 // see QDragEnterEvent documentation.
1043 if (m_dragTarget)
1044 QGuiApplication::forwardEvent(m_dragTarget, &translated, event);
1045 }
1046 }
1047 event->setAccepted(translated.isAccepted());
1048 event->setDropAction(translated.dropAction());
1049 }
1050}
1051
1052void QWidgetWindow::handleDragLeaveEvent(QDragLeaveEvent *event)
1053{
1054 if (m_dragTarget) {
1055 QWidget *dragTarget = m_dragTarget;
1056 m_dragTarget = nullptr;
1057 QGuiApplication::forwardEvent(dragTarget, event);
1058 }
1059}
1060
1061void QWidgetWindow::handleDropEvent(QDropEvent *event)
1062{
1063 if (Q_UNLIKELY(m_dragTarget.isNull())) {
1064 qWarning() << m_widget << ": No drag target set.";
1065 event->ignore();
1066 return;
1067 }
1068 const QPointF mapped = m_dragTarget->mapFromGlobal(m_widget->mapToGlobal(event->position()));
1069 QDropEvent translated(mapped, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
1070 QWidget *dragTarget = m_dragTarget;
1071 m_dragTarget = nullptr;
1072 QGuiApplication::forwardEvent(dragTarget, &translated, event);
1073 event->setAccepted(translated.isAccepted());
1074 event->setDropAction(translated.dropAction());
1075}
1076
1077#endif // QT_CONFIG(draganddrop)
1078
1079void QWidgetWindow::handleExposeEvent(QExposeEvent *event)
1080{
1081 if (m_widget->testAttribute(Qt::WA_DontShowOnScreen))
1082 return; // Ignore for widgets that fake exposure
1083
1084 QWidgetPrivate *wPriv = m_widget->d_func();
1085 const bool exposed = isExposed();
1086
1087 // We might get an expose event from the platform as part of
1088 // closing the window from ~QWidget, to support animated close
1089 // transitions. But at that point we no longer have a widget
1090 // subclass to draw a new frame, so skip the expose event.
1091 if (exposed && wPriv->data.in_destructor)
1092 return;
1093
1094 if (wPriv->childrenHiddenByWState) {
1095 // If widgets has been previously hidden by window state change event
1096 // and they aren't yet shown...
1097 if (exposed) {
1098 // If the window becomes exposed...
1099 if (!wPriv->childrenShownByExpose) {
1100 // ... and they haven't been shown by this function yet - show it.
1101 wPriv->showChildren(true);
1102 QShowEvent showEvent;
1103 QCoreApplication::forwardEvent(m_widget, &showEvent, event);
1104 wPriv->childrenShownByExpose = true;
1105 }
1106 } else {
1107 // If the window becomes not exposed...
1108 if (wPriv->childrenShownByExpose) {
1109 // ... and child widgets was previously shown by the expose event - hide widgets again.
1110 // This is a workaround, because sometimes when window is minimized programmatically,
1111 // the QPA can notify that the window is exposed after changing window state to minimized
1112 // and then, the QPA can send next expose event with null exposed region (not exposed).
1113 wPriv->hideChildren(true);
1114 QHideEvent hideEvent;
1115 QCoreApplication::forwardEvent(m_widget, &hideEvent, event);
1116 wPriv->childrenShownByExpose = false;
1117 }
1118 }
1119 }
1120
1121 if (exposed) {
1122 // QTBUG-39220, QTBUG-58575: set all (potentially fully obscured parent widgets) mapped.
1123 m_widget->setAttribute(Qt::WA_Mapped);
1124 for (QWidget *p = m_widget->parentWidget(); p && !p->testAttribute(Qt::WA_Mapped); p = p->parentWidget())
1125 p->setAttribute(Qt::WA_Mapped);
1126 if (!event->m_region.isNull())
1127 wPriv->syncBackingStore(event->m_region);
1128 } else {
1129 m_widget->setAttribute(Qt::WA_Mapped, false);
1130 }
1131}
1132
1133void QWidgetWindow::handleWindowStateChangedEvent(QWindowStateChangeEvent *event)
1134{
1135 // QWindow does currently not know 'active'.
1136 Qt::WindowStates eventState = event->oldState();
1137 Qt::WindowStates widgetState = m_widget->windowState();
1138 Qt::WindowStates windowState = windowStates();
1139 if (widgetState & Qt::WindowActive)
1140 eventState |= Qt::WindowActive;
1141
1142 // Determine the new widget state, remember maximized/full screen
1143 // during minimized.
1144 if (windowState & Qt::WindowMinimized) {
1145 widgetState |= Qt::WindowMinimized;
1146 } else {
1147 widgetState = windowState | (widgetState & Qt::WindowActive);
1148 if (windowState) // Maximized or FullScreen
1149 updateNormalGeometry();
1150 }
1151
1152 // Sent event if the state changed (that is, it is not triggered by
1153 // QWidget::setWindowState(), which also sends an event to the widget).
1154 if (widgetState != Qt::WindowStates::Int(m_widget->data->window_state)) {
1155 m_widget->data->window_state = uint(widgetState);
1156 QWindowStateChangeEvent widgetEvent(eventState);
1157 QGuiApplication::forwardEvent(m_widget, &widgetEvent, event);
1158 }
1159}
1160
1161bool QWidgetWindow::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
1162{
1163 return m_widget->nativeEvent(eventType, message, result);
1164}
1165
1166#if QT_CONFIG(tabletevent)
1167void QWidgetWindow::handleTabletEvent(QTabletEvent *event)
1168{
1169 static QPointer<QWidget> qt_tablet_target = nullptr;
1170
1171 QWidget *widget = qt_tablet_target;
1172
1173 if (!widget) {
1174 widget = m_widget->childAt(event->position());
1175 if (!widget)
1176 widget = m_widget;
1177 if (event->type() == QEvent::TabletPress)
1178 qt_tablet_target = widget;
1179 }
1180
1181 if (widget) {
1182 const QPointF mapped = widget->mapFromGlobal(event->globalPosition());
1183 QTabletEvent ev(event->type(), event->pointingDevice(), mapped, event->globalPosition(),
1184 event->pressure(), event->xTilt(), event->yTilt(), event->tangentialPressure(),
1185 event->rotation(), event->z(), event->modifiers(), event->button(), event->buttons());
1186 ev.setTimestamp(event->timestamp());
1187 ev.setAccepted(false);
1188 QGuiApplication::forwardEvent(widget, &ev, event);
1189 event->setAccepted(ev.isAccepted());
1190 }
1191
1192 if (event->type() == QEvent::TabletRelease && event->buttons() == Qt::NoButton)
1193 qt_tablet_target = nullptr;
1194}
1195#endif // QT_CONFIG(tabletevent)
1196
1197#ifndef QT_NO_GESTURES
1198void QWidgetWindow::handleGestureEvent(QNativeGestureEvent *e)
1199{
1200 // copy-pasted code to find correct widget follows:
1201 QObject *receiver = nullptr;
1202 if (auto *popup = QApplication::activePopupWidget()) {
1203 QWidget *popupFocusWidget = popup->focusWidget();
1204 receiver = popupFocusWidget ? popupFocusWidget : popup;
1205 }
1206 if (!receiver)
1207 receiver = QApplication::widgetAt(e->globalPosition().toPoint());
1208 if (!receiver)
1209 receiver = m_widget; // last resort
1210
1211 QApplication::forwardEvent(receiver, e);
1212}
1213#endif // QT_NO_GESTURES
1214
1215#ifndef QT_NO_CONTEXTMENU
1216void QWidgetWindow::handleContextMenuEvent(QContextMenuEvent *e)
1217{
1218 QWidget *receiver = qt_last_mouse_receiver.get();
1219 QPoint pos = e->pos();
1220 QPoint globalPos = e->globalPos();
1221
1222 // Keyboard-originating context menu events are delivered to the focus widget,
1223 // independently of event position.
1224 if (e->reason() == QContextMenuEvent::Keyboard) {
1225 receiver = QWidget::keyboardGrabber();
1226 if (!receiver) {
1227 if (QApplication::activePopupWidget()) {
1228 receiver = (QApplication::activePopupWidget()->focusWidget()
1229 ? QApplication::activePopupWidget()->focusWidget()
1230 : QApplication::activePopupWidget());
1231 } else if (QApplication::focusWidget()) {
1232 receiver = QApplication::focusWidget();
1233 } else {
1234 receiver = m_widget;
1235 }
1236 }
1237 if (Q_LIKELY(receiver)) {
1238 pos = receiver->inputMethodQuery(Qt::ImCursorRectangle).toRect().center();
1239 globalPos = receiver->mapToGlobal(pos);
1240 }
1241 } else if (Q_LIKELY(receiver)) {
1242 pos = receiver->mapFromGlobal(e->globalPos());
1243 }
1244
1245 if (receiver && receiver->isEnabled()) {
1246 QContextMenuEvent widgetEvent(e->reason(), pos, globalPos, e->modifiers());
1247 QGuiApplication::forwardEvent(receiver, &widgetEvent, e);
1248 }
1249}
1250#endif // QT_NO_CONTEXTMENU
1251
1252void QWidgetWindow::updateObjectName()
1253{
1254 QString name = m_widget->objectName();
1255 if (name.isEmpty())
1256 name = QString::fromUtf8(m_widget->metaObject()->className()) + "Class"_L1;
1257 name += "Window"_L1;
1258 setObjectName(name);
1259}
1260
1261QT_END_NAMESPACE
1262
1263#include "moc_qwidgetwindow_p.cpp"
bool participatesInLastWindowClosed() const override
QPalette windowPalette() const override
bool treatAsVisible() const override
void setNativeWindowVisibility(bool visible)
QObject * focusObject() const override
Returns the QObject that will be the final receiver of events tied focus, such as key events.
void handleMoveEvent(QMoveEvent *)
void handleEnterLeaveEvent(QEvent *)
bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result) override
Override this to handle platform dependent events.
bool event(QEvent *) override
Override this to handle any event (ev) sent to the window.
void handleExposeEvent(QExposeEvent *)
void closeEvent(QCloseEvent *) override
Override this to handle close events (ev).
void handleGestureEvent(QNativeGestureEvent *)
void handleWindowStateChangedEvent(QWindowStateChangeEvent *event)
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
Combined button and popup list for selecting options.
Q_WIDGETS_EXPORT bool qt_tab_all_widgets()
QWidget * qt_popup_down
static void sendChangeRecursively(QWidget *widget, QEvent::Type type)
bool qt_popup_down_closed
bool q_evaluateRhiConfig(const QWidget *w, QPlatformBackingStoreRhiConfig *outConfig, QSurface::SurfaceType *outType)
Definition qwidget.cpp:1136
static bool shouldBePropagatedToWidget(QEvent *event)
bool qt_try_modal(QWidget *widget, QEvent::Type type)
QPointer< QWindow > qt_last_mouse_receiver