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 QWAYLANDDISPLAY_H |
5 | #define QWAYLANDDISPLAY_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/QList> |
19 | #include <QtCore/QObject> |
20 | #include <QtCore/QPointer> |
21 | #include <QtCore/QRect> |
22 | #include <QtCore/QMutex> |
23 | #include <QtCore/QReadWriteLock> |
24 | |
25 | #include <QtCore/QWaitCondition> |
26 | #include <QtCore/QLoggingCategory> |
27 | |
28 | #include <QtWaylandClient/private/qwayland-wayland.h> |
29 | #include <QtWaylandClient/private/qtwaylandclientglobal_p.h> |
30 | #include <QtWaylandClient/private/qwaylandshm_p.h> |
31 | |
32 | #include <qpa/qplatforminputcontextfactory_p.h> |
33 | |
34 | #if QT_CONFIG(xkbcommon) |
35 | #include <QtGui/private/qxkbcommon_p.h> |
36 | #endif |
37 | |
38 | struct wl_cursor_image; |
39 | struct wp_viewport; |
40 | |
41 | QT_BEGIN_NAMESPACE |
42 | |
43 | class QAbstractEventDispatcher; |
44 | class QSocketNotifier; |
45 | class QPlatformScreen; |
46 | class QPlatformPlaceholderScreen; |
47 | |
48 | namespace QtWayland { |
49 | class qt_surface_extension; |
50 | class zwp_text_input_manager_v1; |
51 | class zwp_text_input_manager_v2; |
52 | class zwp_text_input_manager_v4; |
53 | class qt_text_input_method_manager_v1; |
54 | class wp_cursor_shape_manager_v1; |
55 | class wp_fractional_scale_manager_v1; |
56 | class wp_viewporter; |
57 | class qt_toplevel_drag_manager_v1; |
58 | } |
59 | |
60 | namespace QtWaylandClient { |
61 | |
62 | Q_WAYLANDCLIENT_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcQpaWayland); |
63 | |
64 | class QWaylandInputDevice; |
65 | class QWaylandBuffer; |
66 | class QWaylandScreen; |
67 | class QWaylandXdgOutputManagerV1; |
68 | class QWaylandClientBufferIntegration; |
69 | class QWaylandWindowManagerIntegration; |
70 | class QWaylandDataDeviceManager; |
71 | #if QT_CONFIG(wayland_client_primary_selection) |
72 | class QWaylandPrimarySelectionDeviceManagerV1; |
73 | #endif |
74 | #if QT_CONFIG(tabletevent) |
75 | class QWaylandTabletManagerV2; |
76 | #endif |
77 | class QWaylandPointerGestures; |
78 | class QWaylandTouchExtension; |
79 | class QWaylandQtKeyExtension; |
80 | class QWaylandWindow; |
81 | class QWaylandIntegration; |
82 | class QWaylandHardwareIntegration; |
83 | class QWaylandSurface; |
84 | class QWaylandShellIntegration; |
85 | class QWaylandCursor; |
86 | class QWaylandCursorTheme; |
87 | class EventThread; |
88 | |
89 | typedef void (*RegistryListener)(void *data, |
90 | struct wl_registry *registry, |
91 | uint32_t id, |
92 | const QString &interface, |
93 | uint32_t version); |
94 | |
95 | class Q_WAYLANDCLIENT_EXPORT QWaylandDisplay : public QObject, public QtWayland::wl_registry { |
96 | Q_OBJECT |
97 | |
98 | public: |
99 | QWaylandDisplay(QWaylandIntegration *waylandIntegration); |
100 | ~QWaylandDisplay(void) override; |
101 | |
102 | bool initialize(); |
103 | |
104 | #if QT_CONFIG(xkbcommon) |
105 | struct xkb_context *xkbContext() const { return mXkbContext.get(); } |
106 | #endif |
107 | |
108 | QList<QWaylandScreen *> screens() const { return mScreens; } |
109 | QPlatformPlaceholderScreen *placeholderScreen() const { return mPlaceholderScreen; } |
110 | void ensureScreen(); |
111 | |
112 | QWaylandScreen *screenForOutput(struct wl_output *output) const; |
113 | void handleScreenInitialized(QWaylandScreen *screen); |
114 | |
115 | struct wl_surface *createSurface(void *handle); |
116 | struct ::wl_region *createRegion(const QRegion &qregion); |
117 | struct ::wl_subsurface *createSubSurface(QWaylandWindow *window, QWaylandWindow *parent); |
118 | struct ::wp_viewport *createViewport(QWaylandWindow *window); |
119 | |
120 | QWaylandShellIntegration *shellIntegration() const; |
121 | QWaylandClientBufferIntegration *clientBufferIntegration() const; |
122 | QWaylandWindowManagerIntegration *windowManagerIntegration() const; |
123 | |
124 | #if QT_CONFIG(cursor) |
125 | QWaylandCursor *waylandCursor(); |
126 | QWaylandCursorTheme *loadCursorTheme(const QString &name, int pixelSize); |
127 | #endif |
128 | struct wl_display *wl_display() const { return mDisplay; } |
129 | struct ::wl_registry *wl_registry() { return object(); } |
130 | |
131 | const struct wl_compositor *wl_compositor() const { return mCompositor.object(); } |
132 | QtWayland::wl_compositor *compositor() { return &mCompositor; } |
133 | |
134 | QList<QWaylandInputDevice *> inputDevices() const { return mInputDevices; } |
135 | QWaylandInputDevice *defaultInputDevice() const; |
136 | QWaylandInputDevice *currentInputDevice() const { return defaultInputDevice(); } |
137 | #if QT_CONFIG(wayland_datadevice) |
138 | QWaylandDataDeviceManager *dndSelectionHandler() const { return mDndSelectionHandler.get(); } |
139 | #endif |
140 | #if QT_CONFIG(wayland_client_primary_selection) |
141 | QWaylandPrimarySelectionDeviceManagerV1 *primarySelectionManager() const { return mPrimarySelectionManager.data(); } |
142 | #endif |
143 | QtWayland::qt_surface_extension *windowExtension() const { return mWindowExtension.data(); } |
144 | #if QT_CONFIG(tabletevent) |
145 | QWaylandTabletManagerV2 *tabletManager() const { return mTabletManager.data(); } |
146 | #endif |
147 | QWaylandPointerGestures *pointerGestures() const { return mPointerGestures.data(); } |
148 | QWaylandTouchExtension *touchExtension() const { return mTouchExtension.data(); } |
149 | QtWayland::qt_text_input_method_manager_v1 *textInputMethodManager() const { return mTextInputMethodManager.data(); } |
150 | QtWayland::zwp_text_input_manager_v1 *textInputManagerv1() const { return mTextInputManagerv1.data(); } |
151 | QtWayland::zwp_text_input_manager_v2 *textInputManagerv2() const { return mTextInputManagerv2.data(); } |
152 | QtWayland::zwp_text_input_manager_v4 *textInputManagerv4() const { return mTextInputManagerv4.data(); } |
153 | QWaylandHardwareIntegration *hardwareIntegration() const { return mHardwareIntegration.data(); } |
154 | QWaylandXdgOutputManagerV1 *xdgOutputManager() const { return mXdgOutputManager.data(); } |
155 | QtWayland::wp_fractional_scale_manager_v1 *fractionalScaleManager() const { return mFractionalScaleManager.data(); } |
156 | QtWayland::wp_viewporter *viewporter() const { return mViewporter.data(); } |
157 | QtWayland::wp_cursor_shape_manager_v1 *cursorShapeManager() const { return mCursorShapeManager.data();} |
158 | QtWayland::qt_toplevel_drag_manager_v1 *xdgToplevelDragManager() const { return mXdgToplevelDragManager.data();} |
159 | |
160 | struct RegistryGlobal { |
161 | uint32_t id; |
162 | QString interface; |
163 | uint32_t version; |
164 | struct ::wl_registry *registry = nullptr; |
165 | RegistryGlobal(uint32_t id_, const QString &interface_, uint32_t version_, struct ::wl_registry *registry_) |
166 | : id(id_), interface(interface_), version(version_), registry(registry_) { } |
167 | }; |
168 | QList<RegistryGlobal> globals() const { return mGlobals; } |
169 | bool hasRegistryGlobal(QStringView interfaceName) const; |
170 | |
171 | /* wl_registry_add_listener does not add but rather sets a listener, so this function is used |
172 | * to enable many listeners at once. */ |
173 | void addRegistryListener(RegistryListener listener, void *data); |
174 | void removeListener(RegistryListener listener, void *data); |
175 | |
176 | QWaylandShm *shm() const { return mShm.data(); } |
177 | |
178 | static uint32_t currentTimeMillisec(); |
179 | |
180 | void forceRoundTrip(); |
181 | |
182 | bool supportsWindowDecoration() const; |
183 | |
184 | uint32_t lastInputSerial() const { return mLastInputSerial; } |
185 | QWaylandInputDevice *lastInputDevice() const { return mLastInputDevice; } |
186 | QWaylandWindow *lastInputWindow() const; |
187 | void setLastInputDevice(QWaylandInputDevice *device, uint32_t serial, QWaylandWindow *window); |
188 | |
189 | bool isWindowActivated(const QWaylandWindow *window); |
190 | void handleWindowActivated(QWaylandWindow *window); |
191 | void handleWindowDeactivated(QWaylandWindow *window); |
192 | void handleKeyboardFocusChanged(QWaylandInputDevice *inputDevice); |
193 | void handleWindowDestroyed(QWaylandWindow *window); |
194 | |
195 | wl_event_queue *frameEventQueue() { return m_frameEventQueue; }; |
196 | |
197 | bool isKeyboardAvailable() const; |
198 | bool isClientSideInputContextRequested() const; |
199 | |
200 | void initEventThread(); |
201 | |
202 | public slots: |
203 | void blockingReadEvents(); |
204 | void flushRequests(); |
205 | |
206 | signals: |
207 | void reconnected(); |
208 | void globalAdded(const RegistryGlobal &global); |
209 | void globalRemoved(const RegistryGlobal &global); |
210 | |
211 | private: |
212 | void checkWaylandError(); |
213 | void reconnect(); |
214 | void setupConnection(); |
215 | void handleWaylandSync(); |
216 | void requestWaylandSync(); |
217 | |
218 | void checkTextInputProtocol(); |
219 | |
220 | struct Listener { |
221 | Listener() = default; |
222 | Listener(RegistryListener incomingListener, |
223 | void* incomingData) |
224 | : listener(incomingListener), data(incomingData) |
225 | {} |
226 | RegistryListener listener = nullptr; |
227 | void *data = nullptr; |
228 | }; |
229 | |
230 | struct wl_display *mDisplay = nullptr; |
231 | std::unique_ptr<EventThread> m_eventThread; |
232 | wl_event_queue *m_frameEventQueue = nullptr; |
233 | QScopedPointer<EventThread> m_frameEventQueueThread; |
234 | QtWayland::wl_compositor mCompositor; |
235 | QScopedPointer<QWaylandShm> mShm; |
236 | QList<QWaylandScreen *> mWaitingScreens; |
237 | QList<QWaylandScreen *> mScreens; |
238 | QPlatformPlaceholderScreen *mPlaceholderScreen = nullptr; |
239 | QList<QWaylandInputDevice *> mInputDevices; |
240 | QList<Listener> mRegistryListeners; |
241 | QWaylandIntegration *mWaylandIntegration = nullptr; |
242 | #if QT_CONFIG(cursor) |
243 | struct WaylandCursorTheme { |
244 | QString name; |
245 | int pixelSize; |
246 | std::unique_ptr<QWaylandCursorTheme> theme; |
247 | }; |
248 | std::vector<WaylandCursorTheme> mCursorThemes; |
249 | |
250 | struct FindExistingCursorThemeResult { |
251 | std::vector<WaylandCursorTheme>::const_iterator position; |
252 | bool found; |
253 | |
254 | QWaylandCursorTheme *theme() const noexcept |
255 | { return found ? position->theme.get() : nullptr; } |
256 | }; |
257 | FindExistingCursorThemeResult findExistingCursorTheme(const QString &name, int pixelSize) const noexcept; |
258 | |
259 | QScopedPointer<QWaylandCursor> mCursor; |
260 | #endif |
261 | #if QT_CONFIG(wayland_datadevice) |
262 | QScopedPointer<QWaylandDataDeviceManager> mDndSelectionHandler; |
263 | #endif |
264 | QScopedPointer<QtWayland::qt_surface_extension> mWindowExtension; |
265 | QScopedPointer<QtWayland::wl_subcompositor> mSubCompositor; |
266 | QScopedPointer<QWaylandTouchExtension> mTouchExtension; |
267 | QScopedPointer<QWaylandQtKeyExtension> mQtKeyExtension; |
268 | QScopedPointer<QWaylandWindowManagerIntegration> mWindowManagerIntegration; |
269 | #if QT_CONFIG(tabletevent) |
270 | QScopedPointer<QWaylandTabletManagerV2> mTabletManager; |
271 | #endif |
272 | QScopedPointer<QWaylandPointerGestures> mPointerGestures; |
273 | #if QT_CONFIG(wayland_client_primary_selection) |
274 | QScopedPointer<QWaylandPrimarySelectionDeviceManagerV1> mPrimarySelectionManager; |
275 | #endif |
276 | QScopedPointer<QtWayland::qt_text_input_method_manager_v1> mTextInputMethodManager; |
277 | QScopedPointer<QtWayland::zwp_text_input_manager_v1> mTextInputManagerv1; |
278 | QScopedPointer<QtWayland::zwp_text_input_manager_v2> mTextInputManagerv2; |
279 | QScopedPointer<QtWayland::zwp_text_input_manager_v4> mTextInputManagerv4; |
280 | QScopedPointer<QWaylandHardwareIntegration> mHardwareIntegration; |
281 | QScopedPointer<QWaylandXdgOutputManagerV1> mXdgOutputManager; |
282 | QScopedPointer<QtWayland::wp_viewporter> mViewporter; |
283 | QScopedPointer<QtWayland::wp_fractional_scale_manager_v1> mFractionalScaleManager; |
284 | QScopedPointer<QtWayland::wp_cursor_shape_manager_v1> mCursorShapeManager; |
285 | QScopedPointer<QtWayland::qt_toplevel_drag_manager_v1> mXdgToplevelDragManager; |
286 | int mFd = -1; |
287 | int mWritableNotificationFd = -1; |
288 | QList<RegistryGlobal> mGlobals; |
289 | uint32_t mLastInputSerial = 0; |
290 | QWaylandInputDevice *mLastInputDevice = nullptr; |
291 | QPointer<QWaylandWindow> mLastInputWindow; |
292 | QPointer<QWaylandWindow> mLastKeyboardFocus; |
293 | QList<QWaylandWindow *> mActiveWindows; |
294 | struct wl_callback *mSyncCallback = nullptr; |
295 | static const wl_callback_listener syncCallbackListener; |
296 | bool mWaylandTryReconnect = false; |
297 | |
298 | bool mClientSideInputContextRequested = [] () { |
299 | const QString& requested = QPlatformInputContextFactory::requested(); |
300 | return !requested.isEmpty() && requested != QLatin1String("wayland" ); |
301 | }(); |
302 | QStringList mTextInputManagerList; |
303 | int mTextInputManagerIndex = INT_MAX; |
304 | |
305 | void registry_global(uint32_t id, const QString &interface, uint32_t version) override; |
306 | void registry_global_remove(uint32_t id) override; |
307 | |
308 | #if QT_CONFIG(xkbcommon) |
309 | QXkbCommon::ScopedXKBContext mXkbContext; |
310 | #endif |
311 | |
312 | friend class QWaylandIntegration; |
313 | }; |
314 | |
315 | } |
316 | |
317 | QT_END_NAMESPACE |
318 | |
319 | #endif // QWAYLANDDISPLAY_H |
320 | |