1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QWAYLANDWINDOW_H
5#define QWAYLANDWINDOW_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtCore/QWaitCondition>
19#include <QtCore/QMutex>
20#include <QtCore/QReadWriteLock>
21
22#include <QtGui/QIcon>
23#include <QtGui/QEventPoint>
24#include <QtCore/QVariant>
25#include <QtCore/QLoggingCategory>
26#include <QtCore/QElapsedTimer>
27#include <QtCore/QList>
28#include <QtCore/QMap> // for QVariantMap
29
30#include <qpa/qplatformwindow.h>
31#include <qpa/qplatformwindow_p.h>
32
33#include <QtWaylandClient/private/qwayland-wayland.h>
34#include <QtWaylandClient/private/qwaylanddisplay_p.h>
35#include <QtWaylandClient/qtwaylandclientglobal.h>
36#include <QtWaylandClient/private/qwaylandshellsurface_p.h>
37
38#include <QtCore/qpointer.h>
39
40struct wl_egl_window;
41
42QT_BEGIN_NAMESPACE
43
44namespace QtWaylandClient {
45
46Q_DECLARE_LOGGING_CATEGORY(lcWaylandBackingstore)
47
48class QWaylandDisplay;
49class QWaylandBuffer;
50class QWaylandShellSurface;
51class QWaylandSubSurface;
52class QWaylandAbstractDecoration;
53class QWaylandInputDevice;
54class QWaylandScreen;
55class QWaylandShellIntegration;
56class QWaylandShmBackingStore;
57class QWaylandPointerEvent;
58class QWaylandPointerGestureSwipeEvent;
59class QWaylandPointerGesturePinchEvent;
60class QWaylandSurface;
61class QWaylandFractionalScale;
62class QWaylandViewport;
63class ColorManagementSurface;
64class ImageDescription;
65
66class Q_WAYLANDCLIENT_EXPORT QWaylandWindow : public QNativeInterface::Private::QWaylandWindow,
67 public QPlatformWindow
68{
69 Q_OBJECT
70public:
71 enum WindowType {
72 Shm,
73 Egl,
74 Vulkan
75 };
76
77 enum ToplevelWindowTilingState {
78 WindowNoState = 0,
79 WindowTiledLeft = 1,
80 WindowTiledRight = 2,
81 WindowTiledTop = 4,
82 WindowTiledBottom = 8
83 };
84 Q_DECLARE_FLAGS(ToplevelWindowTilingStates, ToplevelWindowTilingState)
85
86 QWaylandWindow(QWindow *window, QWaylandDisplay *display);
87 ~QWaylandWindow() override;
88
89 // Keep Toplevels position on the top left corner of their screen
90 static inline bool fixedToplevelPositions = true;
91
92 virtual WindowType windowType() const = 0;
93 virtual void ensureSize();
94 WId winId() const override;
95 void setVisible(bool visible) override;
96 void setParent(const QPlatformWindow *parent) override;
97
98 QString windowTitle() const override;
99 void setWindowTitle(const QString &title) override;
100
101 inline QIcon windowIcon() const;
102 void setWindowIcon(const QIcon &icon) override;
103
104 void setGeometry(const QRect &rect) override;
105
106 bool allowsIndependentThreadedRendering() const override;
107
108 void resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset = {0, 0});
109 void repositionFromApplyConfigure(const QPoint &position);
110 void setGeometryFromApplyConfigure(const QPoint &globalPosition, const QSize &sizeWithMargins);
111
112 void applyConfigureWhenPossible(); //rename to possible?
113
114 void attach(QWaylandBuffer *buffer, int x, int y);
115 void attachOffset(QWaylandBuffer *buffer);
116 QPoint attachOffset() const;
117
118 void damage(const QRect &rect);
119
120 void safeCommit(QWaylandBuffer *buffer, const QRegion &damage);
121 void commit(QWaylandBuffer *buffer, const QRegion &damage);
122
123 void commit();
124
125 bool waitForFrameSync(int timeout);
126
127 QMargins frameMargins() const override;
128 QMargins clientSideMargins() const;
129 void setCustomMargins(const QMargins &margins) override;
130 QSize surfaceSize() const;
131 QMargins windowContentMargins() const;
132 QRect windowContentGeometry() const;
133 QPointF mapFromWlSurface(const QPointF &surfacePosition) const;
134
135 QWaylandSurface *waylandSurface() const { return mSurface.data(); }
136 ::wl_surface *wlSurface() const;
137 ::wl_surface *surface() const override
138 {
139 return wlSurface();
140 }
141 static QWaylandWindow *fromWlSurface(::wl_surface *surface);
142
143 QWaylandDisplay *display() const { return mDisplay; }
144 QWaylandShellSurface *shellSurface() const;
145 std::any _surfaceRole() const override;
146 QWaylandSubSurface *subSurfaceWindow() const;
147 QWaylandScreen *waylandScreen() const;
148
149 void handleContentOrientationChange(Qt::ScreenOrientation orientation) override;
150 void updateBufferTransform();
151 void setOrientationMask(Qt::ScreenOrientations mask);
152
153 ToplevelWindowTilingStates toplevelWindowTilingStates() const;
154 void handleToplevelWindowTilingStatesChanged(ToplevelWindowTilingStates states);
155
156 Qt::WindowStates windowStates() const;
157 void setWindowState(Qt::WindowStates states) override;
158 void setWindowFlags(Qt::WindowFlags flags) override;
159 Qt::WindowFlags windowFlags() const;
160 void handleWindowStatesChanged(Qt::WindowStates states);
161
162 void raise() override;
163 void lower() override;
164
165 void setMask(const QRegion &region) override;
166
167 void setAlertState(bool enabled) override;
168 bool isAlertState() const override;
169
170 qreal scale() const;
171 qreal devicePixelRatio() const override;
172
173 void requestActivateWindow() override;
174 bool isExposed() const override;
175 bool isActive() const override;
176
177 QWaylandAbstractDecoration *decoration() const;
178
179 void handleMouse(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e);
180#ifndef QT_NO_GESTURES
181 void handleSwipeGesture(QWaylandInputDevice *inputDevice,
182 const QWaylandPointerGestureSwipeEvent &e);
183 void handlePinchGesture(QWaylandInputDevice *inputDevice,
184 const QWaylandPointerGesturePinchEvent &e);
185#endif
186
187 bool touchDragDecoration(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global,
188 QEventPoint::State state, Qt::KeyboardModifiers mods);
189 bool handleTabletEventDecoration(QWaylandInputDevice *inputDevice, const QPointF &local,
190 const QPointF &global, Qt::MouseButtons buttons,
191 Qt::KeyboardModifiers modifiers);
192
193 virtual bool createDecoration();
194
195#if QT_CONFIG(cursor)
196 void restoreMouseCursor(QWaylandInputDevice *device);
197 void setStoredCursor(const QCursor &cursor);
198 void resetStoredCursor();
199 void applyCursor(QWaylandInputDevice *device, const QCursor &cursor);
200#endif
201
202 QWaylandWindow *transientParent() const;
203
204 bool setMouseGrabEnabled(bool grab) override;
205 static QWaylandWindow *mouseGrab() { return mMouseGrab; }
206
207 void sendProperty(const QString &name, const QVariant &value);
208 void setProperty(const QString &name, const QVariant &value);
209
210 QVariantMap properties() const;
211 QVariant property(const QString &name);
212 QVariant property(const QString &name, const QVariant &defaultValue);
213
214#ifdef QT_PLATFORM_WINDOW_HAS_VIRTUAL_SET_BACKING_STORE
215 void setBackingStore(QPlatformBackingStore *store) override;
216#else
217 void setBackingStore(QWaylandShmBackingStore *backingStore) { mBackingStore = backingStore; }
218#endif
219 QWaylandShmBackingStore *backingStore() const { return mBackingStore; }
220
221 void setShellIntegration(QWaylandShellIntegration *shellIntegration);
222 QWaylandShellIntegration *shellIntegration() const { return mShellIntegration; }
223
224 bool setKeyboardGrabEnabled(bool) override { return false; }
225 void propagateSizeHints() override;
226 void addAttachOffset(const QPoint point);
227
228 bool startSystemResize(Qt::Edges edges) override;
229 bool startSystemMove() override;
230
231 void timerEvent(QTimerEvent *event) override;
232 void requestUpdate() override;
233 void handleUpdate();
234 void deliverUpdateRequest() override;
235
236 void setXdgActivationToken(const QString &token);
237 void requestXdgActivationToken(uint serial) override;
238
239 void beginFrame();
240 void endFrame();
241
242 void closeChildPopups();
243
244 // should be invoked whenever a property that potentially affects
245 // exposure changes
246 void updateExposure();
247
248 virtual void reinit();
249 void reset();
250 void initializeWlSurface();
251
252 bool windowEvent(QEvent *event) override;
253
254 QSurfaceFormat format() const override;
255
256public Q_SLOTS:
257 void applyConfigure();
258
259Q_SIGNALS:
260 void wlSurfaceCreated();
261 void wlSurfaceDestroyed();
262
263protected:
264 virtual void doHandleFrameCallback();
265 virtual QRect defaultGeometry() const;
266 void setFormat(const QSurfaceFormat &format);
267
268 // this should be called directly for buffer size changes only
269 // use updateExposure for anything affecting the on/off state
270 void sendExposeEvent(const QRect &rect);
271
272 QWaylandDisplay *mDisplay = nullptr;
273
274 // mSurface can be written by the main thread. Other threads should claim a read lock for access
275 mutable QReadWriteLock mSurfaceLock;
276 QScopedPointer<QWaylandSurface> mSurface;
277 QScopedPointer<QWaylandFractionalScale> mFractionalScale;
278 QScopedPointer<QWaylandViewport> mViewport;
279
280 QWaylandShellIntegration *mShellIntegration = nullptr;
281 QWaylandShellSurface *mShellSurface = nullptr;
282 QWaylandSubSurface *mSubSurfaceWindow = nullptr;
283 QList<QWaylandSubSurface *> mChildren;
284
285 std::unique_ptr<QWaylandAbstractDecoration> mWindowDecoration;
286 bool mWindowDecorationEnabled = false;
287 bool mMouseEventsInContentArea = false;
288 Qt::MouseButtons mMousePressedInContentArea = Qt::NoButton;
289
290#ifndef QT_NO_GESTURES
291 enum GestureState {
292 GestureNotActive,
293 GestureActiveInContentArea,
294 GestureActiveInDecoration
295 };
296
297 // We want gestures started in the decoration area to be completely ignored even if the mouse
298 // pointer is later moved to content area. Likewise, gestures started in the content area should
299 // keep sending events even if the mouse pointer is moved over the decoration (consider that
300 // the events for that gesture will be sent to us even if it's moved outside the window).
301 // So we track the gesture state and accept or ignore events based on that. Note that
302 // concurrent gestures of different types are not allowed in the protocol, so single state is
303 // enough
304 GestureState mGestureState = GestureNotActive;
305#endif
306
307 std::atomic_bool mFrameCallbackTimedOut = false; // Whether the frame callback has timed out
308 int mFrameCallbackCheckIntervalTimerId = -1;
309 QAtomicInt mWaitingForUpdateDelivery = false;
310
311 bool mWaitingForFrameCallback = false; // Protected by mFrameSyncMutex
312 QElapsedTimer mFrameCallbackElapsedTimer; // Protected by mFrameSyncMutex
313 struct ::wl_callback *mFrameCallback = nullptr; // Protected by mFrameSyncMutex
314 QMutex mFrameSyncMutex;
315 QWaitCondition mFrameSyncWait;
316
317 // True when we have called deliverRequestUpdate, but the client has not yet attached a new buffer
318 std::atomic_bool mWaitingForUpdate = false;
319 bool mExposed = false;
320 std::atomic_bool mExposeEventNeedsAttachedBuffer = false;
321
322 // written from the main thread, read by the render thread
323 std::atomic_bool mWaitingToApplyConfigure = false;
324 // written from the render thread, read by the main thread
325 std::atomic_bool mInFrameRender = false;
326
327 int mFrameCallbackTimeout = 100;
328 QVariantMap m_properties;
329
330 bool mSentInitialResize = false;
331 QPoint mOffset;
332 std::optional<qreal> mScale = std::nullopt;
333
334 QString mWindowTitle;
335 QIcon mWindowIcon;
336
337 Qt::WindowFlags mFlags;
338 QRegion mMask;
339
340 // Empty QRegion maps to "infinite" input region, needs a dedicated "deliberately empty" state.
341 QRegion mInputRegion;
342 bool mTransparentInputRegion = false;
343
344 QRegion mOpaqueArea;
345 Qt::WindowStates mLastReportedWindowStates = Qt::WindowNoState;
346 ToplevelWindowTilingStates mLastReportedToplevelWindowTilingStates = WindowNoState;
347
348 QWaylandShmBackingStore *mBackingStore = nullptr;
349
350 QMargins mCustomMargins;
351
352 QPointer<QWaylandWindow> mTransientParent;
353 QList<QPointer<QWaylandWindow>> mChildPopups;
354
355 Qt::ScreenOrientation mLastReportedContentOrientation = Qt::PrimaryOrientation;
356
357 std::unique_ptr<ColorManagementSurface> mColorManagementSurface;
358 QSurfaceFormat mSurfaceFormat;
359
360#if QT_CONFIG(cursor)
361 QCursor mStoredCursor;
362 bool mHasStoredCursor = false;
363#endif
364
365private:
366 void setGeometry_helper(const QRect &rect);
367 void synthesizeExposeOnGeometryChange();
368 void initWindow();
369 bool shouldCreateShellSurface() const;
370 bool shouldCreateSubSurface() const;
371 void resetSurfaceRole();
372 void resetFrameCallback();
373 QPlatformScreen *calculateScreenFromSurfaceEvents() const;
374 void setOpaqueArea(const QRegion &opaqueArea);
375 bool isOpaque() const;
376 void updateInputRegion();
377 void updateViewport();
378 bool calculateExposure() const;
379 void setPendingImageDescription();
380
381 void handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e);
382 void handleScreensChanged();
383 void updateScale();
384 void setScale(qreal newScale);
385
386 QWaylandWindow *guessTransientParent() const;
387 void addChildPopup(QWaylandWindow *child);
388 void removeChildPopup(QWaylandWindow *child);
389
390 bool mInResizeFromApplyConfigure = false;
391 bool lastVisible = false;
392 QRect mLastExposeGeometry;
393 std::unique_ptr<ImageDescription> mPendingImageDescription;
394
395 static const wl_callback_listener callbackListener;
396 void handleFrameCallback(struct ::wl_callback* callback);
397 const QPlatformWindow *lastParent = nullptr;
398
399 static QWaylandWindow *mMouseGrab;
400 static QWaylandWindow *mTopPopup;
401
402 friend class QWaylandSubSurface;
403};
404
405Q_DECLARE_OPERATORS_FOR_FLAGS(QWaylandWindow::ToplevelWindowTilingStates)
406
407inline QIcon QWaylandWindow::windowIcon() const
408{
409 return mWindowIcon;
410}
411
412inline QPoint QWaylandWindow::attachOffset() const
413{
414 return mOffset;
415}
416
417}
418
419QT_END_NAMESPACE
420
421#endif // QWAYLANDWINDOW_H
422

source code of qtbase/src/plugins/platforms/wayland/qwaylandwindow_p.h