1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2024 Jie Liu <liujie01@kylinos.cn>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QWAYLANDDISPLAY_H
6#define QWAYLANDDISPLAY_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <QtCore/QList>
20#include <QtCore/QObject>
21#include <QtCore/QPointer>
22#include <QtCore/QRect>
23#include <QtCore/QMutex>
24#include <QtCore/QReadWriteLock>
25
26#include <QtCore/QWaitCondition>
27#include <QtCore/QLoggingCategory>
28
29#include <QtWaylandClient/private/qwayland-wayland.h>
30#include <QtWaylandClient/private/qtwaylandclientglobal_p.h>
31#include <QtWaylandClient/private/qwaylandshm_p.h>
32
33#include <qpa/qplatforminputcontextfactory_p.h>
34
35#if QT_CONFIG(xkbcommon)
36#include <QtGui/private/qxkbcommon_p.h>
37#endif
38
39struct wl_cursor_image;
40struct wp_viewport;
41
42QT_BEGIN_NAMESPACE
43
44#define WAYLAND_IM_KEY "wayland"
45
46class QAbstractEventDispatcher;
47class QSocketNotifier;
48class QPlatformScreen;
49class QPlatformPlaceholderScreen;
50
51namespace QtWayland {
52 class zwp_text_input_manager_v1;
53 class zwp_text_input_manager_v2;
54 class zwp_text_input_manager_v3;
55 class qt_text_input_method_manager_v1;
56 class wp_cursor_shape_manager_v1;
57 class wp_fractional_scale_manager_v1;
58 class wp_viewporter;
59 class xdg_system_bell_v1;
60 class xdg_toplevel_drag_manager_v1;
61 class wp_pointer_warp_v1;
62}
63
64namespace QtWaylandClient {
65
66QT_DECLARE_EXPORTED_QT_LOGGING_CATEGORY(lcQpaWayland, Q_WAYLANDCLIENT_EXPORT);
67
68class QWaylandAppMenuManager;
69class QWaylandInputDevice;
70class QWaylandBuffer;
71class QWaylandScreen;
72class QWaylandXdgOutputManagerV1;
73class QWaylandClientBufferIntegration;
74class QWaylandWindowManagerIntegration;
75class QWaylandDataDeviceManager;
76#if QT_CONFIG(clipboard)
77class QWaylandDataControlManagerV1;
78#endif
79#if QT_CONFIG(wayland_client_primary_selection)
80class QWaylandPrimarySelectionDeviceManagerV1;
81#endif
82#if QT_CONFIG(tabletevent)
83class QWaylandTabletManagerV2;
84#endif
85class QWaylandPointerGestures;
86class QWaylandWindow;
87class QWaylandIntegration;
88class QWaylandHardwareIntegration;
89class QWaylandSurface;
90class QWaylandShellIntegration;
91class QWaylandCursor;
92class QWaylandCursorTheme;
93class EventThread;
94class ColorManager;
95
96typedef void (*RegistryListener)(void *data,
97 struct wl_registry *registry,
98 uint32_t id,
99 const QString &interface,
100 uint32_t version);
101
102class Q_WAYLANDCLIENT_EXPORT QWaylandDisplay : public QObject, public QtWayland::wl_registry {
103 Q_OBJECT
104
105public:
106 QWaylandDisplay(QWaylandIntegration *waylandIntegration);
107 ~QWaylandDisplay(void) override;
108
109 bool initialize();
110
111#if QT_CONFIG(xkbcommon)
112 struct xkb_context *xkbContext() const { return mXkbContext.get(); }
113#endif
114
115 QList<QWaylandScreen *> screens() const { return mScreens; }
116 QPlatformPlaceholderScreen *placeholderScreen() const { return mPlaceholderScreen; }
117 void ensureScreen();
118
119 QWaylandScreen *screenForOutput(struct wl_output *output) const;
120 void handleScreenInitialized(QWaylandScreen *screen);
121
122 struct wl_surface *createSurface(void *handle);
123 struct ::wl_region *createRegion(const QRegion &qregion);
124 struct ::wl_subsurface *createSubSurface(QWaylandWindow *window, QWaylandWindow *parent);
125 struct ::wp_viewport *createViewport(QWaylandWindow *window);
126
127 QWaylandShellIntegration *shellIntegration() const;
128 QWaylandClientBufferIntegration *clientBufferIntegration() const;
129 QWaylandWindowManagerIntegration *windowManagerIntegration() const;
130
131#if QT_CONFIG(cursor)
132 QWaylandCursor *waylandCursor();
133 QWaylandCursorTheme *loadCursorTheme(const QString &name, int pixelSize);
134#endif
135 struct wl_display *wl_display() const
136 {
137 return mDisplay;
138 }
139 struct ::wl_registry *wl_registry() { return object(); }
140
141 QtWayland::wl_compositor *compositor()
142 {
143 return mGlobals.compositor.get();
144 }
145
146 QList<QWaylandInputDevice *> inputDevices() const { return mInputDevices; }
147 QWaylandInputDevice *defaultInputDevice() const;
148 QWaylandInputDevice *currentInputDevice() const { return defaultInputDevice(); }
149#if QT_CONFIG(wayland_datadevice)
150 QWaylandDataDeviceManager *dndSelectionHandler() const
151 {
152 return mGlobals.dndSelectionHandler.get();
153 }
154#endif
155#if QT_CONFIG(clipboard)
156 QWaylandDataControlManagerV1 *dataControlManager() const
157 {
158 return mGlobals.dataControlManager.get();
159 }
160#endif
161#if QT_CONFIG(wayland_client_primary_selection)
162 QWaylandPrimarySelectionDeviceManagerV1 *primarySelectionManager() const
163 {
164 return mGlobals.primarySelectionManager.get();
165 }
166#endif
167#if QT_CONFIG(tabletevent)
168 QWaylandTabletManagerV2 *tabletManager() const
169 {
170 return mGlobals.tabletManager.get();
171 }
172#endif
173 QWaylandPointerGestures *pointerGestures() const
174 {
175 return mGlobals.pointerGestures.get();
176 }
177 QtWayland::qt_text_input_method_manager_v1 *textInputMethodManager() const
178 {
179 return mGlobals.textInputMethodManager.get();
180 }
181 QtWayland::zwp_text_input_manager_v1 *textInputManagerv1() const
182 {
183 return mGlobals.textInputManagerv1.get();
184 }
185 QtWayland::zwp_text_input_manager_v2 *textInputManagerv2() const
186 {
187 return mGlobals.textInputManagerv2.get();
188 }
189 QtWayland::zwp_text_input_manager_v3 *textInputManagerv3() const
190 {
191 return mGlobals.textInputManagerv3.get();
192 }
193 QWaylandHardwareIntegration *hardwareIntegration() const
194 {
195 return mGlobals.hardwareIntegration.get();
196 }
197 QWaylandXdgOutputManagerV1 *xdgOutputManager() const
198 {
199 return mGlobals.xdgOutputManager.get();
200 }
201 QtWayland::wp_fractional_scale_manager_v1 *fractionalScaleManager() const
202 {
203 return mGlobals.fractionalScaleManager.get();
204 }
205 QtWayland::wp_viewporter *viewporter() const
206 {
207 return mGlobals.viewporter.get();
208 }
209 QtWayland::wp_cursor_shape_manager_v1 *cursorShapeManager() const
210 {
211 return mGlobals.cursorShapeManager.get();
212 }
213 QtWayland::xdg_toplevel_drag_manager_v1 *xdgToplevelDragManager() const
214 {
215 return mGlobals.xdgToplevelDragManager.get();
216 }
217 QtWayland::xdg_system_bell_v1 *systemBell() const
218 {
219 return mGlobals.systemBell.get();
220 }
221 QWaylandAppMenuManager *appMenuManager() const
222 {
223 return mGlobals.appMenuManager.get();
224 }
225 ColorManager *colorManager() const
226 {
227 return mGlobals.colorManager.get();
228 }
229 QtWayland::wp_pointer_warp_v1 *pointerWarp() const
230 {
231 return mGlobals.pointerWarp.get();
232 }
233
234 struct RegistryGlobal {
235 uint32_t id;
236 QString interface;
237 uint32_t version;
238 struct ::wl_registry *registry = nullptr;
239 RegistryGlobal(uint32_t id_, const QString &interface_, uint32_t version_, struct ::wl_registry *registry_)
240 : id(id_), interface(interface_), version(version_), registry(registry_) { }
241 };
242 QList<RegistryGlobal> globals() const
243 {
244 return mRegistryGlobals;
245 }
246 bool hasRegistryGlobal(QStringView interfaceName) const;
247
248 /* wl_registry_add_listener does not add but rather sets a listener, so this function is used
249 * to enable many listeners at once. */
250 void addRegistryListener(RegistryListener listener, void *data);
251 void removeListener(RegistryListener listener, void *data);
252
253 QWaylandShm *shm() const
254 {
255 return mGlobals.shm.get();
256 }
257
258 void forceRoundTrip();
259
260 bool supportsWindowDecoration() const;
261
262 uint32_t lastInputSerial() const { return mLastInputSerial; }
263 QWaylandInputDevice *lastInputDevice() const { return mLastInputDevice; }
264 QWaylandWindow *lastInputWindow() const;
265 void setLastInputDevice(QWaylandInputDevice *device, uint32_t serial, QWaylandWindow *window);
266
267 bool isWindowActivated(const QWaylandWindow *window);
268 void handleWindowActivated(QWaylandWindow *window);
269 void handleWindowDeactivated(QWaylandWindow *window);
270 void handleKeyboardFocusChanged(QWaylandInputDevice *inputDevice);
271 void handleWindowDestroyed(QWaylandWindow *window);
272
273 wl_event_queue *frameEventQueue() { return m_frameEventQueue; };
274
275 bool isKeyboardAvailable() const;
276 bool isWaylandInputContextRequested() const;
277
278 void initEventThread();
279
280public Q_SLOTS:
281 void flushRequests();
282
283Q_SIGNALS:
284 void connected();
285 void globalAdded(const RegistryGlobal &global);
286 void globalRemoved(const RegistryGlobal &global);
287
288private:
289 void checkWaylandError();
290 void reconnect();
291 void setupConnection();
292 void handleWaylandSync();
293 void requestWaylandSync();
294
295 void checkTextInputProtocol();
296
297 struct Listener {
298 Listener() = default;
299 Listener(RegistryListener incomingListener,
300 void* incomingData)
301 : listener(incomingListener), data(incomingData)
302 {}
303 RegistryListener listener = nullptr;
304 void *data = nullptr;
305 };
306 struct wl_display *mDisplay = nullptr;
307 std::unique_ptr<EventThread> m_eventThread;
308 wl_event_queue *m_frameEventQueue = nullptr;
309 QScopedPointer<EventThread> m_frameEventQueueThread;
310 QList<QWaylandScreen *> mWaitingScreens;
311 QList<QWaylandScreen *> mScreens;
312 QPlatformPlaceholderScreen *mPlaceholderScreen = nullptr;
313 QList<QWaylandInputDevice *> mInputDevices;
314 QList<Listener> mRegistryListeners;
315 QWaylandIntegration *mWaylandIntegration = nullptr;
316#if QT_CONFIG(cursor)
317 struct WaylandCursorTheme {
318 QString name;
319 int pixelSize;
320 std::unique_ptr<QWaylandCursorTheme> theme;
321 };
322 std::vector<WaylandCursorTheme> mCursorThemes;
323
324 struct FindExistingCursorThemeResult {
325 std::vector<WaylandCursorTheme>::const_iterator position;
326 bool found;
327
328 QWaylandCursorTheme *theme() const noexcept
329 { return found ? position->theme.get() : nullptr; }
330 };
331 FindExistingCursorThemeResult findExistingCursorTheme(const QString &name,
332 int pixelSize) const noexcept;
333 QScopedPointer<QWaylandCursor> mCursor;
334#endif
335
336 struct GlobalHolder
337 {
338 std::unique_ptr<QtWayland::wl_compositor> compositor;
339 std::unique_ptr<QWaylandShm> shm;
340#if QT_CONFIG(wayland_datadevice)
341 std::unique_ptr<QWaylandDataDeviceManager> dndSelectionHandler;
342#endif
343 std::unique_ptr<QtWayland::wl_subcompositor> subCompositor;
344#if QT_CONFIG(tabletevent)
345 std::unique_ptr<QWaylandTabletManagerV2> tabletManager;
346#endif
347 std::unique_ptr<QWaylandPointerGestures> pointerGestures;
348#if QT_CONFIG(clipboard)
349 std::unique_ptr<QWaylandDataControlManagerV1> dataControlManager;
350#endif
351#if QT_CONFIG(wayland_client_primary_selection)
352 std::unique_ptr<QWaylandPrimarySelectionDeviceManagerV1> primarySelectionManager;
353#endif
354 std::unique_ptr<QtWayland::qt_text_input_method_manager_v1> textInputMethodManager;
355 std::unique_ptr<QtWayland::zwp_text_input_manager_v1> textInputManagerv1;
356 std::unique_ptr<QtWayland::zwp_text_input_manager_v2> textInputManagerv2;
357 std::unique_ptr<QtWayland::zwp_text_input_manager_v3> textInputManagerv3;
358 std::unique_ptr<QWaylandHardwareIntegration> hardwareIntegration;
359 std::unique_ptr<QWaylandXdgOutputManagerV1> xdgOutputManager;
360 std::unique_ptr<QtWayland::wp_viewporter> viewporter;
361 std::unique_ptr<QtWayland::wp_fractional_scale_manager_v1> fractionalScaleManager;
362 std::unique_ptr<QtWayland::wp_cursor_shape_manager_v1> cursorShapeManager;
363 std::unique_ptr<QtWayland::xdg_system_bell_v1> systemBell;
364 std::unique_ptr<QtWayland::xdg_toplevel_drag_manager_v1> xdgToplevelDragManager;
365 std::unique_ptr<QWaylandWindowManagerIntegration> windowManagerIntegration;
366 std::unique_ptr<QWaylandAppMenuManager> appMenuManager;
367 std::unique_ptr<ColorManager> colorManager;
368 std::unique_ptr<QtWayland::wp_pointer_warp_v1> pointerWarp;
369 } mGlobals;
370
371 int mFd = -1;
372 int mWritableNotificationFd = -1;
373 QList<RegistryGlobal> mRegistryGlobals;
374 uint32_t mLastInputSerial = 0;
375 QWaylandInputDevice *mLastInputDevice = nullptr;
376 QPointer<QWaylandWindow> mLastInputWindow;
377 QPointer<QWaylandWindow> mLastKeyboardFocus;
378 QList<QWaylandWindow *> mActiveWindows;
379 struct wl_callback *mSyncCallback = nullptr;
380 static const wl_callback_listener syncCallbackListener;
381 bool mWaylandTryReconnect = false;
382 bool mPreferWlrDataControl = false;
383
384 bool mWaylandInputContextRequested = [] () {
385 const auto requested = QPlatformInputContextFactory::requested();
386 return requested.isEmpty() || requested.contains(str: QLatin1String(WAYLAND_IM_KEY));
387 }();
388 QStringList mTextInputManagerList;
389 int mTextInputManagerIndex = INT_MAX;
390
391 void registry_global(uint32_t id, const QString &interface, uint32_t version) override;
392 void registry_global_remove(uint32_t id) override;
393
394#if QT_CONFIG(xkbcommon)
395 QXkbCommon::ScopedXKBContext mXkbContext;
396#endif
397
398 friend class QWaylandIntegration;
399};
400
401}
402
403QT_END_NAMESPACE
404
405#endif // QWAYLANDDISPLAY_H
406

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