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
qwaylandwlshellintegration.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
5
6#include <QtWaylandCompositor/QWaylandCompositor>
7#include <QtWaylandCompositor/QWaylandWlShellSurface>
8#include <QtWaylandCompositor/QWaylandQuickShellSurfaceItem>
9#include <QtWaylandCompositor/QWaylandSeat>
10
12
13namespace QtWayland {
14
17 , m_item(item)
18 , m_shellSurface(qobject_cast<QWaylandWlShellSurface *>(item->shellSurface()))
19{
20 m_item->setSurface(m_shellSurface->surface());
21 connect(m_shellSurface.data(), &QWaylandWlShellSurface::startMove, this, &WlShellIntegration::handleStartMove);
22 connect(m_shellSurface.data(), &QWaylandWlShellSurface::startResize, this, &WlShellIntegration::handleStartResize);
23 connect(m_shellSurface->surface(), &QWaylandSurface::redraw, this, &WlShellIntegration::handleRedraw);
24 connect(m_shellSurface->surface(), &QWaylandSurface::offsetForNextFrame, this, &WlShellIntegration::adjustOffsetForNextFrame);
25 connect(m_shellSurface->surface(), &QWaylandSurface::hasContentChanged, this, &WlShellIntegration::handleSurfaceHasContentChanged);
26 connect(m_shellSurface.data(), &QWaylandWlShellSurface::setDefaultToplevel, this, &WlShellIntegration::handleSetDefaultTopLevel);
27 connect(m_shellSurface.data(), &QWaylandWlShellSurface::setTransient, this, &WlShellIntegration::handleSetTransient);
28 connect(m_shellSurface.data(), &QWaylandWlShellSurface::setMaximized, this, &WlShellIntegration::handleSetMaximized);
29 connect(m_shellSurface.data(), &QWaylandWlShellSurface::setFullScreen, this, &WlShellIntegration::handleSetFullScreen);
30 connect(m_shellSurface.data(), &QWaylandWlShellSurface::setPopup, this, &WlShellIntegration::handleSetPopup);
31 connect(m_shellSurface.data(), &QWaylandWlShellSurface::destroyed, this, &WlShellIntegration::handleShellSurfaceDestroyed);
32}
33
38
39void WlShellIntegration::handleStartMove(QWaylandSeat *seat)
40{
41 grabberState = GrabberState::Move;
42 moveState.seat = seat;
43 moveState.initialized = false;
44}
45
46void WlShellIntegration::handleStartResize(QWaylandSeat *seat, QWaylandWlShellSurface::ResizeEdge edges)
47{
48 grabberState = GrabberState::Resize;
49 resizeState.seat = seat;
50 resizeState.resizeEdges = edges;
51 resizeState.initialSize = m_shellSurface->surface()->destinationSize();
52 resizeState.initialized = false;
53}
54
55void WlShellIntegration::handleSetDefaultTopLevel()
56{
57 // Take focus if the policy allows
58 if (m_shellSurface->shell()->focusPolicy() == QWaylandShell::AutomaticFocus)
59 m_item->takeFocus();
60
61 // In order to restore the window state, the client calls setDefaultToplevel()
62 // so we need to unset the flags here but we save the previous state and move
63 // to the initial position when redrawing
64 nextState = State::Windowed;
65
66 // Any handlers for making maximized or fullscreen state track the size of
67 // the designated output, are unneeded now that we're going to windowed
68 // state.
69 nonwindowedState.output = nullptr;
70 disconnect(nonwindowedState.sizeChangedConnection);
71}
72
73void WlShellIntegration::handleSetTransient(QWaylandSurface *parentSurface, const QPoint &relativeToParent, bool inactive)
74{
75 Q_UNUSED(parentSurface);
76 Q_UNUSED(relativeToParent);
77
78 // Take focus if the policy allows and it's not inactive
79 if (m_shellSurface->shell()->focusPolicy() == QWaylandShell::AutomaticFocus && !inactive)
80 m_item->takeFocus();
81}
82
83void WlShellIntegration::handleSetMaximized(QWaylandOutput *output)
84{
85 if (!m_item->view()->isPrimary())
86 return;
87
88 if (currentState == State::Maximized)
89 return;
90
91 QWaylandOutput *designatedOutput = output ? output : m_item->view()->output();
92 if (!designatedOutput)
93 return;
94
95 if (currentState == State::Windowed)
96 normalPosition = m_item->moveItem()->position();
97
98 nextState = State::Maximized;
99 finalPosition = designatedOutput->position() + designatedOutput->availableGeometry().topLeft();
100
101 // Any prior output-resize handlers are irrelevant at this point
102 disconnect(nonwindowedState.sizeChangedConnection);
103 nonwindowedState.output = designatedOutput;
104 nonwindowedState.sizeChangedConnection = connect(designatedOutput, &QWaylandOutput::availableGeometryChanged, this, &WlShellIntegration::handleMaximizedSizeChanged);
105 handleMaximizedSizeChanged();
106}
107
108void WlShellIntegration::handleMaximizedSizeChanged()
109{
110 if (!m_shellSurface)
111 return;
112
113 if (nextState == State::Maximized) {
114 QWaylandOutput *designatedOutput = nonwindowedState.output;
115 auto scaleFactor = designatedOutput->scaleFactor();
116 m_shellSurface->sendConfigure(designatedOutput->availableGeometry().size() / scaleFactor, QWaylandWlShellSurface::NoneEdge);
117 }
118}
119
120void WlShellIntegration::handleSetFullScreen(QWaylandWlShellSurface::FullScreenMethod method, uint framerate, QWaylandOutput *output)
121{
123 Q_UNUSED(framerate);
124
125 if (!m_item->view()->isPrimary())
126 return;
127
128 if (currentState == State::FullScreen)
129 return;
130
131 QWaylandOutput *designatedOutput = output ? output : m_item->view()->output();
132 if (!designatedOutput)
133 return;
134
135 if (currentState == State::Windowed)
136 normalPosition = m_item->moveItem()->position();
137
138 nextState = State::FullScreen;
139 finalPosition = designatedOutput->position();
140
141 // Any prior output-resize handlers are irrelevant at this point
142 disconnect(nonwindowedState.sizeChangedConnection);
143 nonwindowedState.output = designatedOutput;
144 nonwindowedState.sizeChangedConnection = connect(designatedOutput, &QWaylandOutput::geometryChanged, this, &WlShellIntegration::handleFullScreenSizeChanged);
145 handleFullScreenSizeChanged();
146}
147
148void WlShellIntegration::handleFullScreenSizeChanged()
149{
150 if (!m_shellSurface)
151 return;
152
153 if (nextState == State::FullScreen) {
154 QWaylandOutput *designatedOutput = nonwindowedState.output;
155 m_shellSurface->sendConfigure(designatedOutput->geometry().size(), QWaylandWlShellSurface::NoneEdge);
156 }
157}
158
159void WlShellIntegration::handleSetPopup(QWaylandSeat *seat, QWaylandSurface *parent, const QPoint &relativeToParent)
160{
161 Q_UNUSED(seat);
162
163 // Find the parent item on the same output
164 QWaylandQuickShellSurfaceItem *parentItem = nullptr;
165 const auto views = parent->views();
166 for (QWaylandView *view : views) {
167 if (view->output() == m_item->view()->output()) {
168 QWaylandQuickShellSurfaceItem *item = qobject_cast<QWaylandQuickShellSurfaceItem*>(view->renderObject());
169 if (item) {
170 parentItem = item;
171 break;
172 }
173 }
174 }
175
176 if (parentItem) {
177 // Clear all the transforms for this ShellSurfaceItem. They are not
178 // applicable when the item becomes a child to a surface that has its
179 // own transforms. Otherwise the transforms would be applied twice.
180 QQmlListProperty<QQuickTransform> t = m_item->transform();
181 t.clear(&t);
182 m_item->setRotation(0);
183 m_item->setScale(1.0);
184 m_item->setPosition(m_item->mapFromSurface(relativeToParent));
185 m_item->setParentItem(parentItem);
186 }
187
188 isPopup = true;
189 auto shell = m_shellSurface->shell();
190 QWaylandQuickShellEventFilter::startFilter(m_shellSurface->surface()->client(), [shell]() {
191 shell->closeAllPopups();
192 });
193
195 this, &WlShellIntegration::handleSurfaceHasContentChanged);
196}
197
198void WlShellIntegration::handlePopupClosed()
199{
200 handlePopupRemoved();
201 if (m_shellSurface)
203 this, &WlShellIntegration::handleSurfaceHasContentChanged);
204}
205
206void WlShellIntegration::handlePopupRemoved()
207{
208 if (!m_shellSurface || m_shellSurface->shell()->mappedPopups().isEmpty())
210 isPopup = false;
211}
212
213qreal WlShellIntegration::devicePixelRatio() const
214{
215 return m_item->window() ? m_item->window()->devicePixelRatio() : 1;
216}
217
218void WlShellIntegration::handleShellSurfaceDestroyed()
219{
220 if (isPopup)
221 handlePopupRemoved();
222
223 // Disarm any handlers that might fire and attempt to use the now-stale pointer
224 nonwindowedState.output = nullptr;
225 disconnect(nonwindowedState.sizeChangedConnection);
226
227 m_shellSurface = nullptr;
228}
229
230void WlShellIntegration::handleSurfaceHasContentChanged()
231{
232 if (m_shellSurface && m_shellSurface->surface()->destinationSize().isEmpty()
233 && m_shellSurface->windowType() == Qt::WindowType::Popup) {
234 handlePopupClosed();
235 }
236}
237
238void WlShellIntegration::handleRedraw()
239{
240 if (currentState == nextState)
241 return;
242
243 m_item->moveItem()->setPosition(nextState == State::Windowed ? normalPosition : finalPosition);
244 currentState = nextState;
245}
246
247void WlShellIntegration::adjustOffsetForNextFrame(const QPointF &offset)
248{
249 if (!m_item->view()->isPrimary())
250 return;
251
252 QQuickItem *moveItem = m_item->moveItem();
253 moveItem->setPosition(moveItem->position() + m_item->mapFromSurface(offset));
254}
255
257{
258 if (event->type() == QEvent::MouseMove) {
259 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
260 return filterMouseMoveEvent(mouseEvent);
261 } else if (event->type() == QEvent::MouseButtonRelease) {
262 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
263 return filterMouseReleaseEvent(mouseEvent);
264 }
266}
267
268bool WlShellIntegration::filterMouseMoveEvent(QMouseEvent *event)
269{
270 if (grabberState == GrabberState::Resize) {
271 Q_ASSERT(resizeState.seat == m_item->compositor()->seatFor(event));
272 if (!resizeState.initialized) {
273 resizeState.initialMousePos = event->scenePosition();
274 resizeState.initialized = true;
275 return true;
276 }
277 float scaleFactor = m_item->view()->output()->scaleFactor();
278 QPointF delta = (event->scenePosition() - resizeState.initialMousePos) / scaleFactor * devicePixelRatio();
279 QSize newSize = m_shellSurface->sizeForResize(resizeState.initialSize, delta, resizeState.resizeEdges);
280 m_shellSurface->sendConfigure(newSize, resizeState.resizeEdges);
281 } else if (grabberState == GrabberState::Move) {
282 Q_ASSERT(moveState.seat == m_item->compositor()->seatFor(event));
283 QQuickItem *moveItem = m_item->moveItem();
284 if (!moveState.initialized) {
285 moveState.initialOffset = moveItem->mapFromItem(nullptr, event->scenePosition());
286 moveState.initialized = true;
287 return true;
288 }
289 if (!moveItem->parentItem())
290 return true;
291 QPointF parentPos = moveItem->parentItem()->mapFromItem(nullptr, event->scenePosition());
292 moveItem->setPosition(parentPos - moveState.initialOffset);
293 }
294 return false;
295}
296
297bool WlShellIntegration::filterMouseReleaseEvent(QMouseEvent *event)
298{
300 if (grabberState != GrabberState::Default) {
301 grabberState = GrabberState::Default;
302 return true;
303 }
304 return false;
305}
306
307}
308
310
311#include "moc_qwaylandwlshellintegration_p.cpp"
\inmodule QtCore
Definition qcoreevent.h:45
@ MouseMove
Definition qcoreevent.h:63
@ MouseButtonRelease
Definition qcoreevent.h:61
bool isEmpty() const noexcept
Definition qlist.h:401
\inmodule QtGui
Definition qevent.h:196
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
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
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
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
T * data() const noexcept
Definition qpointer.h:73
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...
void setScale(qreal)
void setRotation(qreal)
void setParentItem(QQuickItem *parent)
QQuickWindow * window() const
Returns the window in which this item is rendered.
QQuickItem * parentItem() const
QPointF position() const
void setPosition(const QPointF &)
QQmlListProperty< QQuickTransform > transform
\qmlproperty list<Transform> QtQuick::Item::transform This property holds the list of transformations...
Definition qquickitem.h:110
\inmodule QtCore
Definition qsize.h:25
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:124
\qmltype WaylandOutput \instantiates QWaylandOutput \inqmlmodule QtWayland.Compositor
void availableGeometryChanged()
int scaleFactor
\qmlproperty int QtWayland.Compositor::WaylandOutput::scaleFactor
void geometryChanged()
virtual void takeFocus(QWaylandSeat *device=nullptr)
Calling this function causes the item to take the focus of the input device.
QWaylandView * view() const
Returns the view rendered by this QWaylandQuickItem.
void setSurface(QWaylandSurface *surface)
QWaylandCompositor * compositor
\qmlproperty WaylandCompositor QtWayland.Compositor::WaylandQuickItem::compositor
static void startFilter(QWaylandClient *client, CallbackFunction closePopupCallback)
\qmltype ShellSurfaceItem \instantiates QWaylandQuickShellSurfaceItem \inherits WaylandQuickItem \inq...
QQuickItem * moveItem
\qmlproperty Item QtWayland.Compositor::ShellSurfaceItem::moveItem
\qmltype WaylandSeat \instantiates QWaylandSeat \inqmlmodule QtWayland.Compositor
FocusPolicy focusPolicy
\qmlproperty enumeration Shell::focusPolicy
\qmltype WaylandSurface \instantiates QWaylandSurface \inqmlmodule QtWayland.Compositor
QSize destinationSize
\qmlproperty size QtWayland.Compositor::WaylandSurface::destinationSize
void offsetForNextFrame(const QPoint &offset)
void hasContentChanged()
QWaylandClient * client
\qmlproperty WaylandClient QtWayland.Compositor::WaylandSurface::client
\qmltype WaylandView \instantiates QWaylandView \inqmlmodule QtWayland.Compositor
bool isPrimary() const
Returns true if this QWaylandView is the primary view for the QWaylandSurface.
QWaylandOutput * output
\qmlproperty WaylandOutput QtWayland.Compositor::WaylandView::output
\qmltype WlShellSurface \instantiates QWaylandWlShellSurface \inqmlmodule QtWayland....
void setPopup(QWaylandSeat *seat, QWaylandSurface *parentSurface, const QPoint &relativeToParent)
void setFullScreen(FullScreenMethod method, uint framerate, QWaylandOutput *output)
QWaylandWlShell * shell
\qmlproperty WlShell WlShellSurface::shell
void setMaximized(QWaylandOutput *output)
void startResize(QWaylandSeat *seat, ResizeEdge edges)
Q_INVOKABLE void sendConfigure(const QSize &size, ResizeEdge edges)
\qmlmethod void WlShellSurface::sendConfigure(size s, enum edges)
void startMove(QWaylandSeat *seat)
void setTransient(QWaylandSurface *parentSurface, const QPoint &relativeToParent, bool inactive)
ResizeEdge
This enum type provides a way to specify an edge or corner of the surface.
Qt::WindowType windowType() const override
\qmlproperty enum WlShellSurface::windowType
QWaylandSurface * surface
\qmlproperty WaylandSurface WlShellSurface::surface
Q_INVOKABLE QSize sizeForResize(const QSizeF &size, const QPointF &delta, ResizeEdge edges)
QList< QWaylandWlShellSurface * > mappedPopups() const
WlShellIntegration(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.
Combined button and popup list for selecting options.
@ Popup
Definition qnamespace.h:211
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
T qobject_cast(QObject *object)
\variable QObject::staticMetaObject
Definition qobject.h:419
GLenum GLuint GLintptr offset
struct _cl_event * event
GLdouble GLdouble t
Definition qopenglext.h:243
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_UNUSED(x)
unsigned int uint
Definition qtypes.h:34
double qreal
Definition qtypes.h:187
QT_BEGIN_NAMESPACE typedef uchar * output
myObject disconnect()
[26]
QGraphicsItem * item
QQuickView * view
[0]