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 (QApplicationPrivate::inPopupMode()) {
512 QPointer<QWidget> activePopupWidget = QApplication::activePopupWidget();
513 QPointF mapped = event->position();
514 if (activePopupWidget != m_widget)
515 mapped = activePopupWidget->mapFromGlobal(event->globalPosition());
516 bool releaseAfter = false;
517 QWidget *popupChild = activePopupWidget->childAt(p: mapped);
518
519 if (activePopupWidget != qt_popup_down) {
520 qt_button_down = nullptr;
521 qt_popup_down = nullptr;
522 }
523
524 switch (event->type()) {
525 case QEvent::MouseButtonPress:
526 case QEvent::MouseButtonDblClick:
527 qt_button_down = popupChild;
528 qt_popup_down = activePopupWidget;
529 qt_popup_down_closed = false;
530 break;
531 case QEvent::MouseButtonRelease:
532 releaseAfter = true;
533 break;
534 default:
535 break; // nothing for mouse move
536 }
537
538 if (activePopupWidget->isEnabled()) {
539 // deliver event
540 QPointer<QWidget> receiver = activePopupWidget;
541 QPointF widgetPos = mapped;
542 if (qt_button_down)
543 receiver = qt_button_down;
544 else if (popupChild)
545 receiver = popupChild;
546 if (receiver != activePopupWidget)
547 widgetPos = receiver->mapFromGlobal(event->globalPosition());
548
549 const bool reallyUnderMouse = activePopupWidget->rect().contains(p: mapped.toPoint());
550 const bool underMouse = activePopupWidget->underMouse();
551 if (underMouse != reallyUnderMouse) {
552 if (reallyUnderMouse) {
553 const QPoint receiverMapped = receiver->mapFromGlobal(event->globalPosition().toPoint());
554 // Prevent negative mouse position on enter event - this event
555 // should be properly handled in "handleEnterLeaveEvent()".
556 if (receiverMapped.x() >= 0 && receiverMapped.y() >= 0) {
557 QApplicationPrivate::dispatchEnterLeave(enter: receiver, leave: nullptr, globalPosF: event->globalPosition());
558 qt_last_mouse_receiver = receiver;
559 }
560 } else {
561 QApplicationPrivate::dispatchEnterLeave(enter: nullptr, leave: qt_last_mouse_receiver, globalPosF: event->globalPosition());
562 qt_last_mouse_receiver = receiver;
563 receiver = activePopupWidget;
564 }
565 }
566
567 if ((event->type() != QEvent::MouseButtonPress) || !(QMutableSinglePointEvent::from(e: event)->isDoubleClick())) {
568 // if the widget that was pressed is gone, then deliver move events without buttons
569 const auto buttons = event->type() == QEvent::MouseMove && qt_popup_down_closed
570 ? Qt::NoButton : event->buttons();
571 QMouseEvent e(event->type(), widgetPos, event->scenePosition(), event->globalPosition(),
572 event->button(), buttons, event->modifiers(),
573 event->source(), event->pointingDevice());
574 e.setTimestamp(event->timestamp());
575 QApplicationPrivate::sendMouseEvent(receiver, event: &e, alienWidget: receiver, native: receiver->window(), buttonDown: &qt_button_down, lastMouseReceiver&: qt_last_mouse_receiver);
576 qt_last_mouse_receiver = receiver;
577 }
578 } else {
579 // close disabled popups when a mouse button is pressed or released
580 switch (event->type()) {
581 case QEvent::MouseButtonPress:
582 case QEvent::MouseButtonDblClick:
583 case QEvent::MouseButtonRelease:
584 activePopupWidget->close();
585 break;
586 default:
587 break;
588 }
589 }
590
591 if (QApplication::activePopupWidget() != activePopupWidget
592 && QApplicationPrivate::replayMousePress
593 && QGuiApplicationPrivate::platformIntegration()->styleHint(hint: QPlatformIntegration::ReplayMousePressOutsidePopup).toBool()) {
594 if (m_widget->windowType() != Qt::Popup)
595 qt_button_down = nullptr;
596 if (event->type() == QEvent::MouseButtonPress) {
597 // the popup disappeared: replay the mouse press event to whatever is behind it
598 QWidget *w = QApplication::widgetAt(p: event->globalPosition().toPoint());
599 if (w && !QApplicationPrivate::isBlockedByModal(widget: w)) {
600 // activate window of the widget under mouse pointer
601 if (!w->isActiveWindow()) {
602 w->activateWindow();
603 w->window()->raise();
604 }
605
606 if (auto win = qt_widget_private(widget: w)->windowHandle(mode: QWidgetPrivate::WindowHandleMode::Closest)) {
607 const QRect globalGeometry = win->isTopLevel()
608 ? win->geometry()
609 : QRect(win->mapToGlobal(pos: QPoint(0, 0)), win->size());
610 if (globalGeometry.contains(p: event->globalPosition().toPoint())) {
611 // Use postEvent() to ensure the local QEventLoop terminates when called from QMenu::exec()
612 const QPoint localPos = win->mapFromGlobal(pos: event->globalPosition().toPoint());
613 QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonPress, localPos, localPos, event->globalPosition().toPoint(),
614 event->button(), event->buttons(), event->modifiers(), event->source());
615 QCoreApplicationPrivate::setEventSpontaneous(e, spontaneous: true);
616 e->setTimestamp(event->timestamp());
617 QCoreApplication::postEvent(receiver: win, event: e);
618 }
619 }
620 }
621 }
622 QApplicationPrivate::replayMousePress = false;
623 }
624
625 if (releaseAfter) {
626 qt_button_down = nullptr;
627 qt_popup_down_closed = false;
628 qt_popup_down = nullptr;
629 }
630 return;
631 }
632
633 qt_popup_down_closed = false;
634 // modal event handling
635 if (QApplicationPrivate::instance()->modalState() && !qt_try_modal(widget: m_widget, type: event->type()))
636 return;
637
638 // which child should have it?
639 QWidget *widget = m_widget->childAt(p: event->position());
640 QPointF mapped = event->position();
641
642 if (!widget)
643 widget = m_widget;
644
645 const bool initialPress = event->buttons() == event->button();
646 if (event->type() == QEvent::MouseButtonPress && initialPress)
647 qt_button_down = widget;
648
649 QWidget *receiver = QApplicationPrivate::pickMouseReceiver(candidate: m_widget, windowPos: event->scenePosition(), pos: &mapped, type: event->type(), buttons: event->buttons(),
650 buttonDown: qt_button_down, alienWidget: widget);
651 if (!receiver)
652 return;
653
654 if (d_func()->isPopup() && receiver->window()->windowHandle() != this) {
655 receiver = widget;
656 mapped = event->position().toPoint();
657 }
658
659 if ((event->type() != QEvent::MouseButtonPress) || !QMutableSinglePointEvent::from(e: event)->isDoubleClick()) {
660
661 // The preceding statement excludes MouseButtonPress events which caused
662 // creation of a MouseButtonDblClick event. QTBUG-25831
663 QMouseEvent translated(event->type(), mapped, event->scenePosition(), event->globalPosition(),
664 event->button(), event->buttons(), event->modifiers(),
665 event->source(), event->pointingDevice());
666 translated.setTimestamp(event->timestamp());
667 QApplicationPrivate::sendMouseEvent(receiver, event: &translated, alienWidget: widget, native: m_widget,
668 buttonDown: &qt_button_down, lastMouseReceiver&: qt_last_mouse_receiver);
669 event->setAccepted(translated.isAccepted());
670 }
671#ifndef QT_NO_CONTEXTMENU
672 if (event->type() == QGuiApplicationPrivate::contextMenuEventType()
673 && event->button() == Qt::RightButton
674 && m_widget->rect().contains(p: event->position().toPoint())) {
675 QContextMenuEvent e(QContextMenuEvent::Mouse, mapped.toPoint(), event->globalPosition().toPoint(), event->modifiers());
676 QGuiApplication::forwardEvent(receiver, event: &e, originatingEvent: event);
677 if (e.isAccepted())
678 event->accept();
679 }
680#endif
681}
682
683void QWidgetWindow::handleTouchEvent(QTouchEvent *event)
684{
685 if (event->type() == QEvent::TouchCancel) {
686 QApplicationPrivate::translateTouchCancel(device: event->pointingDevice(), timestamp: event->timestamp());
687 event->accept();
688 } else if (QApplicationPrivate::inPopupMode()) {
689 // Ignore touch events for popups. This will cause QGuiApplication to synthesise mouse
690 // events instead, which QWidgetWindow::handleMouseEvent will forward correctly:
691 event->ignore();
692 } else {
693 event->setAccepted(QApplicationPrivate::translateRawTouchEvent(widget: m_widget, touchEvent: event));
694 }
695}
696
697void QWidgetWindow::handleKeyEvent(QKeyEvent *event)
698{
699 if (QApplicationPrivate::instance()->modalState() && !qt_try_modal(widget: m_widget, type: event->type()))
700 return;
701
702 QObject *receiver = QWidget::keyboardGrabber();
703 if (!receiver && QApplicationPrivate::inPopupMode()) {
704 QWidget *popup = QApplication::activePopupWidget();
705 QWidget *popupFocusWidget = popup->focusWidget();
706 receiver = popupFocusWidget ? popupFocusWidget : popup;
707 }
708 if (!receiver)
709 receiver = focusObject();
710 QGuiApplication::forwardEvent(receiver, event);
711}
712
713bool QWidgetWindow::updateSize()
714{
715 bool changed = false;
716 if (m_widget->testAttribute(attribute: Qt::WA_OutsideWSRange))
717 return changed;
718 if (m_widget->testAttribute(attribute: Qt::WA_DontShowOnScreen))
719 return changed;
720
721 if (m_widget->data->crect.size() != geometry().size()) {
722 changed = true;
723 m_widget->data->crect.setSize(geometry().size());
724 }
725
726 updateMargins();
727 return changed;
728}
729
730void QWidgetWindow::updateMargins()
731{
732 // QTBUG-79147 (Windows): Bail out on resize events after closing a dialog
733 // and destroying the platform window which would clear the margins.
734 QTLWExtra *te = m_widget->d_func()->topData();
735 if (te->window == nullptr || te->window->handle() == nullptr)
736 return;
737 const QMargins margins = frameMargins();
738 te->posIncludesFrame= false;
739 te->frameStrut.setCoords(xp1: margins.left(), yp1: margins.top(), xp2: margins.right(), yp2: margins.bottom());
740 m_widget->data->fstrut_dirty = false;
741}
742
743static void sendChangeRecursively(QWidget *widget, QEvent::Type type)
744{
745 QEvent e(type);
746 QCoreApplication::sendEvent(receiver: widget, event: &e);
747 QWidgetPrivate *d = QWidgetPrivate::get(w: widget);
748 for (int i = 0; i < d->children.size(); ++i) {
749 QWidget *w = qobject_cast<QWidget *>(o: d->children.at(i));
750 if (w)
751 sendChangeRecursively(widget: w, type);
752 }
753}
754
755void QWidgetWindow::handleScreenChange()
756{
757 // Send an event recursively to the widget and its children.
758 sendChangeRecursively(widget: m_widget, type: QEvent::ScreenChangeInternal);
759
760 // Invalidate the backing store buffer and repaint immediately.
761 if (screen())
762 repaintWindow();
763}
764
765void QWidgetWindow::handleDevicePixelRatioChange()
766{
767 // Send an event recursively to the widget and its children.
768 sendChangeRecursively(widget: m_widget, type: QEvent::DevicePixelRatioChange);
769
770 // Invalidate the backing store buffer and repaint immediately.
771 if (screen())
772 repaintWindow();
773}
774
775void QWidgetWindow::repaintWindow()
776{
777 if (!m_widget->isVisible() || !m_widget->updatesEnabled() || !m_widget->rect().isValid())
778 return;
779
780 QTLWExtra *tlwExtra = m_widget->window()->d_func()->maybeTopData();
781 if (tlwExtra && tlwExtra->backingStore)
782 tlwExtra->repaintManager->markDirty(r: m_widget->rect(), widget: m_widget,
783 updateTime: QWidgetRepaintManager::UpdateNow, bufferState: QWidgetRepaintManager::BufferInvalid);
784}
785
786// Store normal geometry used for saving application settings.
787void QWidgetWindow::updateNormalGeometry()
788{
789 QTLWExtra *tle = m_widget->d_func()->maybeTopData();
790 if (!tle)
791 return;
792 // Ask platform window, default to widget geometry.
793 QRect normalGeometry;
794 if (const QPlatformWindow *pw = handle())
795 normalGeometry = QHighDpi::fromNativePixels(value: pw->normalGeometry(), context: this);
796 if (!normalGeometry.isValid() && !(m_widget->windowState() & ~Qt::WindowActive))
797 normalGeometry = m_widget->geometry();
798 if (normalGeometry.isValid())
799 tle->normalGeometry = normalGeometry;
800}
801
802void QWidgetWindow::handleMoveEvent(QMoveEvent *event)
803{
804 if (m_widget->testAttribute(attribute: Qt::WA_OutsideWSRange))
805 return;
806 if (m_widget->testAttribute(attribute: Qt::WA_DontShowOnScreen))
807 return;
808
809 auto oldPosition = m_widget->data->crect.topLeft();
810 auto newPosition = geometry().topLeft();
811
812 if (!m_widget->isWindow()) {
813 if (auto *nativeParent = m_widget->nativeParentWidget())
814 newPosition = m_widget->parentWidget()->mapFrom(nativeParent, newPosition);
815 }
816
817 bool changed = newPosition != oldPosition;
818
819 if (changed)
820 m_widget->data->crect.moveTopLeft(p: newPosition);
821
822 updateMargins(); // FIXME: Only do when changed?
823
824 if (changed) {
825 QMoveEvent widgetEvent(newPosition, oldPosition);
826 QGuiApplication::forwardEvent(receiver: m_widget, event: &widgetEvent, originatingEvent: event);
827 }
828}
829
830void QWidgetWindow::handleResizeEvent(QResizeEvent *event)
831{
832 auto oldRect = m_widget->rect();
833
834 if (updateSize()) {
835 QGuiApplication::forwardEvent(receiver: m_widget, event);
836
837 if (m_widget->d_func()->shouldPaintOnScreen()) {
838 QRegion dirtyRegion = m_widget->rect();
839 if (m_widget->testAttribute(attribute: Qt::WA_StaticContents))
840 dirtyRegion -= oldRect;
841 m_widget->d_func()->syncBackingStore(region: dirtyRegion);
842 } else {
843 m_widget->d_func()->syncBackingStore();
844 }
845 }
846}
847
848void QWidgetWindow::closeEvent(QCloseEvent *event)
849{
850 Q_D(QWidgetWindow);
851 if (qt_popup_down == m_widget) {
852 qt_popup_down = nullptr;
853 qt_popup_down_closed = true;
854 }
855 bool accepted = m_widget->d_func()->handleClose(mode: d->inClose ? QWidgetPrivate::CloseWithEvent
856 : QWidgetPrivate::CloseWithSpontaneousEvent);
857 event->setAccepted(accepted);
858}
859
860bool QWidgetWindowPrivate::participatesInLastWindowClosed() const
861{
862 Q_Q(const QWidgetWindow);
863
864 // For historical reasons WA_QuitOnClose has been closely tied
865 // to the lastWindowClosed signal, since the default behavior
866 // is to quit the application after emitting lastWindowClosed.
867 // ### Qt 7: Rename this attribute, or decouple behavior.
868 if (!q->widget()->testAttribute(attribute: Qt::WA_QuitOnClose))
869 return false;
870
871 return QWindowPrivate::participatesInLastWindowClosed();
872}
873
874bool QWidgetWindowPrivate::treatAsVisible() const
875{
876 Q_Q(const QWidgetWindow);
877
878 // Widget windows may have Qt::WA_DontShowOnScreen, in which case the
879 // QQWidget will be visible, but the corresponding QWindow will not.
880 // Since the lastWindowClosed logic relies on checking whether the
881 // closed window was visible, and if there are any remaining visible
882 // windows, we need to reflect the QWidget state, not the QWindow one.
883 return q->widget()->isVisible();
884}
885
886#if QT_CONFIG(wheelevent)
887
888void QWidgetWindow::handleWheelEvent(QWheelEvent *event)
889{
890 if (QApplicationPrivate::instance()->modalState() && !qt_try_modal(widget: m_widget, type: event->type()))
891 return;
892
893 QWidget *rootWidget = m_widget;
894 QPointF pos = event->position();
895
896 // Use proper popup window for wheel event. Some QPA sends the wheel
897 // event to the root menu, so redirect it to the proper popup window.
898 QWidget *activePopupWidget = QApplication::activePopupWidget();
899 if (activePopupWidget && activePopupWidget != m_widget) {
900 rootWidget = activePopupWidget;
901 pos = rootWidget->mapFromGlobal(event->globalPosition());
902 }
903
904 // which child should have it?
905 QWidget *widget = rootWidget->childAt(p: pos);
906
907 if (!widget)
908 widget = rootWidget;
909
910 QPointF mapped = widget->mapFrom(rootWidget, pos);
911
912 QWheelEvent translated(mapped, event->globalPosition(), event->pixelDelta(), event->angleDelta(),
913 event->buttons(), event->modifiers(), event->phase(), event->inverted(),
914 event->source(), event->pointingDevice());
915 translated.setTimestamp(event->timestamp());
916 QGuiApplication::forwardEvent(receiver: widget, event: &translated, originatingEvent: event);
917}
918
919#endif // QT_CONFIG(wheelevent)
920
921#if QT_CONFIG(draganddrop)
922
923static QWidget *findDnDTarget(QWidget *parent, const QPoint &pos)
924{
925 // Find a target widget under mouse that accepts drops (QTBUG-22987).
926 QWidget *widget = parent->childAt(p: pos);
927 if (!widget)
928 widget = parent;
929 for ( ; widget && !widget->isWindow() && !widget->acceptDrops(); widget = widget->parentWidget()) ;
930 if (widget && !widget->acceptDrops())
931 widget = nullptr;
932 return widget;
933}
934
935void QWidgetWindow::handleDragEnterEvent(QDragEnterEvent *event, QWidget *widget)
936{
937 Q_ASSERT(m_dragTarget == nullptr);
938 if (!widget)
939 widget = findDnDTarget(parent: m_widget, pos: event->position().toPoint());
940 if (!widget) {
941 event->ignore();
942 return;
943 }
944 m_dragTarget = widget;
945
946 const QPoint mapped = widget->mapFromGlobal(m_widget->mapToGlobal(event->position().toPoint()));
947 QDragEnterEvent translated(mapped, event->possibleActions(), event->mimeData(),
948 event->buttons(), event->modifiers());
949 QGuiApplication::forwardEvent(receiver: m_dragTarget, event: &translated, originatingEvent: event);
950 event->setAccepted(translated.isAccepted());
951 event->setDropAction(translated.dropAction());
952}
953
954void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event)
955{
956 QPointer<QWidget> widget = findDnDTarget(parent: m_widget, pos: event->position().toPoint());
957 if (!widget) {
958 event->ignore();
959 if (m_dragTarget) { // Send DragLeave to previous
960 QDragLeaveEvent leaveEvent;
961 QWidget *dragTarget = m_dragTarget;
962 m_dragTarget = nullptr;
963 QGuiApplication::forwardEvent(receiver: dragTarget, event: &leaveEvent, originatingEvent: event);
964 }
965 } else {
966 const QPoint mapped = widget->mapFromGlobal(m_widget->mapToGlobal(event->position().toPoint()));
967 QDragMoveEvent translated(mapped, event->possibleActions(), event->mimeData(),
968 event->buttons(), event->modifiers());
969
970 if (widget == m_dragTarget) { // Target widget unchanged: Send DragMove
971 translated.setDropAction(event->dropAction());
972 translated.setAccepted(event->isAccepted());
973 QGuiApplication::forwardEvent(receiver: m_dragTarget, event: &translated, originatingEvent: event);
974 } else {
975 if (m_dragTarget) { // Send DragLeave to previous
976 QDragLeaveEvent leaveEvent;
977 QWidget *dragTarget = m_dragTarget;
978 m_dragTarget = nullptr;
979 QGuiApplication::forwardEvent(receiver: dragTarget, event: &leaveEvent, originatingEvent: event);
980 }
981 // widget might have been deleted when handling the leaveEvent
982 if (widget) {
983 // Send DragEnter to new widget.
984 handleDragEnterEvent(event: static_cast<QDragEnterEvent*>(event), widget);
985 // Handling 'DragEnter' should suffice for the application.
986 translated.setDropAction(event->dropAction());
987 translated.setAccepted(event->isAccepted());
988 // The drag enter event is always immediately followed by a drag move event,
989 // see QDragEnterEvent documentation.
990 if (m_dragTarget)
991 QGuiApplication::forwardEvent(receiver: m_dragTarget, event: &translated, originatingEvent: event);
992 }
993 }
994 event->setAccepted(translated.isAccepted());
995 event->setDropAction(translated.dropAction());
996 }
997}
998
999void QWidgetWindow::handleDragLeaveEvent(QDragLeaveEvent *event)
1000{
1001 if (m_dragTarget) {
1002 QWidget *dragTarget = m_dragTarget;
1003 m_dragTarget = nullptr;
1004 QGuiApplication::forwardEvent(receiver: dragTarget, event);
1005 }
1006}
1007
1008void QWidgetWindow::handleDropEvent(QDropEvent *event)
1009{
1010 if (Q_UNLIKELY(m_dragTarget.isNull())) {
1011 qWarning() << m_widget << ": No drag target set.";
1012 event->ignore();
1013 return;
1014 }
1015 const QPoint mapped = m_dragTarget->mapFromGlobal(m_widget->mapToGlobal(event->position().toPoint()));
1016 QDropEvent translated(mapped, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
1017 QWidget *dragTarget = m_dragTarget;
1018 m_dragTarget = nullptr;
1019 QGuiApplication::forwardEvent(receiver: dragTarget, event: &translated, originatingEvent: event);
1020 event->setAccepted(translated.isAccepted());
1021 event->setDropAction(translated.dropAction());
1022}
1023
1024#endif // QT_CONFIG(draganddrop)
1025
1026void QWidgetWindow::handleExposeEvent(QExposeEvent *event)
1027{
1028 if (m_widget->testAttribute(attribute: Qt::WA_DontShowOnScreen))
1029 return; // Ignore for widgets that fake exposure
1030
1031 QWidgetPrivate *wPriv = m_widget->d_func();
1032 const bool exposed = isExposed();
1033
1034 if (wPriv->childrenHiddenByWState) {
1035 // If widgets has been previously hidden by window state change event
1036 // and they aren't yet shown...
1037 if (exposed) {
1038 // If the window becomes exposed...
1039 if (!wPriv->childrenShownByExpose) {
1040 // ... and they haven't been shown by this function yet - show it.
1041 wPriv->showChildren(spontaneous: true);
1042 QShowEvent showEvent;
1043 QCoreApplication::forwardEvent(receiver: m_widget, event: &showEvent, originatingEvent: event);
1044 wPriv->childrenShownByExpose = true;
1045 }
1046 } else {
1047 // If the window becomes not exposed...
1048 if (wPriv->childrenShownByExpose) {
1049 // ... and child widgets was previously shown by the expose event - hide widgets again.
1050 // This is a workaround, because sometimes when window is minimized programmatically,
1051 // the QPA can notify that the window is exposed after changing window state to minimized
1052 // and then, the QPA can send next expose event with null exposed region (not exposed).
1053 wPriv->hideChildren(spontaneous: true);
1054 QHideEvent hideEvent;
1055 QCoreApplication::forwardEvent(receiver: m_widget, event: &hideEvent, originatingEvent: event);
1056 wPriv->childrenShownByExpose = false;
1057 }
1058 }
1059 }
1060
1061 if (exposed) {
1062 // QTBUG-39220, QTBUG-58575: set all (potentially fully obscured parent widgets) mapped.
1063 m_widget->setAttribute(Qt::WA_Mapped);
1064 for (QWidget *p = m_widget->parentWidget(); p && !p->testAttribute(attribute: Qt::WA_Mapped); p = p->parentWidget())
1065 p->setAttribute(Qt::WA_Mapped);
1066 if (!event->m_region.isNull())
1067 wPriv->syncBackingStore(region: event->m_region);
1068 } else {
1069 m_widget->setAttribute(Qt::WA_Mapped, on: false);
1070 }
1071}
1072
1073void QWidgetWindow::handleWindowStateChangedEvent(QWindowStateChangeEvent *event)
1074{
1075 // QWindow does currently not know 'active'.
1076 Qt::WindowStates eventState = event->oldState();
1077 Qt::WindowStates widgetState = m_widget->windowState();
1078 Qt::WindowStates windowState = windowStates();
1079 if (widgetState & Qt::WindowActive)
1080 eventState |= Qt::WindowActive;
1081
1082 // Determine the new widget state, remember maximized/full screen
1083 // during minimized.
1084 if (windowState & Qt::WindowMinimized) {
1085 widgetState |= Qt::WindowMinimized;
1086 } else {
1087 widgetState = windowState | (widgetState & Qt::WindowActive);
1088 if (windowState) // Maximized or FullScreen
1089 updateNormalGeometry();
1090 }
1091
1092 // Sent event if the state changed (that is, it is not triggered by
1093 // QWidget::setWindowState(), which also sends an event to the widget).
1094 if (widgetState != Qt::WindowStates::Int(m_widget->data->window_state)) {
1095 m_widget->data->window_state = uint(widgetState);
1096 QWindowStateChangeEvent widgetEvent(eventState);
1097 QGuiApplication::forwardEvent(receiver: m_widget, event: &widgetEvent, originatingEvent: event);
1098 }
1099}
1100
1101bool QWidgetWindow::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
1102{
1103 return m_widget->nativeEvent(eventType, message, result);
1104}
1105
1106#if QT_CONFIG(tabletevent)
1107void QWidgetWindow::handleTabletEvent(QTabletEvent *event)
1108{
1109 static QPointer<QWidget> qt_tablet_target = nullptr;
1110
1111 QWidget *widget = qt_tablet_target;
1112
1113 if (!widget) {
1114 widget = m_widget->childAt(p: event->position());
1115 if (!widget)
1116 widget = m_widget;
1117 if (event->type() == QEvent::TabletPress)
1118 qt_tablet_target = widget;
1119 }
1120
1121 if (widget) {
1122 QPointF delta = event->globalPosition() - event->globalPosition().toPoint();
1123 QPointF mapped = widget->mapFromGlobal(event->globalPosition().toPoint()) + delta;
1124 QTabletEvent ev(event->type(), event->pointingDevice(), mapped, event->globalPosition(),
1125 event->pressure(), event->xTilt(), event->yTilt(), event->tangentialPressure(),
1126 event->rotation(), event->z(), event->modifiers(), event->button(), event->buttons());
1127 ev.setTimestamp(event->timestamp());
1128 ev.setAccepted(false);
1129 QGuiApplication::forwardEvent(receiver: widget, event: &ev, originatingEvent: event);
1130 event->setAccepted(ev.isAccepted());
1131 }
1132
1133 if (event->type() == QEvent::TabletRelease && event->buttons() == Qt::NoButton)
1134 qt_tablet_target = nullptr;
1135}
1136#endif // QT_CONFIG(tabletevent)
1137
1138#ifndef QT_NO_GESTURES
1139void QWidgetWindow::handleGestureEvent(QNativeGestureEvent *e)
1140{
1141 // copy-pasted code to find correct widget follows:
1142 QObject *receiver = nullptr;
1143 if (QApplicationPrivate::inPopupMode()) {
1144 QWidget *popup = QApplication::activePopupWidget();
1145 QWidget *popupFocusWidget = popup->focusWidget();
1146 receiver = popupFocusWidget ? popupFocusWidget : popup;
1147 }
1148 if (!receiver)
1149 receiver = QApplication::widgetAt(p: e->globalPosition().toPoint());
1150 if (!receiver)
1151 receiver = m_widget; // last resort
1152
1153 QApplication::forwardEvent(receiver, event: e);
1154}
1155#endif // QT_NO_GESTURES
1156
1157#ifndef QT_NO_CONTEXTMENU
1158void QWidgetWindow::handleContextMenuEvent(QContextMenuEvent *e)
1159{
1160 // We are only interested in keyboard originating context menu events here,
1161 // mouse originated context menu events for widgets are generated in mouse handling methods.
1162 if (e->reason() != QContextMenuEvent::Keyboard)
1163 return;
1164
1165 QWidget *fw = QWidget::keyboardGrabber();
1166 if (!fw) {
1167 if (QApplication::activePopupWidget()) {
1168 fw = (QApplication::activePopupWidget()->focusWidget()
1169 ? QApplication::activePopupWidget()->focusWidget()
1170 : QApplication::activePopupWidget());
1171 } else if (QApplication::focusWidget()) {
1172 fw = QApplication::focusWidget();
1173 } else {
1174 fw = m_widget;
1175 }
1176 }
1177 if (fw && fw->isEnabled()) {
1178 QPoint pos = fw->inputMethodQuery(Qt::ImCursorRectangle).toRect().center();
1179 QContextMenuEvent widgetEvent(QContextMenuEvent::Keyboard, pos, fw->mapToGlobal(pos),
1180 e->modifiers());
1181 QGuiApplication::forwardEvent(receiver: fw, event: &widgetEvent, originatingEvent: e);
1182 }
1183}
1184#endif // QT_NO_CONTEXTMENU
1185
1186void QWidgetWindow::updateObjectName()
1187{
1188 QString name = m_widget->objectName();
1189 if (name.isEmpty())
1190 name = QString::fromUtf8(utf8: m_widget->metaObject()->className()) + "Class"_L1;
1191 name += "Window"_L1;
1192 setObjectName(name);
1193}
1194
1195QT_END_NAMESPACE
1196
1197#include "moc_qwidgetwindow_p.cpp"
1198

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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