summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qwindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/kernel/qwindow.cpp')
-rw-r--r--src/gui/kernel/qwindow.cpp95
1 files changed, 87 insertions, 8 deletions
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 46a787e706..cd3af8598d 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -27,6 +27,8 @@
#endif // QT_CONFIG(draganddrop)
#include <private/qevent_p.h>
+#include <private/qeventpoint_p.h>
+#include <private/qguiapplication_p.h>
#include <QtCore/QTimer>
#include <QtCore/QDebug>
@@ -37,6 +39,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcPopup)
+
/*!
\class QWindow
\inmodule QtGui
@@ -186,6 +190,7 @@ QWindow::~QWindow()
// Decouple from parent before window goes under
setParent(nullptr);
QGuiApplicationPrivate::window_list.removeAll(this);
+ QGuiApplicationPrivate::popup_list.removeAll(this);
if (!QGuiApplicationPrivate::is_app_closing)
QGuiApplicationPrivate::instance()->modalWindowList.removeOne(this);
@@ -411,6 +416,13 @@ void QWindowPrivate::setVisible(bool visible)
QGuiApplicationPrivate::updateBlockedStatus(q);
}
+ if (q->type() == Qt::Popup) {
+ if (visible)
+ QGuiApplicationPrivate::activatePopup(q);
+ else
+ QGuiApplicationPrivate::closePopup(q);
+ }
+
#ifndef QT_NO_CURSOR
if (visible && (hasCursor || QGuiApplication::overrideCursor()))
applyCursor();
@@ -521,7 +533,9 @@ void QWindowPrivate::setTopLevelScreen(QScreen *newScreen, bool recreate)
}
}
-void QWindowPrivate::create(bool recursive, WId nativeHandle)
+static constexpr auto kForeignWindowId = "_q_foreignWinId";
+
+void QWindowPrivate::create(bool recursive)
{
Q_Q(QWindow);
if (platformWindow)
@@ -549,6 +563,8 @@ void QWindowPrivate::create(bool recursive, WId nativeHandle)
setTopLevelScreen(screen, false);
}
+ const WId nativeHandle = q->property(kForeignWindowId).value<WId>();
+
QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
platformWindow = nativeHandle ? platformIntegration->createForeignWindow(q, nativeHandle)
: platformIntegration->createPlatformWindow(q);
@@ -2059,6 +2075,16 @@ void QWindowPrivate::destroy()
QObject *object = childrenWindows.at(i);
if (object->isWindowType()) {
QWindow *w = static_cast<QWindow*>(object);
+ auto *childPlatformWindow = w->handle();
+ if (!childPlatformWindow)
+ continue;
+
+ // Decouple the foreign window from this window,
+ // so that destroying our native handle doesn't
+ // bring down the foreign window as well.
+ if (childPlatformWindow->isForeignWindow())
+ childPlatformWindow->setParent(nullptr);
+
qt_window_private(w)->destroy();
}
}
@@ -2347,8 +2373,13 @@ bool QWindow::close()
if (!isTopLevel())
return false;
- if (!d->platformWindow)
+ if (!d->platformWindow) {
+ // dock widgets can transition back and forth to being popups;
+ // avoid getting stuck
+ if (QGuiApplicationPrivate::activePopupWindow() == this)
+ QGuiApplicationPrivate::closePopup(this);
return true;
+ }
// The window might be deleted during close,
// as a result of delivering the close event.
@@ -2388,6 +2419,52 @@ bool QWindowPrivate::treatAsVisible() const
return q->isVisible();
}
+/*! \internal
+ Returns the popup window that has consumed \a event, if any.
+ \a activePopupOnPress is the window that we have observed previously handling the press.
+*/
+const QWindow *QWindowPrivate::forwardToPopup(QEvent *event, const QWindow */*activePopupOnPress*/)
+{
+ Q_Q(const QWindow);
+ qCDebug(lcPopup) << "checking for popup alternative to" << q << "for" << event
+ << "active popup?" << QGuiApplicationPrivate::activePopupWindow();
+ QWindow *ret = nullptr;
+ if (QWindow *popupWindow = QGuiApplicationPrivate::activePopupWindow()) {
+ if (q == popupWindow)
+ return nullptr; // avoid infinite recursion: we're already handling it
+ if (event->isPointerEvent()) {
+ // detach eventPoints before modifying them
+ QScopedPointer<QPointerEvent> pointerEvent(static_cast<QPointerEvent *>(event)->clone());
+ for (int i = 0; i < pointerEvent->pointCount(); ++i) {
+ QEventPoint &eventPoint = pointerEvent->point(i);
+ const QPoint globalPos = eventPoint.globalPosition().toPoint();
+ const QPointF mapped = popupWindow->mapFromGlobal(globalPos);
+ QMutableEventPoint::setPosition(eventPoint, mapped);
+ QMutableEventPoint::setScenePosition(eventPoint, mapped);
+ }
+
+ /* Popups are expected to be able to directly handle the
+ drag-release sequence after pressing to open, as well as
+ any other mouse events that occur within the popup's bounds. */
+ if (QCoreApplication::sendEvent(popupWindow, pointerEvent.get())) {
+ event->setAccepted(pointerEvent->isAccepted());
+ if (pointerEvent->isAccepted())
+ ret = popupWindow;
+ }
+ qCDebug(lcPopup) << q << "forwarded" << event->type() << "to popup" << popupWindow
+ << "handled?" << (ret != nullptr) << event->isAccepted();
+ return ret;
+ } else if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
+ if (QCoreApplication::sendEvent(popupWindow, event))
+ ret = popupWindow;
+ qCDebug(lcPopup) << q << "forwarded" << event->type() << "to popup" << popupWindow
+ << "handled?" << (ret != nullptr) << event->isAccepted();
+ return ret;
+ }
+ }
+ return ret;
+}
+
/*!
The expose event (\a ev) is sent by the window system when a window moves
between the un-exposed and exposed states.
@@ -2640,16 +2717,14 @@ bool QWindow::event(QEvent *ev)
This logic could be simplified by always synthesizing events in
QGuiApplicationPrivate, or perhaps even in each QPA plugin. See QTBUG-93486.
*/
- static const QEvent::Type contextMenuTrigger =
- QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ContextMenuOnMouseRelease).toBool() ?
- QEvent::MouseButtonRelease : QEvent::MouseButtonPress;
auto asMouseEvent = [](QEvent *ev) {
const auto t = ev->type();
return t == QEvent::MouseButtonPress || t == QEvent::MouseButtonRelease
? static_cast<QMouseEvent *>(ev) : nullptr ;
};
- if (QMouseEvent *me = asMouseEvent(ev); me &&
- ev->type() == contextMenuTrigger && me->button() == Qt::RightButton) {
+ if (QMouseEvent *me = asMouseEvent(ev);
+ me && ev->type() == QGuiApplicationPrivate::contextMenuEventType()
+ && me->button() == Qt::RightButton) {
QContextMenuEvent e(QContextMenuEvent::Mouse, me->position().toPoint(),
me->globalPosition().toPoint(), me->modifiers());
QGuiApplication::sendEvent(this, &e);
@@ -2986,7 +3061,11 @@ QWindow *QWindow::fromWinId(WId id)
}
QWindow *window = new QWindow;
- qt_window_private(window)->create(false, id);
+
+ // Persist the winId in a private property so that we
+ // can recreate the window after being destroyed.
+ window->setProperty(kForeignWindowId, id);
+ window->create();
if (!window->handle()) {
delete window;