summaryrefslogtreecommitdiffstats
path: root/src/compositor
diff options
context:
space:
mode:
authorPaul Olav Tvete <paul.tvete@theqtcompany.com>2016-05-25 16:28:52 +0200
committerPaul Olav Tvete <paul.tvete@theqtcompany.com>2016-05-31 08:03:10 +0000
commitfd9eefba8089ff9cd0bfe986dc527bbdb0630b02 (patch)
tree8da1ee5f02d49b641bf1be2eaf73537e0ea5e5bf /src/compositor
parent1f1db8e85eb088f7aaf42c2e15b31e3bb84bfb0d (diff)
Fix for popups
Introduce a singleton event filter that keeps working if the popup is deleted. Move the event filter class to qwaylandquickshellsurfaceitem, so it can be used by the XDG shell. Change-Id: I58998a7e62697bf6f54536d2c2e2732ceb4d970e Reviewed-by: Johan Helsing <johan.helsing@qt.io> Reviewed-by: Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
Diffstat (limited to 'src/compositor')
-rw-r--r--src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp81
-rw-r--r--src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h20
-rw-r--r--src/compositor/extensions/qwaylandwlshellintegration.cpp64
-rw-r--r--src/compositor/extensions/qwaylandwlshellintegration_p.h5
4 files changed, 104 insertions, 66 deletions
diff --git a/src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp b/src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp
index 4b087183f..bfad242cc 100644
--- a/src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp
+++ b/src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp
@@ -38,6 +38,7 @@
#include "qwaylandquickshellsurfaceitem_p.h"
#include <QtWaylandCompositor/QWaylandShellSurface>
+#include <QGuiApplication>
QT_BEGIN_NAMESPACE
@@ -148,4 +149,84 @@ void QWaylandQuickShellSurfaceItem::mouseReleaseEvent(QMouseEvent *event)
QWaylandQuickItem::mouseReleaseEvent(event);
}
+/*!
+\class QWaylandQuickShellEventFilter
+\brief QWaylandQuickShellEventFilter implements a Wayland popup grab
+\internal
+*/
+
+void QWaylandQuickShellEventFilter::startFilter(QWaylandClient *client, CallbackFunction closePopups)
+{
+ if (!self)
+ self = new QWaylandQuickShellEventFilter(qGuiApp);
+ if (!self->eventFilterInstalled) {
+ qGuiApp->installEventFilter(self);
+ self->eventFilterInstalled = true;
+ self->client = client;
+ self->closePopups = closePopups;
+ }
+}
+
+void QWaylandQuickShellEventFilter::cancelFilter()
+{
+ if (!self)
+ return;
+ if (self->eventFilterInstalled && !self->waitForRelease)
+ self->stopFilter();
+}
+
+void QWaylandQuickShellEventFilter::stopFilter()
+{
+ if (eventFilterInstalled) {
+ qGuiApp->removeEventFilter(this);
+ eventFilterInstalled = false;
+ }
+}
+QWaylandQuickShellEventFilter *QWaylandQuickShellEventFilter::self = nullptr;
+
+QWaylandQuickShellEventFilter::QWaylandQuickShellEventFilter(QObject *parent)
+ : QObject(parent), eventFilterInstalled(false), waitForRelease(false), closePopups(nullptr)
+{
+}
+
+bool QWaylandQuickShellEventFilter::eventFilter(QObject *receiver, QEvent *e)
+{
+ if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonRelease) {
+ QQuickItem *item = qobject_cast<QQuickItem*>(receiver);
+ if (!item)
+ return false;
+
+ QMouseEvent *event = static_cast<QMouseEvent*>(e);
+ QWaylandQuickShellSurfaceItem *shellSurfaceItem = qobject_cast<QWaylandQuickShellSurfaceItem*>(item);
+ bool press = event->type() == QEvent::MouseButtonPress;
+ bool finalRelease = (event->type() == QEvent::MouseButtonRelease) && (event->buttons() == Qt::NoButton);
+ bool popupClient = shellSurfaceItem && shellSurfaceItem->surface()->client() == client;
+
+ if (waitForRelease) {
+ // We are eating events until all mouse buttons are released
+ if (finalRelease) {
+ waitForRelease = false;
+ stopFilter();
+ }
+ return true;
+ }
+
+ if (press && !popupClient) {
+ // The user clicked outside the active popup's client. The popups should
+ // be closed, but the event filter will stay to catch the release-
+ // event before removing itself.
+ waitForRelease = true;
+ closePopups();
+ return true;
+ } else if (press) {
+ // There is a surface belonging to this client at this coordinate, so we can
+ // remove the event filter and let the normal event handler handle
+ // this event.
+ stopFilter();
+ }
+ }
+
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h b/src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h
index b2d4780ab..c2f46917e 100644
--- a/src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h
+++ b/src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h
@@ -78,6 +78,26 @@ public:
virtual bool mouseReleaseEvent(QMouseEvent *) { return false; }
};
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandQuickShellEventFilter : public QObject
+{
+ Q_OBJECT
+public:
+ typedef void (*CallbackFunction)(void);
+ static void startFilter(QWaylandClient *client, CallbackFunction closePopupCallback);
+ static void cancelFilter();
+
+private:
+ void stopFilter();
+
+ QWaylandQuickShellEventFilter(QObject *parent = nullptr);
+ bool eventFilter(QObject *, QEvent *) Q_DECL_OVERRIDE;
+ bool eventFilterInstalled;
+ bool waitForRelease;
+ QPointer<QWaylandClient> client;
+ CallbackFunction closePopups;
+ static QWaylandQuickShellEventFilter *self;
+};
+
QT_END_NAMESPACE
#endif // QWAYLANDQUICKSHELLSURFACEITEM_P_H
diff --git a/src/compositor/extensions/qwaylandwlshellintegration.cpp b/src/compositor/extensions/qwaylandwlshellintegration.cpp
index ef4e1efc6..5c0fe7c9d 100644
--- a/src/compositor/extensions/qwaylandwlshellintegration.cpp
+++ b/src/compositor/extensions/qwaylandwlshellintegration.cpp
@@ -40,7 +40,6 @@
#include <QtWaylandCompositor/QWaylandWlShellSurface>
#include <QtWaylandCompositor/QWaylandQuickShellSurfaceItem>
#include <QtWaylandCompositor/QWaylandInputDevice>
-#include <QGuiApplication>
QT_BEGIN_NAMESPACE
@@ -158,8 +157,6 @@ bool WlShellIntegration::mouseReleaseEvent(QMouseEvent *event)
}
QVector<QWaylandWlShellSurface*> WlShellIntegration::popupShellSurfaces;
-bool WlShellIntegration::eventFilterInstalled = false;
-bool WlShellIntegration::waitForRelease = false;
void WlShellIntegration::closePopups()
{
@@ -171,52 +168,11 @@ void WlShellIntegration::closePopups()
}
}
-bool WlShellIntegration::eventFilter(QObject *receiver, QEvent *e)
-{
- if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonRelease) {
- QQuickItem *item = qobject_cast<QQuickItem*>(receiver);
- if (!item)
- return false;
-
- QMouseEvent *event = static_cast<QMouseEvent*>(e);
- QWaylandQuickShellSurfaceItem *shellSurfaceItem = qobject_cast<QWaylandQuickShellSurfaceItem*>(item);
- bool press = event->type() == QEvent::MouseButtonPress;
- bool finalRelease = (event->type() == QEvent::MouseButtonRelease) && (event->buttons() == Qt::NoButton);
- bool popupClient = shellSurfaceItem && shellSurfaceItem->surface()->client() == m_shellSurface->surface()->client();
-
- if (waitForRelease) {
- // We are eating events until all mouse buttons are released
- if (finalRelease) {
- waitForRelease = false;
- setFilterEnabled(false);
- }
- return true;
- }
-
- if (press && !popupClient) {
- // The user clicked outside the active popup's client. The popups should
- // be closed, but the event filter will stay to catch the release-
- // event before removing itself.
- waitForRelease = true;
- closePopups();
- return true;
- } else if (press) {
- // There is a surface belonging to this client at this coordinate, so we can
- // remove the event filter and let the normal event handler handle
- // this event.
- setFilterEnabled(false);
- }
- }
-
- return false;
-}
-
void WlShellIntegration::setIsPopup(bool popup)
{
isPopup = popup;
if (popup) {
- if (!eventFilterInstalled)
- setFilterEnabled(true);
+ QWaylandQuickShellEventFilter::startFilter(m_shellSurface->surface()->client(), &closePopups);
if (!popupShellSurfaces.contains(m_shellSurface)) {
popupShellSurfaces.append(m_shellSurface);
@@ -229,23 +185,9 @@ void WlShellIntegration::setIsPopup(bool popup)
QObject::disconnect(m_shellSurface->surface(), &QWaylandSurface::mappedChanged,
this, &WlShellIntegration::handleSurfaceUnmapped);
}
- if (!waitForRelease && eventFilterInstalled && popupShellSurfaces.isEmpty())
- setFilterEnabled(false);
- }
-}
-
-void WlShellIntegration::setFilterEnabled(bool enabled)
-{
- static QPointer<QObject> filter;
-
- if (enabled && filter.isNull()) {
- qGuiApp->installEventFilter(this);
- filter = this;
- } else if (!enabled && !filter.isNull()){
- qGuiApp->removeEventFilter(filter);
- filter = nullptr;
+ if (popupShellSurfaces.isEmpty())
+ QWaylandQuickShellEventFilter::cancelFilter();
}
- eventFilterInstalled = enabled;
}
}
diff --git a/src/compositor/extensions/qwaylandwlshellintegration_p.h b/src/compositor/extensions/qwaylandwlshellintegration_p.h
index 486077200..07bbc63cb 100644
--- a/src/compositor/extensions/qwaylandwlshellintegration_p.h
+++ b/src/compositor/extensions/qwaylandwlshellintegration_p.h
@@ -79,10 +79,7 @@ private:
Move
};
- bool eventFilter(QObject *, QEvent *) Q_DECL_OVERRIDE;
-
void setIsPopup(bool popup);
- void setFilterEnabled(bool enabled);
static void closePopups();
QWaylandQuickShellSurfaceItem *m_item;
@@ -102,8 +99,6 @@ private:
} resizeState;
static QVector<QWaylandWlShellSurface*> popupShellSurfaces;
- static bool eventFilterInstalled;
- static bool waitForRelease;
bool isPopup;
};