| /**************************************************************************** |
| ** |
| ** Copyright (C) 2017 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtWaylandCompositor module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 or (at your option) any later version |
| ** approved by the KDE Free Qt Foundation. The licenses are as published by |
| ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qwaylandquickshellsurfaceitem.h" |
| #include "qwaylandquickshellsurfaceitem_p.h" |
| |
| #include <QtWaylandCompositor/QWaylandShellSurface> |
| #include <QGuiApplication> |
| |
| QT_BEGIN_NAMESPACE |
| |
| QWaylandQuickShellSurfaceItem *QWaylandQuickShellSurfaceItemPrivate::maybeCreateAutoPopup(QWaylandShellSurface* shellSurface) |
| { |
| if (!m_autoCreatePopupItems) |
| return nullptr; |
| |
| Q_Q(QWaylandQuickShellSurfaceItem); |
| auto *popupItem = new QWaylandQuickShellSurfaceItem(q); |
| popupItem->setShellSurface(shellSurface); |
| popupItem->setAutoCreatePopupItems(true); |
| QObject::connect(popupItem, &QWaylandQuickShellSurfaceItem::surfaceDestroyed, [popupItem](){ |
| popupItem->deleteLater(); |
| }); |
| return popupItem; |
| } |
| |
| /*! |
| * \qmltype ShellSurfaceItem |
| * \inherits WaylandQuickItem |
| * \inqmlmodule QtWayland.Compositor |
| * \since 5.8 |
| * \brief A Qt Quick item type for displaying and interacting with a ShellSurface. |
| * |
| * This type is used to render \c wl_shell, \c xdg_shell or \c ivi_application surfaces as part of |
| * a Qt Quick scene. It handles moving and resizing triggered by clicking on the window decorations. |
| * |
| * \sa WaylandQuickItem, WlShellSurface, XdgSurfaceV5, IviSurface |
| */ |
| |
| /*! |
| * \class QWaylandQuickShellSurfaceItem |
| * \inmodule QtWaylandCompositor |
| * \since 5.8 |
| * \brief The QWaylandQuickShellSurfaceItem class provides a Qt Quick item that represents a QWaylandShellSurface. |
| * |
| * This class is used to render \c wl_shell, \c xdg_shell or \c ivi_application surfaces as part of |
| * a Qt Quick scene. It handles moving and resizing triggered by clicking on the window decorations. |
| * |
| * \sa QWaylandQuickItem, QWaylandWlShellSurface, QWaylandXdgSurfaceV5, QWaylandIviSurface |
| */ |
| |
| /*! |
| * Constructs a QWaylandQuickWlShellSurfaceItem with the given \a parent. |
| */ |
| QWaylandQuickShellSurfaceItem::QWaylandQuickShellSurfaceItem(QQuickItem *parent) |
| : QWaylandQuickItem(*new QWaylandQuickShellSurfaceItemPrivate(), parent) |
| { |
| } |
| |
| QWaylandQuickShellSurfaceItem::~QWaylandQuickShellSurfaceItem() |
| { |
| Q_D(QWaylandQuickShellSurfaceItem); |
| |
| if (d->m_shellIntegration) { |
| removeEventFilter(d->m_shellIntegration); |
| delete d->m_shellIntegration; |
| } |
| } |
| |
| /*! |
| * \internal |
| */ |
| QWaylandQuickShellSurfaceItem::QWaylandQuickShellSurfaceItem(QWaylandQuickShellSurfaceItemPrivate &dd, QQuickItem *parent) |
| : QWaylandQuickItem(dd, parent) |
| { |
| } |
| |
| /*! |
| * \qmlproperty ShellSurface QtWaylandCompositor::ShellSurfaceItem::shellSurface |
| * |
| * This property holds the ShellSurface rendered by this ShellSurfaceItem. |
| * It may either be an XdgSurfaceV5, WlShellSurface or IviSurface depending on which shell protocol |
| * is in use. |
| */ |
| |
| /*! |
| * \property QWaylandQuickShellSurfaceItem::shellSurface |
| * |
| * This property holds the QWaylandShellSurface rendered by this QWaylandQuickShellSurfaceItem. |
| * It may either be a QWaylandXdgSurfaceV5, QWaylandWlShellSurface or QWaylandIviSurface depending |
| * on which shell protocol is in use. |
| */ |
| QWaylandShellSurface *QWaylandQuickShellSurfaceItem::shellSurface() const |
| { |
| Q_D(const QWaylandQuickShellSurfaceItem); |
| return d->m_shellSurface; |
| } |
| |
| void QWaylandQuickShellSurfaceItem::setShellSurface(QWaylandShellSurface *shellSurface) |
| { |
| Q_D(QWaylandQuickShellSurfaceItem); |
| if (d->m_shellSurface == shellSurface) |
| return; |
| |
| d->m_shellSurface = shellSurface; |
| |
| if (d->m_shellIntegration) { |
| removeEventFilter(d->m_shellIntegration); |
| delete d->m_shellIntegration; |
| d->m_shellIntegration = nullptr; |
| } |
| |
| if (shellSurface) { |
| d->m_shellIntegration = shellSurface->createIntegration(this); |
| installEventFilter(d->m_shellIntegration); |
| } |
| |
| emit shellSurfaceChanged(); |
| } |
| |
| /*! |
| * \qmlproperty Item QtWaylandCompositor::ShellSurfaceItem::moveItem |
| * |
| * This property holds the move item for this ShellSurfaceItem. This is the item that will be moved |
| * when the clients request the ShellSurface to be moved, maximized, resized etc. This property is |
| * useful when implementing server-side decorations. |
| */ |
| |
| /*! |
| * \property QWaylandQuickShellSurfaceItem::moveItem |
| * |
| * This property holds the move item for this QWaylandQuickShellSurfaceItem. This is the item that |
| * will be moved when the clients request the QWaylandShellSurface to be moved, maximized, resized |
| * etc. This property is useful when implementing server-side decorations. |
| */ |
| QQuickItem *QWaylandQuickShellSurfaceItem::moveItem() const |
| { |
| Q_D(const QWaylandQuickShellSurfaceItem); |
| return d->m_moveItem ? d->m_moveItem : const_cast<QWaylandQuickShellSurfaceItem *>(this); |
| } |
| |
| void QWaylandQuickShellSurfaceItem::setMoveItem(QQuickItem *moveItem) |
| { |
| Q_D(QWaylandQuickShellSurfaceItem); |
| moveItem = moveItem ? moveItem : this; |
| if (this->moveItem() == moveItem) |
| return; |
| d->m_moveItem = moveItem; |
| moveItemChanged(); |
| } |
| |
| /*! |
| * \qmlproperty bool QtWaylandCompositor::ShellSurfaceItem::autoCreatePopupItems |
| * |
| * This property holds whether ShellSurfaceItems for popups parented to the shell |
| * surface managed by this item should automatically be created. |
| */ |
| |
| /*! |
| * \property QWaylandQuickShellSurfaceItem::autoCreatePopupItems |
| * |
| * This property holds whether QWaylandQuickShellSurfaceItems for popups |
| * parented to the shell surface managed by this item should automatically be created. |
| */ |
| bool QWaylandQuickShellSurfaceItem::autoCreatePopupItems() |
| { |
| Q_D(const QWaylandQuickShellSurfaceItem); |
| return d->m_autoCreatePopupItems; |
| } |
| |
| void QWaylandQuickShellSurfaceItem::setAutoCreatePopupItems(bool enabled) |
| { |
| Q_D(QWaylandQuickShellSurfaceItem); |
| |
| if (enabled == d->m_autoCreatePopupItems) |
| return; |
| |
| d->m_autoCreatePopupItems = enabled; |
| emit autoCreatePopupItemsChanged(); |
| } |
| |
| /*! |
| \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) |
| { |
| } |
| |
| bool QWaylandQuickShellEventFilter::eventFilter(QObject *receiver, QEvent *e) |
| { |
| if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonRelease) { |
| bool press = e->type() == QEvent::MouseButtonPress; |
| if (press && !waitForRelease) { |
| // The user clicked something: we need to close popups unless this press is caught later |
| if (!mousePressTimeout.isActive()) |
| mousePressTimeout.start(0, this); |
| } |
| |
| QQuickItem *item = qobject_cast<QQuickItem*>(receiver); |
| if (!item) |
| return false; |
| |
| QMouseEvent *event = static_cast<QMouseEvent*>(e); |
| QWaylandQuickShellSurfaceItem *shellSurfaceItem = qobject_cast<QWaylandQuickShellSurfaceItem*>(item); |
| bool finalRelease = (event->type() == QEvent::MouseButtonRelease) && (event->buttons() == Qt::NoButton); |
| bool popupClient = shellSurfaceItem && shellSurfaceItem->surface() && shellSurfaceItem->surface()->client() == client; |
| |
| if (waitForRelease) { |
| // We are eating events until all mouse buttons are released |
| if (finalRelease) { |
| waitForRelease = false; |
| stopFilter(); |
| } |
| return true; |
| } |
| |
| if (finalRelease && mousePressTimeout.isActive()) { |
| // the user somehow managed to press and release the mouse button in 0 milliseconds |
| qWarning("Badly written autotest detected"); |
| mousePressTimeout.stop(); |
| stopFilter(); |
| } |
| |
| if (press && !shellSurfaceItem && !QQmlProperty(item, QStringLiteral("qtwayland_blocking_overlay")).isValid()) { |
| // the user clicked on something that's not blocking mouse events |
| e->ignore(); //propagate the event to items below |
| return true; // don't give the event to the item |
| } |
| |
| mousePressTimeout.stop(); // we've got this |
| |
| 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; |
| } |
| } |
| |
| return false; |
| } |
| |
| void QWaylandQuickShellEventFilter::timerEvent(QTimerEvent *event) |
| { |
| if (event->timerId() == mousePressTimeout.timerId()) { |
| mousePressTimeout.stop(); |
| closePopups(); |
| stopFilter(); |
| // Don't wait for release: Since the press wasn't accepted, |
| // the release won't be delivered. |
| } |
| } |
| |
| QT_END_NAMESPACE |