6#if QT_CONFIG(quicktemplates2_container)
7#include "qquickdialog_p.h"
13#if QT_CONFIG(quicktemplates2_container)
14#include "qquickmenubar_p_p.h"
18#include <QtGui/private/qguiapplication_p.h>
20#include <QtCore/qloggingcategory.h>
21#include <QtGui/private/qeventpoint_p.h>
22#include <QtQuick/private/qquickitem_p.h>
23#include <QtQuick/private/qquickwindowmodule_p.h>
24#include <QtQuick/private/qquickwindowmodule_p_p.h>
25#include <qpa/qplatformwindow_p.h>
29Q_STATIC_LOGGING_CATEGORY(lcPopupWindow,
"qt.quick.controls.popup.window")
31static bool s_popupGrabOk =
false;
36 Q_DECLARE_PUBLIC(QQuickPopupWindow)
48 bool filterPopupSpecialCases(QEvent *event);
51QQuickPopupWindow::QQuickPopupWindow(QQuickPopup *popup, QWindow *parent)
52 : QQuickWindowQmlImpl(*(
new QQuickPopupWindowPrivate),
nullptr)
54 Q_D(QQuickPopupWindow);
57 d->m_popupItem = popup->popupItem();
58 setTransientParent(parent);
60 connect(d->m_popup, &QQuickPopup::windowChanged,
this, &QQuickPopupWindow::windowChanged);
61 connect(d->m_popup, &QQuickPopup::implicitWidthChanged,
this, &QQuickPopupWindow::implicitWidthChanged);
62 connect(d->m_popup, &QQuickPopup::implicitHeightChanged,
this, &QQuickPopupWindow::implicitHeightChanged);
63 if (QQuickWindow *nearestParentItemWindow = d->m_popup->window()) {
64 d->m_popupParentItemWindow = nearestParentItemWindow;
65 connect(d->m_popupParentItemWindow, &QWindow::xChanged,
this, &QQuickPopupWindow::parentWindowXChanged);
66 connect(d->m_popupParentItemWindow, &QWindow::yChanged,
this, &QQuickPopupWindow::parentWindowYChanged);
68 setWidth(d->m_popupItem->implicitWidth());
69 setHeight(d->m_popupItem->implicitHeight());
71 const auto flags = QQuickPopupPrivate::get(popup)->popupWindowType();
74 if (flags & Qt::Popup)
75 setColor(QColorConstants::Transparent);
79 qCDebug(lcPopupWindow) <<
"Created popup window" <<
this <<
"with parent" << parent;
82QQuickPopup *QQuickPopupWindow::popup()
const
84 Q_D(
const QQuickPopupWindow);
88void QQuickPopupWindow::hideEvent(QHideEvent *e)
90 Q_D(QQuickPopupWindow);
91 QQuickWindow::hideEvent(e);
93 QScopedValueRollback<
bool>inHideEventRollback(d->m_inHideEvent,
true);
94 if (QQuickPopup *popup = d->m_popup) {
95#if QT_CONFIG(quicktemplates2_container)
96 QQuickDialog *dialog = qobject_cast<QQuickDialog *>(popup);
97 if (dialog && QQuickPopupPrivate::get(dialog)->visible)
101 popup->setVisible(
false);
105void QQuickPopupWindow::moveEvent(QMoveEvent *e)
107 handlePopupPositionChangeFromWindowSystem(e->pos());
110void QQuickPopupWindow::resizeEvent(QResizeEvent *e)
112 Q_D(QQuickPopupWindow);
113 QQuickWindowQmlImpl::resizeEvent(e);
118 qCDebug(lcPopupWindow).nospace() <<
"A window system event changed the popup's ("
119 << d->m_popup <<
") size to " << e->size();
120 QQuickPopupPrivate *popupPrivate = QQuickPopupPrivate::get(d->m_popup);
122 const auto topLeftFromSystem = global2Local(d->geometry.topLeft());
125 const auto oldX = popupPrivate->x;
126 const auto oldY = popupPrivate->y;
128 if (Q_LIKELY(topLeftFromSystem)) {
129 popupPrivate->x = topLeftFromSystem->x();
130 popupPrivate->y = topLeftFromSystem->y();
133 const QMarginsF windowInsets = popupPrivate->windowInsets();
134 d->m_popupItem->setWidth(e->size().width() - windowInsets.left() - windowInsets.right());
135 d->m_popupItem->setHeight(e->size().height() - windowInsets.top() - windowInsets.bottom());
138 popupPrivate->x = oldX;
139 popupPrivate->y = oldY;
144 Q_Q(QQuickPopupWindow);
145 const bool isTransientParentDestroyed = !q->transientParent() ?
true :
146 QQuickWindowPrivate::get(qobject_cast<QQuickWindow *>(q->transientParent()))->inDestructor;
150 const bool visibleChanged = QWindowPrivate::visible != visible;
153 if (!visible && visibleChanged && QGuiApplicationPrivate::popupCount() == 1 && s_grabbedWindow) {
156 s_popupGrabOk =
false;
157 qCDebug(lcPopupWindow) <<
"The window " << s_grabbedWindow <<
"has disabled global mouse and keyboard grabs.";
161 QQuickWindowQmlImplPrivate::setVisible(visible);
167 if (visible && visibleChanged && QGuiApplicationPrivate::popupCount() == 1 && !s_popupGrabOk) {
168 QWindow *win = m_popup->window();
169 if (QGuiApplication::platformName() == QStringLiteral(
"offscreen"))
171 s_popupGrabOk = win->setKeyboardGrabEnabled(
true);
173 s_popupGrabOk = win->setMouseGrabEnabled(
true);
175 win->setKeyboardGrabEnabled(
false);
177 qCDebug(lcPopupWindow) <<
"The window" << win <<
"has enabled global mouse" << (s_popupGrabOk ?
"and keyboard" :
"") <<
"grabs.";
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
207#if QT_CONFIG(quicktemplates2_container)
208 Q_Q(QQuickPopupWindow);
210 if (!event->isPointerEvent())
213 QQuickPopup *popup = m_popup;
217 auto *pe =
static_cast<QPointerEvent *>(event);
218 const QPointF globalPos = pe->points().first().globalPosition();
219 const QQuickPopup::ClosePolicy closePolicy = popup->closePolicy();
220 QQuickPopup *targetPopup = QQuickPopupPrivate::get(popup)->contains(contentItem->mapFromGlobal(globalPos)) ? popup :
nullptr;
223 QQuickMenu *menu = qobject_cast<QQuickMenu *>(popup);
224 QQuickMenuBar *targetMenuBar =
nullptr;
225 QObject *menuParent = menu;
227 if (
auto *parentMenu = qobject_cast<QQuickMenu *>(menuParent)) {
228 QQuickPopupWindow *popupWindow = QQuickMenuPrivate::get(parentMenu)->popupWindow;
229 auto *popup_d = QQuickPopupPrivate::get(popupWindow->popup());
230 QPointF scenePos = popupWindow->contentItem()->mapFromGlobal(globalPos);
231 if (popup_d->contains(scenePos)) {
232 targetPopup = parentMenu;
235 }
else if (
auto *menuBar = qobject_cast<QQuickMenuBar *>(menuParent)) {
236 const QPointF menuBarPos = menuBar->mapFromGlobal(globalPos);
237 if (menuBar->contains(menuBarPos))
238 targetMenuBar = menuBar;
242 menuParent = menuParent->parent();
245 auto closePopupAndParentMenus = [q]() {
246 QQuickPopup *current = q->popup();
248 qCDebug(lcPopupWindow) <<
"Closing" << current <<
"from an outside pointer press or release event";
250 current = qobject_cast<QQuickMenu *>(current->parent());
254 if (pe->isBeginEvent()) {
261 closePopupAndParentMenus();
263 }
else if (!targetPopup && closePolicy.testAnyFlags(QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnPressOutsideParent)) {
269 if (event->type() != QEvent::NonClientAreaMouseButtonPress && event->type() != QEvent::NonClientAreaMouseButtonDblClick)
270 closePopupAndParentMenus();
273 }
else if (pe->isUpdateEvent()){
274 QQuickWindow *targetWindow =
nullptr;
276 targetWindow = QQuickPopupPrivate::get(targetPopup)->popupWindow;
277 else if (targetMenuBar)
278 targetWindow = targetMenuBar->window();
283 const auto scenePos = pe->point(0).scenePosition();
284 const auto translatedScenePos = targetWindow->mapFromGlobal(globalPos);
285 QMutableEventPoint::setScenePosition(pe->point(0), translatedScenePos);
286 auto *grabber = pe->exclusiveGrabber(pe->point(0));
293 pe->setExclusiveGrabber(pe->point(0),
nullptr);
296 qCDebug(lcPopupWindow) <<
"forwarding" << pe <<
"to popup menu:" << targetWindow;
297 QQuickWindowPrivate::get(targetWindow)->deliveryAgent->event(pe);
300 QMutableEventPoint::setScenePosition(pe->point(0), scenePos);
302 pe->setExclusiveGrabber(pe->point(0), grabber);
303 }
else if (pe->isEndEvent()) {
304 if (!targetPopup && !targetMenuBar && closePolicy.testAnyFlags(QQuickPopup::CloseOnReleaseOutside | QQuickPopup::CloseOnReleaseOutsideParent)) {
307 if (event->type() != QEvent::NonClientAreaMouseButtonRelease)
308 closePopupAndParentMenus();
315 if (QQuickMenu *targetMenu = qobject_cast<QQuickMenu *>(targetPopup)) {
316 qCDebug(lcPopupWindow) <<
"forwarding" << pe <<
"to popup menu:" << targetMenu;
317 QQuickMenuPrivate::get(targetMenu)->handleReleaseWithoutGrab(pe->point(0));
325bool QQuickPopupWindow::event(QEvent *e)
327 Q_D(QQuickPopupWindow);
328 if (d->filterPopupSpecialCases(e))
331 if (QQuickPopup *popup = d->m_popup) {
333 if (!popup->hasFocus() && (e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease)
334#if QT_CONFIG(shortcut)
335 && (!
static_cast<QKeyEvent *>(e)->matches(QKeySequence::Cancel)
336#if defined(Q_OS_ANDROID)
337 ||
static_cast<QKeyEvent *>(e)->key() != Qt::Key_Back
344 return QQuickWindowQmlImpl::event(e);
347void QQuickPopupWindow::windowChanged(QWindow *window)
349 Q_D(QQuickPopupWindow);
350 if (!d->m_popupParentItemWindow.isNull()) {
351 disconnect(d->m_popupParentItemWindow, &QWindow::xChanged,
this, &QQuickPopupWindow::parentWindowXChanged);
352 disconnect(d->m_popupParentItemWindow, &QWindow::yChanged,
this, &QQuickPopupWindow::parentWindowYChanged);
355 d->m_popupParentItemWindow = window;
356 connect(window, &QWindow::xChanged,
this, &QQuickPopupWindow::parentWindowXChanged);
357 connect(window, &QWindow::yChanged,
this, &QQuickPopupWindow::parentWindowYChanged);
359 d->m_popupParentItemWindow.clear();
363std::optional<QPoint> QQuickPopupWindow::global2Local(
const QPoint &pos)
const
365 Q_D(
const QQuickPopupWindow);
366 QQuickPopup *popup = d->m_popup;
368 QWindow *mainWindow = d->m_popupParentItemWindow;
370 mainWindow = transientParent();
371 if (Q_UNLIKELY((!mainWindow || mainWindow != popup->window())))
374 const QPoint scenePos = mainWindow->mapFromGlobal(pos);
376 return popup->parentItem() ? popup->parentItem()->mapFromScene(scenePos).toPoint() : scenePos;
379void QQuickPopupWindow::parentWindowXChanged(
int newX)
381 const auto popupLocalPos = global2Local({x(), y()});
382 if (Q_UNLIKELY(!popupLocalPos))
384 handlePopupPositionChangeFromWindowSystem({ newX + popupLocalPos->x(), y() });
387void QQuickPopupWindow::parentWindowYChanged(
int newY)
389 const auto popupLocalPos = global2Local({x(), y()});
390 if (Q_UNLIKELY(!popupLocalPos))
392 handlePopupPositionChangeFromWindowSystem({ x(), newY + popupLocalPos->y() });
395void QQuickPopupWindow::handlePopupPositionChangeFromWindowSystem(
const QPoint &pos)
397 Q_D(QQuickPopupWindow);
398 QQuickPopup *popup = d->m_popup;
402 const auto windowPos = global2Local(pos);
403 if (Q_LIKELY(windowPos)) {
404 qCDebug(lcPopupWindow).nospace() <<
"A window system event changed the popup's"
405 <<
" (" << d->m_popup <<
") position to " << *windowPos;
406 QQuickPopupPrivate::get(popup)->setEffectivePosFromWindowPos(*windowPos);
410void QQuickPopupWindow::implicitWidthChanged()
412 Q_D(
const QQuickPopupWindow);
413 if (
auto popup = d->m_popup)
414 setWidth(popup->implicitWidth());
417void QQuickPopupWindow::implicitHeightChanged()
419 Q_D(
const QQuickPopupWindow);
420 if (
auto popup = d->m_popup)
421 setHeight(popup->implicitHeight());
Combined button and popup list for selecting options.