Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qwaylandquickshellsurfaceitem.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
6
7#include <QtWaylandCompositor/QWaylandShellSurface>
8#include <QGuiApplication>
9
11
13{
15 return nullptr;
16
18 auto *popupItem = new QWaylandQuickShellSurfaceItem(q);
19 popupItem->setShellSurface(shellSurface);
20 popupItem->setAutoCreatePopupItems(true);
22 popupItem->deleteLater();
23 });
24 return popupItem;
25}
26
58{
59}
60
62{
64
65 if (d->m_shellIntegration) {
66 removeEventFilter(d->m_shellIntegration);
67 delete d->m_shellIntegration;
68 }
69}
70
76{
77}
78
95{
97 return d->m_shellSurface;
98}
99
101{
103 if (d->m_shellSurface == shellSurface)
104 return;
105
106 d->m_shellSurface = shellSurface;
107
108 if (d->m_shellIntegration) {
109 removeEventFilter(d->m_shellIntegration);
110 delete d->m_shellIntegration;
111 d->m_shellIntegration = nullptr;
112 }
113
114 if (shellSurface) {
115 d->m_shellIntegration = shellSurface->createIntegration(this);
116 installEventFilter(d->m_shellIntegration);
117 }
118
120}
121
138{
140 return d->m_moveItem ? d->m_moveItem : const_cast<QWaylandQuickShellSurfaceItem *>(this);
141}
142
144{
146 moveItem = moveItem ? moveItem : this;
147 if (this->moveItem() == moveItem)
148 return;
149 d->m_moveItem = moveItem;
151}
152
167{
169 return d->m_autoCreatePopupItems;
170}
171
173{
175
176 if (enabled == d->m_autoCreatePopupItems)
177 return;
178
179 d->m_autoCreatePopupItems = enabled;
181}
182
190{
191 if (!self)
193 if (!self->eventFilterInstalled) {
194 qGuiApp->installEventFilter(self);
195 self->eventFilterInstalled = true;
196 self->client = client;
197 self->closePopups = closePopups;
198 }
199}
200
202{
203 if (!self)
204 return;
205 if (self->eventFilterInstalled && !self->waitForRelease)
206 self->stopFilter();
207}
208
209void QWaylandQuickShellEventFilter::stopFilter()
210{
211 if (eventFilterInstalled) {
212 qGuiApp->removeEventFilter(this);
213 eventFilterInstalled = false;
214 }
215}
216QWaylandQuickShellEventFilter *QWaylandQuickShellEventFilter::self = nullptr;
217
218QWaylandQuickShellEventFilter::QWaylandQuickShellEventFilter(QObject *parent)
219 : QObject(parent)
220{
221}
222
224{
225 if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonRelease) {
226 bool press = e->type() == QEvent::MouseButtonPress;
227 if (press && !waitForRelease) {
228 // The user clicked something: we need to close popups unless this press is caught later
229 if (!mousePressTimeout.isActive())
230 mousePressTimeout.start(0, this);
231 }
232
234 if (!item)
235 return false;
236
237 QMouseEvent *event = static_cast<QMouseEvent*>(e);
238 QWaylandQuickShellSurfaceItem *shellSurfaceItem = qobject_cast<QWaylandQuickShellSurfaceItem*>(item);
239 bool finalRelease = (event->type() == QEvent::MouseButtonRelease) && (event->buttons() == Qt::NoButton);
240 bool popupClient = shellSurfaceItem && shellSurfaceItem->surface() && shellSurfaceItem->surface()->client() == client;
241
242 if (waitForRelease) {
243 // We are eating events until all mouse buttons are released
244 if (finalRelease) {
245 waitForRelease = false;
246 stopFilter();
247 }
248 return true;
249 }
250
251 if (finalRelease && mousePressTimeout.isActive()) {
252 // the user somehow managed to press and release the mouse button in 0 milliseconds
253 qWarning("Badly written autotest detected");
254 mousePressTimeout.stop();
255 stopFilter();
256 }
257
258 if (press && !shellSurfaceItem && !QQmlProperty(item, QStringLiteral("qtwayland_blocking_overlay")).isValid()) {
259 // the user clicked on something that's not blocking mouse events
260 e->ignore(); //propagate the event to items below
261 return true; // don't give the event to the item
262 }
263
264 mousePressTimeout.stop(); // we've got this
265
266 if (press && !popupClient) {
267 // The user clicked outside the active popup's client. The popups should
268 // be closed, but the event filter will stay to catch the release-
269 // event before removing itself.
270 waitForRelease = true;
271 closePopups();
272 return true;
273 }
274 }
275
276 return false;
277}
278
280{
281 if (event->timerId() == mousePressTimeout.timerId()) {
282 mousePressTimeout.stop();
283 closePopups();
284 stopFilter();
285 // Don't wait for release: Since the press wasn't accepted,
286 // the release won't be delivered.
287 }
288}
289
291{
292 if (Q_UNLIKELY(!moveItem))
293 return nullptr;
294 if (auto *surf = qobject_cast<QWaylandQuickShellSurfaceItem *>(moveItem))
295 return surf;
296 for (auto *item : moveItem->childItems()) {
297 if (auto *surf = findSurfaceItemFromMoveItem(item))
298 return surf;
299 }
300 return nullptr;
301}
302
303/*
304 To raise a surface, find the topmost suitable surface and place above that.
305 We start from the top and:
306 If we don't have staysOnTop, skip all surfaces with staysOnTop
307 If we have staysOnBottom, skip all surfaces that don't have staysOnBottom
308 */
310{
312 auto *moveItem = q->moveItem();
313 QQuickItem *parent = moveItem->parentItem();
314 if (!parent)
315 return;
316 auto it = parent->childItems().crbegin();
317 auto skip = [this](QQuickItem *item) {
318 if (auto *surf = findSurfaceItemFromMoveItem(item))
319 return (!staysOnTop && surf->staysOnTop()) || (staysOnBottom && !surf->staysOnBottom());
320 return true; // ignore any other Quick items that may be there
321 };
322 auto end = parent->childItems().crend();
323 while (it != end && skip(*it))
324 ++it;
325 if (it != end) {
326 QQuickItem *top = *it;
327 if (moveItem != top)
328 moveItem->stackAfter(top);
329 }
330}
331
332/*
333 To lower a surface, find the lowest suitable surface and place below that.
334 We start from the bottom and:
335 If we don't have staysOnBottom, skip all surfaces with staysOnBottom
336 If we have staysOnTop, skip all surfaces that don't have staysOnTop
337 */
339{
341 auto *moveItem = q->moveItem();
342 QQuickItem *parent = moveItem->parentItem();
343 if (!parent)
344 return;
345 auto it = parent->childItems().cbegin();
346
347 auto skip = [this](QQuickItem *item) {
348 if (auto *surf = findSurfaceItemFromMoveItem(item))
349 return (!staysOnBottom && surf->staysOnBottom()) || (staysOnTop && !surf->staysOnTop());
350 return true; // ignore any other Quick items that may be there
351 };
352 while (skip(*it))
353 ++it;
354
355 QQuickItem *bottom = *it;
356 if (moveItem != bottom)
357 moveItem->stackBefore(bottom);
358}
359
366{
368 return d->staysOnTop;
369}
370
372{
374 if (d->staysOnTop == onTop)
375 return;
376 d->staysOnTop = onTop;
377 if (d->staysOnBottom) {
378 d->staysOnBottom = false;
380 }
381 // We need to call raise() even if onTop is false, since we need to stack under any other
382 // staysOnTop surfaces in that case
383 raise();
385 Q_ASSERT(!(d->staysOnTop && d->staysOnBottom));
386}
387
394{
396 return d->staysOnBottom;
397}
398
400{
402 if (d->staysOnBottom == onBottom)
403 return;
404 d->staysOnBottom = onBottom;
405 if (d->staysOnTop) {
406 d->staysOnTop = false;
408 }
409 // We need to call lower() even if onBottom is false, since we need to stack over any other
410 // staysOnBottom surfaces in that case
411 lower();
413 Q_ASSERT(!(d->staysOnTop && d->staysOnBottom));
414}
415
417
418#include "moc_qwaylandquickshellsurfaceitem_p.cpp"
419
420#include "moc_qwaylandquickshellsurfaceitem.cpp"
void start(int msec, QObject *obj)
\obsolete Use chrono overload instead.
int timerId() const noexcept
Returns the timer's ID.
Definition qbasictimer.h:35
void stop()
Stops the timer.
bool isActive() const noexcept
Returns true if the timer is running and has not been stopped; otherwise returns false.
Definition qbasictimer.h:34
\inmodule QtCore
Definition qcoreevent.h:45
@ MouseButtonPress
Definition qcoreevent.h:60
@ MouseButtonRelease
Definition qcoreevent.h:61
\inmodule QtGui
Definition qevent.h:195
QObject * parent
Definition qobject.h:61
\inmodule QtCore
Definition qobject.h:90
void installEventFilter(QObject *filterObj)
Installs an event filter filterObj on this object.
Definition qobject.cpp:2269
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
void removeEventFilter(QObject *obj)
Removes an event filter object obj from this object.
Definition qobject.cpp:2300
The QQmlProperty class abstracts accessing properties on objects created from QML.
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:64
QList< QQuickItem * > childItems() const
Returns the children of this item.
bool enabled
\qmlproperty bool QtQuick::Item::enabled
Definition qquickitem.h:80
\inmodule QtCore
Definition qcoreevent.h:359
\qmltype WaylandClient \instantiates QWaylandClient \inqmlmodule QtWayland.Compositor
\qmltype WaylandQuickItem \instantiates QWaylandQuickItem \inqmlmodule QtWayland.Compositor
void surfaceDestroyed()
\qmlsignal void QtWayland.Compositor::WaylandQuickItem::surfaceDestroyed()
QWaylandSurface * surface
\qmlproperty WaylandSurface QtWayland.Compositor::WaylandQuickItem::surface
QWaylandQuickShellEventFilter implements a Wayland popup grab.
bool eventFilter(QObject *, QEvent *) override
Filters events if this object has been installed as an event filter for the watched object.
static void startFilter(QWaylandClient *client, CallbackFunction closePopupCallback)
void timerEvent(QTimerEvent *event) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
QWaylandQuickShellSurfaceItem * maybeCreateAutoPopup(QWaylandShellSurface *shellSurface)
\qmltype ShellSurfaceItem \instantiates QWaylandQuickShellSurfaceItem \inherits WaylandQuickItem \inq...
QQuickItem * moveItem
\qmlproperty Item QtWayland.Compositor::ShellSurfaceItem::moveItem
bool staysOnTop
Keep this item above other Wayland surfaces.
QWaylandShellSurface * shellSurface
\qmlproperty ShellSurface QtWayland.Compositor::ShellSurfaceItem::shellSurface
bool staysOnBottom
Keep this item above other Wayland surfaces.
QWaylandQuickShellSurfaceItem(QQuickItem *parent=nullptr)
Constructs a QWaylandQuickWlShellSurfaceItem with the given parent.
bool autoCreatePopupItems
\qmlproperty bool QtWayland.Compositor::ShellSurfaceItem::autoCreatePopupItems
void setShellSurface(QWaylandShellSurface *shellSurface)
\qmltype ShellSurface \instantiates QWaylandShellSurface \inqmlmodule QtWayland.Compositor
QWaylandClient * client
\qmlproperty WaylandClient QtWayland.Compositor::WaylandSurface::client
double e
QSet< QString >::iterator it
Combined button and popup list for selecting options.
@ NoButton
Definition qnamespace.h:56
#define Q_UNLIKELY(x)
#define qGuiApp
#define qWarning
Definition qlogging.h:162
GLuint GLuint end
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLint GLint bottom
struct _cl_event * event
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
QQuickItem * qobject_cast< QQuickItem * >(QObject *o)
Definition qquickitem.h:483
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QStringLiteral(str)
#define emit
static QWaylandQuickShellSurfaceItem * findSurfaceItemFromMoveItem(QQuickItem *moveItem)
QGraphicsItem * item
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent