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

source code of qtbase/src/widgets/kernel/qwidgetwindow.cpp