summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Larsson <erik@ortogonal.com>2016-02-06 21:43:36 +0100
committerPaul Olav Tvete <paul.tvete@theqtcompany.com>2016-05-13 10:32:03 +0000
commited7505ecbd0ad211c9157fb4dd8d172ae2c72454 (patch)
treee7951c5af82e468d2543ad8e8d31d2eb758f9037
parent4db2396db5ea11c77bfbd9243f03d9b3fa400955 (diff)
downloadqtwayland-ed7505ecbd0ad211c9157fb4dd8d172ae2c72454.tar.gz
Add popup support to QWaylandQuickCompositor with the wl shell.
When the shell surface emits the QWaylandShell::setPopup signal the QWaylandQuickWlShellSurfaceItem will move it self into its popup-parent, and also remove all transforms (rotation, scaling, etc.), our new parent already have the same transforms set. During the time a popup is active it installs a filter which handles the closing of popups if the user clicks outside the popup. This requires that the background item of the compositor accepts mouse press. Change-Id: I3e4c3c8728795d4b38a30a9bce178dc315643de2 Reviewed-by: Johan Helsing <johan.helsing@qt.io> Reviewed-by: Paul Olav Tvete <paul.tvete@theqtcompany.com> Reviewed-by: Giulio Camuffo <giulio.camuffo@kdab.com>
-rw-r--r--src/compositor/extensions/qwaylandquickwlshellsurfaceitem.cpp144
-rw-r--r--src/compositor/extensions/qwaylandquickwlshellsurfaceitem.h6
-rw-r--r--src/compositor/extensions/qwaylandquickwlshellsurfaceitem_p.h13
-rw-r--r--src/imports/compositor/qwaylandmousetracker.cpp1
4 files changed, 164 insertions, 0 deletions
diff --git a/src/compositor/extensions/qwaylandquickwlshellsurfaceitem.cpp b/src/compositor/extensions/qwaylandquickwlshellsurfaceitem.cpp
index 21b5c75a..393a054c 100644
--- a/src/compositor/extensions/qwaylandquickwlshellsurfaceitem.cpp
+++ b/src/compositor/extensions/qwaylandquickwlshellsurfaceitem.cpp
@@ -39,6 +39,7 @@
#include <QtWaylandCompositor/QWaylandCompositor>
#include <QtWaylandCompositor/QWaylandInputDevice>
+#include <QGuiApplication>
QT_BEGIN_NAMESPACE
@@ -108,11 +109,15 @@ void QWaylandQuickWlShellSurfaceItem::setShellSurface(QWaylandWlShellSurface *sh
if (d->shellSurface) {
disconnect(d->shellSurface, &QWaylandWlShellSurface::startMove, this, &QWaylandQuickWlShellSurfaceItem::handleStartMove);
disconnect(d->shellSurface, &QWaylandWlShellSurface::startResize, this, &QWaylandQuickWlShellSurfaceItem::handleStartResize);
+ disconnect(d->shellSurface, &QWaylandWlShellSurface::setPopup, this, &QWaylandQuickWlShellSurfaceItem::handleSetPopup);
+ disconnect(d->shellSurface, &QWaylandWlShellSurface::destroyed, this, &QWaylandQuickWlShellSurfaceItem::handleShellSurfaceDestroyed);
}
d->shellSurface = shellSurface;
if (d->shellSurface) {
connect(d->shellSurface, &QWaylandWlShellSurface::startMove, this, &QWaylandQuickWlShellSurfaceItem::handleStartMove);
connect(d->shellSurface, &QWaylandWlShellSurface::startResize, this, &QWaylandQuickWlShellSurfaceItem::handleStartResize);
+ connect(d->shellSurface, &QWaylandWlShellSurface::setPopup, this, &QWaylandQuickWlShellSurfaceItem::handleSetPopup);
+ connect(d->shellSurface, &QWaylandWlShellSurface::destroyed, this, &QWaylandQuickWlShellSurfaceItem::handleShellSurfaceDestroyed);
}
setSurface(shellSurface ? shellSurface->surface() : nullptr);
emit shellSurfaceChanged();
@@ -166,6 +171,48 @@ void QWaylandQuickWlShellSurfaceItem::handleStartResize(QWaylandInputDevice *inp
/*!
* \internal
*/
+void QWaylandQuickWlShellSurfaceItem::handleSetPopup(QWaylandInputDevice *inputDevice, QWaylandSurface *parent, const QPoint &relativeToParent)
+{
+ Q_UNUSED(inputDevice);
+ Q_D(QWaylandQuickWlShellSurfaceItem);
+
+ QWaylandQuickWlShellSurfaceItem* parentItem = qobject_cast<QWaylandQuickWlShellSurfaceItem*>(parent->views().first()->renderObject());
+ if (parentItem) {
+ // Clear all the transforms for this ShellSurfaceItem. They are not
+ // applicable when the item becomes a child to a surface that has its
+ // own transforms. Otherwise the transforms would be applied twice.
+ QQmlListProperty<QQuickTransform> t = transform();
+ t.clear(&t);
+ setRotation(0);
+ setScale(1.0);
+ setX(relativeToParent.x());
+ setY(relativeToParent.y());
+ setParentItem(parentItem);
+ }
+
+ d->setIsPopup(true);
+}
+
+/*!
+ * \internal
+ */
+void QWaylandQuickWlShellSurfaceItem::handleShellSurfaceDestroyed() {
+ Q_D(QWaylandQuickWlShellSurfaceItem);
+ d->setIsPopup(false);
+ d->shellSurface = NULL;
+}
+
+void QWaylandQuickWlShellSurfaceItem::handleSurfaceUnmapped()
+{
+ Q_D(QWaylandQuickWlShellSurfaceItem);
+ if (!d->shellSurface || !d->shellSurface->surface()->size().isEmpty())
+ return;
+ d->setIsPopup(false);
+}
+
+/*!
+ * \internal
+ */
void QWaylandQuickWlShellSurfaceItem::adjustOffsetForNextFrame(const QPointF &offset)
{
Q_D(QWaylandQuickWlShellSurfaceItem);
@@ -231,4 +278,101 @@ void QWaylandQuickWlShellSurfaceItem::surfaceChangedEvent(QWaylandSurface *newSu
connect(newSurface, &QWaylandSurface::offsetForNextFrame, this, &QWaylandQuickWlShellSurfaceItem::adjustOffsetForNextFrame);
}
+QVector<QWaylandWlShellSurface*> QWaylandQuickWlShellSurfaceItemPrivate::popupShellSurfaces;
+bool QWaylandQuickWlShellSurfaceItemPrivate::eventFilterInstalled = false;
+bool QWaylandQuickWlShellSurfaceItemPrivate::waitForRelease = false;
+
+/*!
+ * \internal
+ */
+void QWaylandQuickWlShellSurfaceItemPrivate::closePopups()
+{
+ if (!popupShellSurfaces.isEmpty()) {
+ Q_FOREACH (QWaylandWlShellSurface* shellSurface, popupShellSurfaces) {
+ shellSurface->sendPopupDone();
+ }
+ popupShellSurfaces.clear();
+ }
+}
+
+bool QWaylandQuickWlShellSurfaceItem::eventFilter(QObject *receiver, QEvent *e)
+{
+ Q_D(QWaylandQuickWlShellSurfaceItem);
+ 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);
+ QWaylandQuickWlShellSurfaceItem *shellSurfaceItem = qobject_cast<QWaylandQuickWlShellSurfaceItem*>(item);
+ bool press = event->type() == QEvent::MouseButtonPress;
+ bool finalRelease = (event->type() == QEvent::MouseButtonRelease) && (event->buttons() == Qt::NoButton);
+ bool popupClient = shellSurfaceItem && shellSurfaceItem->shellSurface()->surface()->client() == shellSurface()->surface()->client();
+
+ if (d->waitForRelease) {
+ // We are eating events until all mouse buttons are released
+ if (finalRelease) {
+ d->waitForRelease = false;
+ d->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.
+ d->waitForRelease = true;
+ d->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.
+ d->setFilterEnabled(false);
+ }
+ }
+
+ return false;
+}
+
+void QWaylandQuickWlShellSurfaceItemPrivate::setIsPopup(bool popup)
+{
+ Q_Q(QWaylandQuickWlShellSurfaceItem);
+ isPopup = popup;
+ if (popup) {
+ if (!eventFilterInstalled)
+ setFilterEnabled(true);
+
+ if (!popupShellSurfaces.contains(shellSurface)) {
+ popupShellSurfaces.append(shellSurface);
+ QObject::connect(shellSurface->surface(), &QWaylandSurface::mappedChanged,
+ q, &QWaylandQuickWlShellSurfaceItem::handleSurfaceUnmapped);
+ }
+ } else {
+ if (shellSurface) {
+ popupShellSurfaces.removeOne(shellSurface);
+ QObject::disconnect(shellSurface->surface(), &QWaylandSurface::mappedChanged,
+ q, &QWaylandQuickWlShellSurfaceItem::handleSurfaceUnmapped);
+ }
+ if (!waitForRelease && eventFilterInstalled && popupShellSurfaces.isEmpty())
+ setFilterEnabled(false);
+ }
+}
+
+void QWaylandQuickWlShellSurfaceItemPrivate::setFilterEnabled(bool enabled)
+{
+ Q_Q(QWaylandQuickWlShellSurfaceItem);
+ static QPointer<QObject> filter;
+
+ if (enabled && filter.isNull()) {
+ qGuiApp->installEventFilter(q);
+ filter = q;
+ } else if (!enabled && !filter.isNull()){
+ qGuiApp->removeEventFilter(filter);
+ filter = nullptr;
+ }
+ eventFilterInstalled = enabled;
+}
+
QT_END_NAMESPACE
diff --git a/src/compositor/extensions/qwaylandquickwlshellsurfaceitem.h b/src/compositor/extensions/qwaylandquickwlshellsurfaceitem.h
index 7f32c9f3..0b24e43a 100644
--- a/src/compositor/extensions/qwaylandquickwlshellsurfaceitem.h
+++ b/src/compositor/extensions/qwaylandquickwlshellsurfaceitem.h
@@ -69,7 +69,11 @@ Q_SIGNALS:
private Q_SLOTS:
void handleStartMove(QWaylandInputDevice *inputDevice);
void handleStartResize(QWaylandInputDevice *inputDevice, QWaylandWlShellSurface::ResizeEdge edges);
+ void handleSetPopup(QWaylandInputDevice *inputDevice, QWaylandSurface *parent, const QPoint &relativeToParent);
+ void handleShellSurfaceDestroyed();
void adjustOffsetForNextFrame(const QPointF &offset);
+
+ void handleSurfaceUnmapped();
protected:
QWaylandQuickWlShellSurfaceItem(QWaylandQuickWlShellSurfaceItemPrivate &dd, QQuickItem *parent);
@@ -77,6 +81,8 @@ protected:
void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void surfaceChangedEvent(QWaylandSurface *newSurface, QWaylandSurface *oldSurface) Q_DECL_OVERRIDE;
+
+ bool eventFilter(QObject *, QEvent *) Q_DECL_OVERRIDE;
};
QT_END_NAMESPACE
diff --git a/src/compositor/extensions/qwaylandquickwlshellsurfaceitem_p.h b/src/compositor/extensions/qwaylandquickwlshellsurfaceitem_p.h
index 3e683477..c4adb28d 100644
--- a/src/compositor/extensions/qwaylandquickwlshellsurfaceitem_p.h
+++ b/src/compositor/extensions/qwaylandquickwlshellsurfaceitem_p.h
@@ -52,8 +52,11 @@ QT_BEGIN_NAMESPACE
// We mean it.
//
+class QWaylandQuickWlShellSurfaceItem;
+
class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandQuickWlShellSurfaceItemPrivate : public QWaylandQuickItemPrivate
{
+ Q_DECLARE_PUBLIC(QWaylandQuickWlShellSurfaceItem)
public:
enum GrabberState {
DefaultState,
@@ -66,8 +69,13 @@ public:
, shellSurface(Q_NULLPTR)
, moveItem(Q_NULLPTR)
, grabberState(DefaultState)
+ , isPopup(false)
{}
+ void setIsPopup(bool popup);
+ void setFilterEnabled(bool enabled);
+ static void closePopups();
+
QWaylandWlShellSurface *shellSurface;
QQuickItem *moveItem;
@@ -85,6 +93,11 @@ public:
QPointF initialMousePos;
bool initialized;
} resizeState;
+
+ static QVector<QWaylandWlShellSurface*> popupShellSurfaces;
+ static bool eventFilterInstalled;
+ static bool waitForRelease;
+ bool isPopup;
};
QT_END_NAMESPACE
diff --git a/src/imports/compositor/qwaylandmousetracker.cpp b/src/imports/compositor/qwaylandmousetracker.cpp
index e54321f1..a77d6b1a 100644
--- a/src/imports/compositor/qwaylandmousetracker.cpp
+++ b/src/imports/compositor/qwaylandmousetracker.cpp
@@ -87,6 +87,7 @@ QWaylandMouseTracker::QWaylandMouseTracker(QQuickItem *parent)
Q_D(QWaylandMouseTracker);
setFiltersChildMouseEvents(true);
setAcceptHoverEvents(true);
+ setAcceptedMouseButtons(Qt::AllButtons);
setCursor(QCursor(d->cursorPixmap));
}