Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwaylandxdgshellintegration.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
5
6#include <QtWaylandCompositor/QWaylandXdgSurface>
7#include <QtWaylandCompositor/QWaylandCompositor>
8#include <QtWaylandCompositor/QWaylandSeat>
9
11
12namespace QtWayland {
13
15{
16 if (parentItem->shellSurface() == popup->parentXdgSurface())
17 QWaylandQuickShellSurfaceItemPrivate::get(parentItem)->maybeCreateAutoPopup(popup->xdgSurface());
18}
19
22 , m_item(item)
23 , m_xdgSurface(qobject_cast<QWaylandXdgSurface *>(item->shellSurface()))
24 , m_toplevel(m_xdgSurface->toplevel())
25 , grabberState(GrabberState::Default)
26{
27 Q_ASSERT(m_toplevel);
28
29 m_item->setSurface(m_xdgSurface->surface());
30
31 connect(m_toplevel, &QWaylandXdgToplevel::startMove, this, &XdgToplevelIntegration::handleStartMove);
32 connect(m_toplevel, &QWaylandXdgToplevel::startResize, this, &XdgToplevelIntegration::handleStartResize);
33 connect(m_toplevel, &QWaylandXdgToplevel::setMaximized, this, &XdgToplevelIntegration::handleSetMaximized);
34 connect(m_toplevel, &QWaylandXdgToplevel::unsetMaximized, this, &XdgToplevelIntegration::handleUnsetMaximized);
35 connect(m_toplevel, &QWaylandXdgToplevel::maximizedChanged, this, &XdgToplevelIntegration::handleMaximizedChanged);
36 connect(m_toplevel, &QWaylandXdgToplevel::setFullscreen, this, &XdgToplevelIntegration::handleSetFullscreen);
37 connect(m_toplevel, &QWaylandXdgToplevel::unsetFullscreen, this, &XdgToplevelIntegration::handleUnsetFullscreen);
38 connect(m_toplevel, &QWaylandXdgToplevel::fullscreenChanged, this, &XdgToplevelIntegration::handleFullscreenChanged);
39 connect(m_toplevel, &QWaylandXdgToplevel::activatedChanged, this, &XdgToplevelIntegration::handleActivatedChanged);
41 handlePopupCreated(item, popup);
42 });
43 connect(m_xdgSurface->surface(), &QWaylandSurface::destinationSizeChanged, this, &XdgToplevelIntegration::handleSurfaceSizeChanged);
44 connect(m_toplevel, &QObject::destroyed, this, &XdgToplevelIntegration::handleToplevelDestroyed);
45}
46
48{
49 if (event->type() == QEvent::MouseMove) {
50 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
51 return filterMouseMoveEvent(mouseEvent);
52 } else if (event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::TouchEnd || event->type() == QEvent::TouchCancel) {
53 return filterPointerReleaseEvent();
54 } else if (event->type() == QEvent::TouchUpdate) {
55 QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
56 return filterTouchUpdateEvent(touchEvent);
57 }
59}
60
61bool XdgToplevelIntegration::filterPointerMoveEvent(const QPointF &scenePosition)
62{
63 if (grabberState == GrabberState::Resize) {
64 if (!resizeState.initialized) {
65 resizeState.initialMousePos = scenePosition;
66 resizeState.initialized = true;
67 return true;
68 }
69 QPointF delta = m_item->mapToSurface(scenePosition - resizeState.initialMousePos);
70 QSize newSize = m_toplevel->sizeForResize(resizeState.initialWindowSize, delta, resizeState.resizeEdges);
71 m_toplevel->sendResizing(newSize);
72 } else if (grabberState == GrabberState::Move) {
73 QQuickItem *moveItem = m_item->moveItem();
74 if (!moveState.initialized) {
75 moveState.initialOffset = moveItem->mapFromItem(nullptr, scenePosition);
76 moveState.initialized = true;
77 return true;
78 }
79 if (!moveItem->parentItem())
80 return true;
81 QPointF parentPos = moveItem->parentItem()->mapFromItem(nullptr, scenePosition);
82 moveItem->setPosition(parentPos - moveState.initialOffset);
83 }
84 return false;
85}
86
87bool XdgToplevelIntegration::filterTouchUpdateEvent(QTouchEvent *event)
88{
89 if (event->pointCount() == 0)
90 return false;
91
92 Q_ASSERT(grabberState != GrabberState::Move || moveState.seat == m_item->compositor()->seatFor(event));
93 Q_ASSERT(grabberState != GrabberState::Resize || resizeState.seat == m_item->compositor()->seatFor(event));
94
95 QEventPoint point = event->points().first();
96 return filterPointerMoveEvent(point.scenePosition());
97 }
98
99bool XdgToplevelIntegration::filterMouseMoveEvent(QMouseEvent *event)
100{
101 Q_ASSERT(grabberState != GrabberState::Move || moveState.seat == m_item->compositor()->seatFor(event));
102 Q_ASSERT(grabberState != GrabberState::Resize || resizeState.seat == m_item->compositor()->seatFor(event));
103
104 return filterPointerMoveEvent(event->scenePosition());
105}
106
107bool XdgToplevelIntegration::filterPointerReleaseEvent()
108{
109 if (grabberState != GrabberState::Default) {
110 grabberState = GrabberState::Default;
111 return true;
112 }
113 return false;
114}
115
116void XdgToplevelIntegration::handleStartMove(QWaylandSeat *seat)
117{
118 grabberState = GrabberState::Move;
119 moveState.seat = seat;
120 moveState.initialized = false;
121}
122
123void XdgToplevelIntegration::handleStartResize(QWaylandSeat *seat, Qt::Edges edges)
124{
125 grabberState = GrabberState::Resize;
126 resizeState.seat = seat;
127 resizeState.resizeEdges = edges;
128 resizeState.initialWindowSize = m_xdgSurface->windowGeometry().size();
129 resizeState.initialPosition = m_item->moveItem()->position();
130 resizeState.initialSurfaceSize = m_item->surface()->destinationSize();
131 resizeState.initialized = false;
132}
133
134void XdgToplevelIntegration::handleSetMaximized()
135{
136 if (!m_item->view()->isPrimary())
137 return;
138
139 QList<QWaylandXdgToplevel::State> states = m_toplevel->states();
140
142 windowedGeometry.initialWindowSize = m_xdgSurface->windowGeometry().size();
143 windowedGeometry.initialPosition = m_item->moveItem()->position();
144 }
145
146 // Any prior output-resize handlers are irrelevant at this point.
147 disconnect(nonwindowedState.sizeChangedConnection);
148 nonwindowedState.output = m_item->view()->output();
149 nonwindowedState.sizeChangedConnection = connect(nonwindowedState.output, &QWaylandOutput::availableGeometryChanged, this, &XdgToplevelIntegration::handleMaximizedSizeChanged);
150 handleMaximizedSizeChanged();
151}
152
153void XdgToplevelIntegration::handleMaximizedSizeChanged()
154{
155 // Insurance against handleToplevelDestroyed() not managing to disconnect this
156 // handler in time.
157 if (m_toplevel == nullptr)
158 return;
159
160 m_toplevel->sendMaximized(nonwindowedState.output->availableGeometry().size() / nonwindowedState.output->scaleFactor());
161}
162
163void XdgToplevelIntegration::handleUnsetMaximized()
164{
165 if (!m_item->view()->isPrimary())
166 return;
167
168 // If no prior windowed size was recorded, send a 0x0 configure event
169 // to allow the client to choose its preferred size.
170 if (windowedGeometry.initialWindowSize.isValid())
171 m_toplevel->sendUnmaximized(windowedGeometry.initialWindowSize);
172 else
173 m_toplevel->sendUnmaximized();
174}
175
176void XdgToplevelIntegration::handleMaximizedChanged()
177{
178 if (m_toplevel->maximized()) {
179 if (auto *output = m_item->view()->output()) {
181 } else {
182 qCWarning(qLcWaylandCompositor) << "The view does not have a corresponding output,"
183 << "ignoring maximized state";
184 }
185 } else {
186 m_item->moveItem()->setPosition(windowedGeometry.initialPosition);
187 }
188}
189
190void XdgToplevelIntegration::handleSetFullscreen()
191{
192 if (!m_item->view()->isPrimary())
193 return;
194
195 QList<QWaylandXdgToplevel::State> states = m_toplevel->states();
196
198 windowedGeometry.initialWindowSize = m_xdgSurface->windowGeometry().size();
199 windowedGeometry.initialPosition = m_item->moveItem()->position();
200 }
201
202 // Any prior output-resize handlers are irrelevant at this point.
203 disconnect(nonwindowedState.sizeChangedConnection);
204 nonwindowedState.output = m_item->view()->output();
205 nonwindowedState.sizeChangedConnection = connect(nonwindowedState.output, &QWaylandOutput::geometryChanged, this, &XdgToplevelIntegration::handleFullscreenSizeChanged);
206 handleFullscreenSizeChanged();
207}
208
209void XdgToplevelIntegration::handleFullscreenSizeChanged()
210{
211 // Insurance against handleToplevelDestroyed() not managing to disconnect this
212 // handler in time.
213 if (m_toplevel == nullptr)
214 return;
215
216 m_toplevel->sendFullscreen(nonwindowedState.output->geometry().size() / nonwindowedState.output->scaleFactor());
217}
218
219void XdgToplevelIntegration::handleUnsetFullscreen()
220{
221 if (!m_item->view()->isPrimary())
222 return;
223
224 // If no prior windowed size was recorded, send a 0x0 configure event
225 // to allow the client to choose its preferred size.
226 if (windowedGeometry.initialWindowSize.isValid())
227 m_toplevel->sendUnmaximized(windowedGeometry.initialWindowSize);
228 else
229 m_toplevel->sendUnmaximized();
230}
231
232void XdgToplevelIntegration::handleFullscreenChanged()
233{
234 if (m_toplevel->fullscreen()) {
235 if (auto *output = m_item->view()->output()) {
237 } else {
238 qCWarning(qLcWaylandCompositor) << "The view does not have a corresponding output,"
239 << "ignoring fullscreen state";
240 }
241 } else {
242 m_item->moveItem()->setPosition(windowedGeometry.initialPosition);
243 }
244}
245
246void XdgToplevelIntegration::handleActivatedChanged()
247{
248 if (m_toplevel->activated())
249 m_item->raise();
250}
251
252void XdgToplevelIntegration::handleSurfaceSizeChanged()
253{
254 if (grabberState == GrabberState::Resize) {
255 qreal dx = 0;
256 qreal dy = 0;
257 if (resizeState.resizeEdges & Qt::TopEdge)
258 dy = resizeState.initialSurfaceSize.height() - m_item->surface()->destinationSize().height();
259 if (resizeState.resizeEdges & Qt::LeftEdge)
260 dx = resizeState.initialSurfaceSize.width() - m_item->surface()->destinationSize().width();
261 QPointF offset = m_item->mapFromSurface({dx, dy});
262 m_item->moveItem()->setPosition(resizeState.initialPosition + offset);
263 }
264}
265
266void XdgToplevelIntegration::handleToplevelDestroyed()
267{
268 // Disarm any handlers that might fire on the now-stale toplevel pointer
269 nonwindowedState.output = nullptr;
270 disconnect(nonwindowedState.sizeChangedConnection);
271}
272
274 : m_item(item)
275 , m_xdgSurface(qobject_cast<QWaylandXdgSurface *>(item->shellSurface()))
276 , m_popup(m_xdgSurface->popup())
277{
278 Q_ASSERT(m_popup);
279
280 m_item->setSurface(m_xdgSurface->surface());
281 handleGeometryChanged();
282
283 connect(m_popup, &QWaylandXdgPopup::configuredGeometryChanged, this, &XdgPopupIntegration::handleGeometryChanged);
285 handlePopupCreated(item, popup);
286 });
287}
288
289void XdgPopupIntegration::handleGeometryChanged()
290{
291 if (m_item->view()->output()) {
292 const QPoint windowOffset = m_popup->parentXdgSurface()->windowGeometry().topLeft();
293 const QPoint surfacePosition = m_popup->unconstrainedPosition() + windowOffset;
294 const QPoint itemPosition = m_item->mapFromSurface(surfacePosition).toPoint();
295 //TODO: positioner size or other size...?
296 //TODO check positioner constraints etc... sliding, flipping
297 m_item->moveItem()->setPosition(itemPosition);
298 } else {
299 qWarning() << "XdgPopupIntegration popup item without output" << m_item;
300 }
301}
302
303}
304
306
307#include "moc_qwaylandxdgshellintegration_p.cpp"
The QEventPoint class provides information about a point in a QPointerEvent.
Definition qeventpoint.h:20
QPointF scenePosition
the scene position of this point.
Definition qeventpoint.h:39
\inmodule QtCore
Definition qcoreevent.h:45
@ MouseMove
Definition qcoreevent.h:63
@ TouchCancel
Definition qcoreevent.h:264
@ TouchUpdate
Definition qcoreevent.h:242
@ MouseButtonRelease
Definition qcoreevent.h:61
\inmodule QtGui
Definition qevent.h:196
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
virtual bool eventFilter(QObject *watched, QEvent *event)
Filters events if this object has been installed as an event filter for the watched object.
Definition qobject.cpp:1555
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
\inmodule QtCore\reentrant
Definition qpoint.h:217
\inmodule QtCore\reentrant
Definition qpoint.h:25
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
Q_INVOKABLE QPointF mapFromItem(const QQuickItem *item, const QPointF &point) const
Maps the given point in item's coordinate system to the equivalent point within this item's coordinat...
QQuickItem * parentItem() const
QPointF position() const
void setPosition(const QPointF &)
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:221
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:242
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
The QTouchEvent class contains parameters that describe a touch event.
Definition qevent.h:917
void availableGeometryChanged()
QPoint position
\qmlproperty point QtWayland.Compositor::WaylandOutput::position
QRect availableGeometry
\qmlproperty rect QtWayland.Compositor::WaylandOutput::availableGeometry
QRect geometry
\qmlproperty rect QtWayland.Compositor::WaylandOutput::geometry
void geometryChanged()
Q_INVOKABLE QPointF mapToSurface(const QPointF &point) const
\qmlmethod point WaylandQuickItem::mapToSurface(point point)
QWaylandView * view() const
Returns the view rendered by this QWaylandQuickItem.
void setSurface(QWaylandSurface *surface)
QWaylandCompositor * compositor
\qmlproperty WaylandCompositor QtWayland.Compositor::WaylandQuickItem::compositor
QWaylandSurface * surface
\qmlproperty WaylandSurface QtWayland.Compositor::WaylandQuickItem::surface
static QWaylandQuickShellSurfaceItemPrivate * get(QWaylandQuickShellSurfaceItem *item)
\qmltype ShellSurfaceItem \instantiates QWaylandQuickShellSurfaceItem \inherits WaylandQuickItem \inq...
QQuickItem * moveItem
\qmlproperty Item QtWayland.Compositor::ShellSurfaceItem::moveItem
QWaylandShellSurface * shellSurface
\qmlproperty ShellSurface QtWayland.Compositor::ShellSurfaceItem::shellSurface
\qmltype WaylandSeat \instantiates QWaylandSeat \inqmlmodule QtWayland.Compositor
QSize destinationSize
\qmlproperty size QtWayland.Compositor::WaylandSurface::destinationSize
bool isPrimary() const
Returns true if this QWaylandView is the primary view for the QWaylandSurface.
QWaylandOutput * output
\qmlproperty WaylandOutput QtWayland.Compositor::WaylandView::output
\qmltype XdgPopup \instantiates QWaylandXdgPopup \inqmlmodule QtWayland.Compositor....
void configuredGeometryChanged()
QWaylandXdgSurface * parentXdgSurface
\qmlproperty XdgSurface XdgPopup::parentXdgSurface
QPoint unconstrainedPosition
\qmlproperty point XdgPopup::unconstrainedPosition
QWaylandXdgSurface * xdgSurface
\qmlproperty XdgSurface XdgPopup::xdgSurface
void popupCreated(QWaylandXdgPopup *popup, QWaylandXdgSurface *xdgSurface)
\qmlsignal XdgShell::popupCreated(XdgPopup popup, XdgSurface xdgSurface)
\qmltype XdgSurface \instantiates QWaylandXdgSurface \inqmlmodule QtWayland.Compositor....
QWaylandSurface * surface
\qmlproperty WaylandSurface XdgSurface::surface
QRect windowGeometry
\qmlproperty rect XdgSurface::windowGeometry
QWaylandXdgShell * shell
\qmlproperty XdgShell XdgSurface::shell
Q_INVOKABLE uint sendMaximized(const QSize &size)
\qmlmethod void XdgToplevel::sendMaximized(size size)
void setFullscreen(QWaylandOutput *output)
Q_INVOKABLE QSize sizeForResize(const QSizeF &size, const QPointF &delta, Qt::Edges edges) const
\qmlmethod size XdgToplevel::sizeForResize(size size, point delta, uint edges)
Q_INVOKABLE uint sendResizing(const QSize &maxSize)
\qmlmethod void XdgToplevel::sendResizing(size maxSize)
Q_INVOKABLE uint sendUnmaximized(const QSize &size=QSize(0, 0))
\qmlmethod void XdgToplevel::sendUnmaximized(size size)
bool maximized
\qmlproperty bool XdgToplevel::maximized
void startMove(QWaylandSeat *seat)
QList< int > states
This property holds the last states the client acknowledged for this QWaylandToplevel.
void startResize(QWaylandSeat *seat, Qt::Edges edges)
Q_INVOKABLE uint sendFullscreen(const QSize &size)
\qmlmethod void XdgToplevel::sendFullscreen(size size)
bool activated
\qmlproperty bool XdgToplevel::activated
bool fullscreen
\qmlproperty bool XdgToplevel::fullscreen
XdgPopupIntegration(QWaylandQuickShellSurfaceItem *item)
bool eventFilter(QObject *object, QEvent *event) override
Filters events if this object has been installed as an event filter for the watched object.
XdgToplevelIntegration(QWaylandQuickShellSurfaceItem *item)
Combined button and popup list for selecting options.
static void handlePopupCreated(QWaylandQuickShellSurfaceItem *parentItem, QWaylandXdgPopup *popup)
@ TopEdge
@ LeftEdge
#define qWarning
Definition qlogging.h:166
#define qCWarning(category,...)
T qobject_cast(QObject *object)
\variable QObject::staticMetaObject
Definition qobject.h:419
GLenum GLuint GLintptr offset
struct _cl_event * event
GLuint * states
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static QT_BEGIN_NAMESPACE const uint Default
Definition qsplitter_p.h:27
double qreal
Definition qtypes.h:187
myObject disconnect()
[26]
QGraphicsItem * item