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

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