1 | /* |
2 | SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org> |
3 | SPDX-FileCopyrightText: 2018 David Edmundson <davidedmundson@kde.org> |
4 | |
5 | SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL |
6 | */ |
7 | #include "registry.h" |
8 | #include "appmenu.h" |
9 | #include "blur.h" |
10 | #include "compositor.h" |
11 | #include "connection_thread.h" |
12 | #include "contrast.h" |
13 | #include "datadevicemanager.h" |
14 | #include "dpms.h" |
15 | #include "event_queue.h" |
16 | #include "fakeinput.h" |
17 | #include "idleinhibit.h" |
18 | #include "logging.h" |
19 | #include "output.h" |
20 | #include "plasmashell.h" |
21 | #include "plasmavirtualdesktop.h" |
22 | #include "plasmawindowmanagement.h" |
23 | #include "pointerconstraints.h" |
24 | #include "pointergestures.h" |
25 | #include "relativepointer.h" |
26 | #include "seat.h" |
27 | #include "shadow.h" |
28 | #include "shell.h" |
29 | #include "shm_pool.h" |
30 | #include "slide.h" |
31 | #include "subcompositor.h" |
32 | #include "textinput_p.h" |
33 | #include "wayland_pointer_p.h" |
34 | #include "xdgdecoration.h" |
35 | #include "xdgforeign_v2.h" |
36 | #include "xdgoutput.h" |
37 | #include "xdgshell.h" |
38 | #include "xdgshell_p.h" |
39 | // Qt |
40 | #include <QDebug> |
41 | // wayland |
42 | #include "../compat/wayland-xdg-shell-v5-client-protocol.h" |
43 | #include <wayland-appmenu-client-protocol.h> |
44 | #include <wayland-blur-client-protocol.h> |
45 | #include <wayland-client-protocol.h> |
46 | #include <wayland-contrast-client-protocol.h> |
47 | #include <wayland-dpms-client-protocol.h> |
48 | #include <wayland-fake-input-client-protocol.h> |
49 | #include <wayland-idle-inhibit-unstable-v1-client-protocol.h> |
50 | #include <wayland-plasma-shell-client-protocol.h> |
51 | #include <wayland-plasma-virtual-desktop-client-protocol.h> |
52 | #include <wayland-plasma-window-management-client-protocol.h> |
53 | #include <wayland-pointer-constraints-unstable-v1-client-protocol.h> |
54 | #include <wayland-pointer-gestures-unstable-v1-client-protocol.h> |
55 | #include <wayland-relativepointer-unstable-v1-client-protocol.h> |
56 | #include <wayland-shadow-client-protocol.h> |
57 | #include <wayland-slide-client-protocol.h> |
58 | #include <wayland-text-input-v0-client-protocol.h> |
59 | #include <wayland-text-input-v2-client-protocol.h> |
60 | #include <wayland-xdg-decoration-unstable-v1-client-protocol.h> |
61 | #include <wayland-xdg-foreign-unstable-v2-client-protocol.h> |
62 | #include <wayland-xdg-output-unstable-v1-client-protocol.h> |
63 | #include <wayland-xdg-shell-client-protocol.h> |
64 | #include <wayland-xdg-shell-v6-client-protocol.h> |
65 | |
66 | /***** |
67 | * How to add another interface: |
68 | * * define a new enum value in Registry::Interface |
69 | * * define the bind<InterfaceName> method |
70 | * * define the create<InterfaceName> method |
71 | * * define the <interfaceName>Announced signal |
72 | * * define the <interfaceName>Removed signal |
73 | * * add a block to s_interfaces |
74 | * * add the BIND macro for the new bind<InterfaceName> |
75 | * * add the CREATE macro for the new create<InterfaceName> |
76 | * * extend registry unit test to verify that it works |
77 | ****/ |
78 | |
79 | namespace KWayland |
80 | { |
81 | namespace Client |
82 | { |
83 | namespace |
84 | { |
85 | struct SuppertedInterfaceData { |
86 | quint32 maxVersion; |
87 | QByteArray name; |
88 | const wl_interface *interface; |
89 | void (Registry::*announcedSignal)(quint32, quint32); |
90 | void (Registry::*removedSignal)(quint32); |
91 | }; |
92 | // clang-format off |
93 | static const QMap<Registry::Interface, SuppertedInterfaceData> s_interfaces = { |
94 | {Registry::Interface::Compositor, { |
95 | .maxVersion: 4, |
96 | QByteArrayLiteral("wl_compositor" ), |
97 | .interface: &wl_compositor_interface, |
98 | .announcedSignal: &Registry::compositorAnnounced, |
99 | .removedSignal: &Registry::compositorRemoved |
100 | }}, |
101 | {Registry::Interface::DataDeviceManager, { |
102 | .maxVersion: 3, |
103 | QByteArrayLiteral("wl_data_device_manager" ), |
104 | .interface: &wl_data_device_manager_interface, |
105 | .announcedSignal: &Registry::dataDeviceManagerAnnounced, |
106 | .removedSignal: &Registry::dataDeviceManagerRemoved |
107 | }}, |
108 | {Registry::Interface::Output, { |
109 | .maxVersion: 4, |
110 | QByteArrayLiteral("wl_output" ), |
111 | .interface: &wl_output_interface, |
112 | .announcedSignal: &Registry::outputAnnounced, |
113 | .removedSignal: &Registry::outputRemoved |
114 | }}, |
115 | {Registry::Interface::Shm, { |
116 | .maxVersion: 1, |
117 | QByteArrayLiteral("wl_shm" ), |
118 | .interface: &wl_shm_interface, |
119 | .announcedSignal: &Registry::shmAnnounced, |
120 | .removedSignal: &Registry::shmRemoved |
121 | }}, |
122 | {Registry::Interface::Seat, { |
123 | .maxVersion: 5, |
124 | QByteArrayLiteral("wl_seat" ), |
125 | .interface: &wl_seat_interface, |
126 | .announcedSignal: &Registry::seatAnnounced, |
127 | .removedSignal: &Registry::seatRemoved |
128 | }}, |
129 | {Registry::Interface::Shell, { |
130 | .maxVersion: 1, |
131 | QByteArrayLiteral("wl_shell" ), |
132 | .interface: &wl_shell_interface, |
133 | .announcedSignal: &Registry::shellAnnounced, |
134 | .removedSignal: &Registry::shellRemoved |
135 | }}, |
136 | {Registry::Interface::SubCompositor, { |
137 | .maxVersion: 1, |
138 | QByteArrayLiteral("wl_subcompositor" ), |
139 | .interface: &wl_subcompositor_interface, |
140 | .announcedSignal: &Registry::subCompositorAnnounced, |
141 | .removedSignal: &Registry::subCompositorRemoved |
142 | }}, |
143 | {Registry::Interface::PlasmaShell, { |
144 | .maxVersion: 8, |
145 | QByteArrayLiteral("org_kde_plasma_shell" ), |
146 | .interface: &org_kde_plasma_shell_interface, |
147 | .announcedSignal: &Registry::plasmaShellAnnounced, |
148 | .removedSignal: &Registry::plasmaShellRemoved |
149 | }}, |
150 | {Registry::Interface::PlasmaVirtualDesktopManagement, { |
151 | .maxVersion: 2, |
152 | QByteArrayLiteral("org_kde_plasma_virtual_desktop_management" ), |
153 | .interface: &org_kde_plasma_virtual_desktop_management_interface, |
154 | .announcedSignal: &Registry::plasmaVirtualDesktopManagementAnnounced, |
155 | .removedSignal: &Registry::plasmaVirtualDesktopManagementRemoved |
156 | }}, |
157 | {Registry::Interface::PlasmaWindowManagement, { |
158 | .maxVersion: 16, |
159 | QByteArrayLiteral("org_kde_plasma_window_management" ), |
160 | .interface: &org_kde_plasma_window_management_interface, |
161 | .announcedSignal: &Registry::plasmaWindowManagementAnnounced, |
162 | .removedSignal: &Registry::plasmaWindowManagementRemoved |
163 | }}, |
164 | {Registry::Interface::FakeInput, { |
165 | .maxVersion: 4, |
166 | QByteArrayLiteral("org_kde_kwin_fake_input" ), |
167 | .interface: &org_kde_kwin_fake_input_interface, |
168 | .announcedSignal: &Registry::fakeInputAnnounced, |
169 | .removedSignal: &Registry::fakeInputRemoved |
170 | }}, |
171 | {Registry::Interface::Shadow, { |
172 | .maxVersion: 2, |
173 | QByteArrayLiteral("org_kde_kwin_shadow_manager" ), |
174 | .interface: &org_kde_kwin_shadow_manager_interface, |
175 | .announcedSignal: &Registry::shadowAnnounced, |
176 | .removedSignal: &Registry::shadowRemoved |
177 | }}, |
178 | {Registry::Interface::Blur, { |
179 | .maxVersion: 1, |
180 | QByteArrayLiteral("org_kde_kwin_blur_manager" ), |
181 | .interface: &org_kde_kwin_blur_manager_interface, |
182 | .announcedSignal: &Registry::blurAnnounced, |
183 | .removedSignal: &Registry::blurRemoved |
184 | }}, |
185 | {Registry::Interface::Contrast, { |
186 | .maxVersion: 2, |
187 | QByteArrayLiteral("org_kde_kwin_contrast_manager" ), |
188 | .interface: &org_kde_kwin_contrast_manager_interface, |
189 | .announcedSignal: &Registry::contrastAnnounced, |
190 | .removedSignal: &Registry::contrastRemoved |
191 | }}, |
192 | {Registry::Interface::Slide, { |
193 | .maxVersion: 1, |
194 | QByteArrayLiteral("org_kde_kwin_slide_manager" ), |
195 | .interface: &org_kde_kwin_slide_manager_interface, |
196 | .announcedSignal: &Registry::slideAnnounced, |
197 | .removedSignal: &Registry::slideRemoved |
198 | }}, |
199 | {Registry::Interface::Dpms, { |
200 | .maxVersion: 1, |
201 | QByteArrayLiteral("org_kde_kwin_dpms_manager" ), |
202 | .interface: &org_kde_kwin_dpms_manager_interface, |
203 | .announcedSignal: &Registry::dpmsAnnounced, |
204 | .removedSignal: &Registry::dpmsRemoved |
205 | }}, |
206 | {Registry::Interface::TextInputManagerUnstableV0, { |
207 | .maxVersion: 1, |
208 | QByteArrayLiteral("wl_text_input_manager" ), |
209 | .interface: &wl_text_input_manager_interface, |
210 | .announcedSignal: &Registry::textInputManagerUnstableV0Announced, |
211 | .removedSignal: &Registry::textInputManagerUnstableV0Removed |
212 | }}, |
213 | {Registry::Interface::TextInputManagerUnstableV2, { |
214 | .maxVersion: 1, |
215 | QByteArrayLiteral("zwp_text_input_manager_v2" ), |
216 | .interface: &zwp_text_input_manager_v2_interface, |
217 | .announcedSignal: &Registry::textInputManagerUnstableV2Announced, |
218 | .removedSignal: &Registry::textInputManagerUnstableV2Removed |
219 | }}, |
220 | {Registry::Interface::XdgShellUnstableV5, { |
221 | .maxVersion: 1, |
222 | QByteArrayLiteral("xdg_shell" ), |
223 | .interface: &zxdg_shell_v5_interface, |
224 | .announcedSignal: &Registry::xdgShellUnstableV5Announced, |
225 | .removedSignal: &Registry::xdgShellUnstableV5Removed |
226 | }}, |
227 | {Registry::Interface::RelativePointerManagerUnstableV1, { |
228 | .maxVersion: 1, |
229 | QByteArrayLiteral("zwp_relative_pointer_manager_v1" ), |
230 | .interface: &zwp_relative_pointer_manager_v1_interface, |
231 | .announcedSignal: &Registry::relativePointerManagerUnstableV1Announced, |
232 | .removedSignal: &Registry::relativePointerManagerUnstableV1Removed |
233 | }}, |
234 | {Registry::Interface::PointerGesturesUnstableV1, { |
235 | .maxVersion: 1, |
236 | QByteArrayLiteral("zwp_pointer_gestures_v1" ), |
237 | .interface: &zwp_pointer_gestures_v1_interface, |
238 | .announcedSignal: &Registry::pointerGesturesUnstableV1Announced, |
239 | .removedSignal: &Registry::pointerGesturesUnstableV1Removed |
240 | }}, |
241 | {Registry::Interface::PointerConstraintsUnstableV1, { |
242 | .maxVersion: 1, |
243 | QByteArrayLiteral("zwp_pointer_constraints_v1" ), |
244 | .interface: &zwp_pointer_constraints_v1_interface, |
245 | .announcedSignal: &Registry::pointerConstraintsUnstableV1Announced, |
246 | .removedSignal: &Registry::pointerConstraintsUnstableV1Removed |
247 | }}, |
248 | {Registry::Interface::XdgExporterUnstableV2, { |
249 | .maxVersion: 1, |
250 | QByteArrayLiteral("zxdg_exporter_v2" ), |
251 | .interface: &zxdg_exporter_v2_interface, |
252 | .announcedSignal: &Registry::exporterUnstableV2Announced, |
253 | .removedSignal: &Registry::exporterUnstableV2Removed |
254 | }}, |
255 | {Registry::Interface::XdgImporterUnstableV2, { |
256 | .maxVersion: 1, |
257 | QByteArrayLiteral("zxdg_importer_v2" ), |
258 | .interface: &zxdg_importer_v2_interface, |
259 | .announcedSignal: &Registry::importerUnstableV2Announced, |
260 | .removedSignal: &Registry::importerUnstableV2Removed |
261 | }}, |
262 | {Registry::Interface::XdgShellUnstableV6, { |
263 | .maxVersion: 1, |
264 | QByteArrayLiteral("zxdg_shell_v6" ), |
265 | .interface: &zxdg_shell_v6_interface, |
266 | .announcedSignal: &Registry::xdgShellUnstableV6Announced, |
267 | .removedSignal: &Registry::xdgShellUnstableV6Removed |
268 | }}, |
269 | {Registry::Interface::IdleInhibitManagerUnstableV1, { |
270 | .maxVersion: 1, |
271 | QByteArrayLiteral("zwp_idle_inhibit_manager_v1" ), |
272 | .interface: &zwp_idle_inhibit_manager_v1_interface, |
273 | .announcedSignal: &Registry::idleInhibitManagerUnstableV1Announced, |
274 | .removedSignal: &Registry::idleInhibitManagerUnstableV1Removed |
275 | }}, |
276 | {Registry::Interface::AppMenu, { |
277 | .maxVersion: 1, |
278 | QByteArrayLiteral("org_kde_kwin_appmenu_manager" ), |
279 | .interface: &org_kde_kwin_appmenu_manager_interface, |
280 | .announcedSignal: &Registry::appMenuAnnounced, |
281 | .removedSignal: &Registry::appMenuRemoved |
282 | }}, |
283 | {Registry::Interface::XdgOutputUnstableV1, { |
284 | .maxVersion: 2, |
285 | QByteArrayLiteral("zxdg_output_manager_v1" ), |
286 | .interface: &zxdg_output_manager_v1_interface, |
287 | .announcedSignal: &Registry::xdgOutputAnnounced, |
288 | .removedSignal: &Registry::xdgOutputRemoved |
289 | }}, |
290 | {Registry::Interface::XdgShellStable, { |
291 | .maxVersion: 1, |
292 | QByteArrayLiteral("xdg_wm_base" ), |
293 | .interface: &xdg_wm_base_interface, |
294 | .announcedSignal: &Registry::xdgShellStableAnnounced, |
295 | .removedSignal: &Registry::xdgShellStableRemoved |
296 | }}, |
297 | {Registry::Interface::XdgDecorationUnstableV1, { |
298 | .maxVersion: 1, |
299 | QByteArrayLiteral("zxdg_decoration_manager_v1" ), |
300 | .interface: &zxdg_decoration_manager_v1_interface, |
301 | .announcedSignal: &Registry::xdgDecorationAnnounced, |
302 | .removedSignal: &Registry::xdgDecorationRemoved |
303 | }}, |
304 | {Registry::Interface::PlasmaActivationFeedback, { |
305 | .maxVersion: 1, |
306 | QByteArrayLiteral("org_kde_plasma_activation_feedback" ), |
307 | .interface: &org_kde_plasma_activation_feedback_interface, |
308 | .announcedSignal: &Registry::plasmaActivationFeedbackAnnounced, |
309 | .removedSignal: &Registry::plasmaActivationFeedbackRemoved |
310 | }}, |
311 | }; |
312 | // clang-format on |
313 | |
314 | static quint32 maxVersion(const Registry::Interface &interface) |
315 | { |
316 | auto it = s_interfaces.find(key: interface); |
317 | if (it != s_interfaces.end()) { |
318 | return it.value().maxVersion; |
319 | } |
320 | return 0; |
321 | } |
322 | } |
323 | |
324 | class Q_DECL_HIDDEN Registry::Private |
325 | { |
326 | public: |
327 | Private(Registry *q); |
328 | void setup(); |
329 | bool hasInterface(Interface interface) const; |
330 | AnnouncedInterface interface(Interface interface) const; |
331 | QList<AnnouncedInterface> interfaces(Interface interface) const; |
332 | Interface interfaceForName(quint32 name) const; |
333 | template<typename T> |
334 | T *bind(Interface interface, uint32_t name, uint32_t version) const; |
335 | template<class T, typename WL> |
336 | T *create(quint32 name, quint32 version, QObject *parent, WL *(Registry::*bindMethod)(uint32_t, uint32_t) const); |
337 | |
338 | WaylandPointer<wl_registry, wl_registry_destroy> registry; |
339 | static const struct wl_callback_listener s_callbackListener; |
340 | WaylandPointer<wl_callback, wl_callback_destroy> callback; |
341 | EventQueue *queue = nullptr; |
342 | |
343 | private: |
344 | void handleAnnounce(uint32_t name, const char *interface, uint32_t version); |
345 | void handleRemove(uint32_t name); |
346 | void handleGlobalSync(); |
347 | static void globalAnnounce(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version); |
348 | static void globalRemove(void *data, struct wl_registry *registry, uint32_t name); |
349 | static void globalSync(void *data, struct wl_callback *callback, uint32_t serial); |
350 | |
351 | Registry *q; |
352 | struct InterfaceData { |
353 | Interface interface; |
354 | uint32_t name; |
355 | uint32_t version; |
356 | }; |
357 | QList<InterfaceData> m_interfaces; |
358 | static const struct wl_registry_listener s_registryListener; |
359 | }; |
360 | |
361 | Registry::Private::Private(Registry *q) |
362 | : q(q) |
363 | { |
364 | } |
365 | |
366 | void Registry::Private::setup() |
367 | { |
368 | wl_registry_add_listener(wl_registry: registry, listener: &s_registryListener, data: this); |
369 | wl_callback_add_listener(wl_callback: callback, listener: &s_callbackListener, data: this); |
370 | } |
371 | |
372 | Registry::Registry(QObject *parent) |
373 | : QObject(parent) |
374 | , d(new Private(this)) |
375 | { |
376 | } |
377 | |
378 | Registry::~Registry() |
379 | { |
380 | release(); |
381 | } |
382 | |
383 | void Registry::release() |
384 | { |
385 | d->registry.release(); |
386 | d->callback.release(); |
387 | } |
388 | |
389 | void Registry::destroy() |
390 | { |
391 | Q_EMIT registryDestroyed(); |
392 | d->registry.destroy(); |
393 | d->callback.destroy(); |
394 | } |
395 | |
396 | void Registry::create(wl_display *display) |
397 | { |
398 | Q_ASSERT(display); |
399 | Q_ASSERT(!isValid()); |
400 | d->registry.setup(pointer: wl_display_get_registry(wl_display: display)); |
401 | d->callback.setup(pointer: wl_display_sync(wl_display: display)); |
402 | if (d->queue) { |
403 | d->queue->addProxy(proxy: d->registry); |
404 | d->queue->addProxy(proxy: d->callback); |
405 | } |
406 | } |
407 | |
408 | void Registry::create(ConnectionThread *connection) |
409 | { |
410 | create(display: connection->display()); |
411 | connect(sender: connection, signal: &ConnectionThread::connectionDied, context: this, slot: &Registry::destroy); |
412 | } |
413 | |
414 | void Registry::setup() |
415 | { |
416 | Q_ASSERT(isValid()); |
417 | d->setup(); |
418 | } |
419 | |
420 | void Registry::setEventQueue(EventQueue *queue) |
421 | { |
422 | d->queue = queue; |
423 | if (!queue) { |
424 | return; |
425 | } |
426 | if (d->registry) { |
427 | d->queue->addProxy(proxy: d->registry); |
428 | } |
429 | if (d->callback) { |
430 | d->queue->addProxy(proxy: d->callback); |
431 | } |
432 | } |
433 | |
434 | EventQueue *Registry::eventQueue() |
435 | { |
436 | return d->queue; |
437 | } |
438 | |
439 | #ifndef K_DOXYGEN |
440 | const struct wl_registry_listener Registry::Private::s_registryListener = {.global: globalAnnounce, .global_remove: globalRemove}; |
441 | |
442 | const struct wl_callback_listener Registry::Private::s_callbackListener = {.done: globalSync}; |
443 | #endif |
444 | |
445 | void Registry::Private::globalAnnounce(void *data, wl_registry *registry, uint32_t name, const char *interface, uint32_t version) |
446 | { |
447 | auto r = reinterpret_cast<Registry::Private *>(data); |
448 | Q_ASSERT(registry == r->registry); |
449 | r->handleAnnounce(name, interface, version); |
450 | } |
451 | |
452 | void Registry::Private::globalRemove(void *data, wl_registry *registry, uint32_t name) |
453 | { |
454 | auto r = reinterpret_cast<Registry::Private *>(data); |
455 | Q_ASSERT(registry == r->registry); |
456 | r->handleRemove(name); |
457 | } |
458 | |
459 | void Registry::Private::globalSync(void *data, wl_callback *callback, uint32_t serial) |
460 | { |
461 | Q_UNUSED(serial) |
462 | auto r = reinterpret_cast<Registry::Private *>(data); |
463 | Q_ASSERT(r->callback == callback); |
464 | r->handleGlobalSync(); |
465 | r->callback.release(); |
466 | } |
467 | |
468 | void Registry::Private::handleGlobalSync() |
469 | { |
470 | Q_EMIT q->interfacesAnnounced(); |
471 | } |
472 | |
473 | namespace |
474 | { |
475 | static Registry::Interface nameToInterface(const char *interface) |
476 | { |
477 | for (auto it = s_interfaces.constBegin(); it != s_interfaces.constEnd(); ++it) { |
478 | if (qstrcmp(str1: interface, str2: it.value().name) == 0) { |
479 | return it.key(); |
480 | } |
481 | } |
482 | return Registry::Interface::Unknown; |
483 | } |
484 | } |
485 | |
486 | void Registry::Private::handleAnnounce(uint32_t name, const char *interface, uint32_t version) |
487 | { |
488 | Interface i = nameToInterface(interface); |
489 | Q_EMIT q->interfaceAnnounced(interface: QByteArray(interface), name, version); |
490 | if (i == Interface::Unknown) { |
491 | qCDebug(KWAYLAND_CLIENT) << "Unknown interface announced: " << interface << "/" << name << "/" << version; |
492 | return; |
493 | } |
494 | qCDebug(KWAYLAND_CLIENT) << "Wayland Interface: " << interface << "/" << name << "/" << version; |
495 | m_interfaces.append(t: {.interface: i, .name: name, .version: version}); |
496 | auto it = s_interfaces.constFind(key: i); |
497 | if (it != s_interfaces.end()) { |
498 | Q_EMIT(q->*it.value().announcedSignal)(name, version); |
499 | } |
500 | } |
501 | |
502 | void Registry::Private::handleRemove(uint32_t name) |
503 | { |
504 | auto it = std::find_if(first: m_interfaces.begin(), last: m_interfaces.end(), pred: [name](const InterfaceData &data) { |
505 | return data.name == name; |
506 | }); |
507 | if (it != m_interfaces.end()) { |
508 | InterfaceData data = *(it); |
509 | m_interfaces.erase(pos: it); |
510 | auto sit = s_interfaces.find(key: data.interface); |
511 | if (sit != s_interfaces.end()) { |
512 | Q_EMIT(q->*sit.value().removedSignal)(data.name); |
513 | } |
514 | } |
515 | Q_EMIT q->interfaceRemoved(name); |
516 | } |
517 | |
518 | bool Registry::Private::hasInterface(Registry::Interface interface) const |
519 | { |
520 | auto it = std::find_if(first: m_interfaces.constBegin(), last: m_interfaces.constEnd(), pred: [interface](const InterfaceData &data) { |
521 | return data.interface == interface; |
522 | }); |
523 | return it != m_interfaces.constEnd(); |
524 | } |
525 | |
526 | QList<Registry::AnnouncedInterface> Registry::Private::interfaces(Interface interface) const |
527 | { |
528 | QList<Registry::AnnouncedInterface> retVal; |
529 | for (auto it = m_interfaces.constBegin(); it != m_interfaces.constEnd(); ++it) { |
530 | const auto &data = *it; |
531 | if (data.interface == interface) { |
532 | retVal << AnnouncedInterface{.name: data.name, .version: data.version}; |
533 | } |
534 | } |
535 | return retVal; |
536 | } |
537 | |
538 | Registry::AnnouncedInterface Registry::Private::interface(Interface interface) const |
539 | { |
540 | const auto all = interfaces(interface); |
541 | if (!all.isEmpty()) { |
542 | return all.last(); |
543 | } |
544 | return AnnouncedInterface{.name: 0, .version: 0}; |
545 | } |
546 | |
547 | Registry::Interface Registry::Private::interfaceForName(quint32 name) const |
548 | { |
549 | auto it = std::find_if(first: m_interfaces.constBegin(), last: m_interfaces.constEnd(), pred: [name](const InterfaceData &data) { |
550 | return data.name == name; |
551 | }); |
552 | if (it == m_interfaces.constEnd()) { |
553 | return Interface::Unknown; |
554 | } |
555 | return (*it).interface; |
556 | } |
557 | |
558 | bool Registry::hasInterface(Registry::Interface interface) const |
559 | { |
560 | return d->hasInterface(interface); |
561 | } |
562 | |
563 | QList<Registry::AnnouncedInterface> Registry::interfaces(Interface interface) const |
564 | { |
565 | return d->interfaces(interface); |
566 | } |
567 | |
568 | Registry::AnnouncedInterface Registry::interface(Interface interface) const |
569 | { |
570 | return d->interface(interface); |
571 | } |
572 | |
573 | // clang-format off |
574 | #define BIND2(__NAME__, __INAME__, __WL__) \ |
575 | __WL__ *Registry::bind##__NAME__(uint32_t name, uint32_t version) const \ |
576 | { \ |
577 | return d->bind<__WL__>(Interface::__INAME__, name, qMin(maxVersion(Interface::__INAME__), version)); \ |
578 | } |
579 | |
580 | #define BIND(__NAME__, __WL__) BIND2(__NAME__, __NAME__, __WL__) |
581 | // clang-format on |
582 | |
583 | BIND(Compositor, wl_compositor) |
584 | BIND(Output, wl_output) |
585 | BIND(Seat, wl_seat) |
586 | BIND(Shell, wl_shell) |
587 | BIND(Shm, wl_shm) |
588 | BIND(SubCompositor, wl_subcompositor) |
589 | BIND(DataDeviceManager, wl_data_device_manager) |
590 | BIND(PlasmaShell, org_kde_plasma_shell) |
591 | BIND(PlasmaActivationFeedback, org_kde_plasma_activation_feedback) |
592 | BIND(PlasmaVirtualDesktopManagement, org_kde_plasma_virtual_desktop_management) |
593 | BIND(PlasmaWindowManagement, org_kde_plasma_window_management) |
594 | BIND(FakeInput, org_kde_kwin_fake_input) |
595 | BIND(TextInputManagerUnstableV0, wl_text_input_manager) |
596 | BIND(TextInputManagerUnstableV2, zwp_text_input_manager_v2) |
597 | BIND(XdgShellUnstableV5, xdg_shell) |
598 | BIND(XdgShellUnstableV6, zxdg_shell_v6) |
599 | BIND(XdgShellStable, xdg_wm_base) |
600 | BIND(RelativePointerManagerUnstableV1, zwp_relative_pointer_manager_v1) |
601 | BIND(PointerGesturesUnstableV1, zwp_pointer_gestures_v1) |
602 | BIND(PointerConstraintsUnstableV1, zwp_pointer_constraints_v1) |
603 | BIND(XdgExporterUnstableV2, zxdg_exporter_v2) |
604 | BIND(XdgImporterUnstableV2, zxdg_importer_v2) |
605 | BIND(IdleInhibitManagerUnstableV1, zwp_idle_inhibit_manager_v1) |
606 | BIND2(ShadowManager, Shadow, org_kde_kwin_shadow_manager) |
607 | BIND2(BlurManager, Blur, org_kde_kwin_blur_manager) |
608 | BIND2(ContrastManager, Contrast, org_kde_kwin_contrast_manager) |
609 | BIND2(SlideManager, Slide, org_kde_kwin_slide_manager) |
610 | BIND2(DpmsManager, Dpms, org_kde_kwin_dpms_manager) |
611 | BIND2(AppMenuManager, AppMenu, org_kde_kwin_appmenu_manager) |
612 | BIND(XdgOutputUnstableV1, zxdg_output_manager_v1) |
613 | BIND(XdgDecorationUnstableV1, zxdg_decoration_manager_v1) |
614 | |
615 | #undef BIND |
616 | #undef BIND2 |
617 | |
618 | template<class T, typename WL> |
619 | T *Registry::Private::create(quint32 name, quint32 version, QObject *parent, WL *(Registry::*bindMethod)(uint32_t, uint32_t) const) |
620 | { |
621 | T *t = new T(parent); |
622 | t->setEventQueue(queue); |
623 | t->setup((q->*bindMethod)(name, version)); |
624 | QObject::connect(q, &Registry::interfaceRemoved, t, [t, name](quint32 removed) { |
625 | if (name == removed) { |
626 | Q_EMIT t->removed(); |
627 | } |
628 | }); |
629 | QObject::connect(q, &Registry::registryDestroyed, t, &T::destroy); |
630 | return t; |
631 | } |
632 | |
633 | // clang-format off |
634 | #define CREATE2(__NAME__, __BINDNAME__) \ |
635 | __NAME__ *Registry::create##__NAME__(quint32 name, quint32 version, QObject *parent) \ |
636 | { \ |
637 | return d->create<__NAME__>(name, version, parent, &Registry::bind##__BINDNAME__); \ |
638 | } |
639 | |
640 | #define CREATE(__NAME__) CREATE2(__NAME__, __NAME__) |
641 | // clang-format on |
642 | |
643 | CREATE(Compositor) |
644 | CREATE(Seat) |
645 | CREATE(Shell) |
646 | CREATE(SubCompositor) |
647 | CREATE(Output) |
648 | CREATE(DataDeviceManager) |
649 | CREATE(PlasmaShell) |
650 | CREATE(PlasmaActivationFeedback) |
651 | CREATE(PlasmaVirtualDesktopManagement) |
652 | CREATE(PlasmaWindowManagement) |
653 | CREATE(FakeInput) |
654 | CREATE(ShadowManager) |
655 | CREATE(BlurManager) |
656 | CREATE(ContrastManager) |
657 | CREATE(SlideManager) |
658 | CREATE(DpmsManager) |
659 | CREATE2(ShmPool, Shm) |
660 | CREATE(AppMenuManager) |
661 | |
662 | #undef CREATE |
663 | #undef CREATE2 |
664 | |
665 | XdgExporter *Registry::createXdgExporter(quint32 name, quint32 version, QObject *parent) |
666 | { |
667 | // only V1 supported for now |
668 | return d->create<XdgExporterUnstableV2>(name, version, parent, bindMethod: &Registry::bindXdgExporterUnstableV2); |
669 | } |
670 | |
671 | XdgImporter *Registry::createXdgImporter(quint32 name, quint32 version, QObject *parent) |
672 | { |
673 | // only V1 supported for now |
674 | return d->create<XdgImporterUnstableV2>(name, version, parent, bindMethod: &Registry::bindXdgImporterUnstableV2); |
675 | } |
676 | |
677 | TextInputManager *Registry::createTextInputManager(quint32 name, quint32 version, QObject *parent) |
678 | { |
679 | switch (d->interfaceForName(name)) { |
680 | case Interface::TextInputManagerUnstableV0: |
681 | return d->create<TextInputManagerUnstableV0>(name, version, parent, bindMethod: &Registry::bindTextInputManagerUnstableV0); |
682 | case Interface::TextInputManagerUnstableV2: |
683 | return d->create<TextInputManagerUnstableV2>(name, version, parent, bindMethod: &Registry::bindTextInputManagerUnstableV2); |
684 | default: |
685 | return nullptr; |
686 | } |
687 | } |
688 | |
689 | XdgShell *Registry::createXdgShell(quint32 name, quint32 version, QObject *parent) |
690 | { |
691 | switch (d->interfaceForName(name)) { |
692 | case Interface::XdgShellUnstableV5: |
693 | return d->create<XdgShellUnstableV5>(name, version, parent, bindMethod: &Registry::bindXdgShellUnstableV5); |
694 | case Interface::XdgShellUnstableV6: |
695 | return d->create<XdgShellUnstableV6>(name, version, parent, bindMethod: &Registry::bindXdgShellUnstableV6); |
696 | case Interface::XdgShellStable: |
697 | return d->create<XdgShellStable>(name, version, parent, bindMethod: &Registry::bindXdgShellStable); |
698 | default: |
699 | return nullptr; |
700 | } |
701 | } |
702 | |
703 | RelativePointerManager *Registry::createRelativePointerManager(quint32 name, quint32 version, QObject *parent) |
704 | { |
705 | switch (d->interfaceForName(name)) { |
706 | case Interface::RelativePointerManagerUnstableV1: |
707 | return d->create<RelativePointerManager>(name, version, parent, bindMethod: &Registry::bindRelativePointerManagerUnstableV1); |
708 | default: |
709 | return nullptr; |
710 | } |
711 | } |
712 | |
713 | PointerGestures *Registry::createPointerGestures(quint32 name, quint32 version, QObject *parent) |
714 | { |
715 | switch (d->interfaceForName(name)) { |
716 | case Interface::PointerGesturesUnstableV1: |
717 | return d->create<PointerGestures>(name, version, parent, bindMethod: &Registry::bindPointerGesturesUnstableV1); |
718 | default: |
719 | return nullptr; |
720 | } |
721 | } |
722 | |
723 | PointerConstraints *Registry::createPointerConstraints(quint32 name, quint32 version, QObject *parent) |
724 | { |
725 | switch (d->interfaceForName(name)) { |
726 | case Interface::PointerConstraintsUnstableV1: |
727 | return d->create<PointerConstraints>(name, version, parent, bindMethod: &Registry::bindPointerConstraintsUnstableV1); |
728 | default: |
729 | return nullptr; |
730 | } |
731 | } |
732 | |
733 | IdleInhibitManager *Registry::createIdleInhibitManager(quint32 name, quint32 version, QObject *parent) |
734 | { |
735 | switch (d->interfaceForName(name)) { |
736 | case Interface::IdleInhibitManagerUnstableV1: |
737 | return d->create<IdleInhibitManager>(name, version, parent, bindMethod: &Registry::bindIdleInhibitManagerUnstableV1); |
738 | default: |
739 | return nullptr; |
740 | } |
741 | } |
742 | |
743 | XdgOutputManager *Registry::createXdgOutputManager(quint32 name, quint32 version, QObject *parent) |
744 | { |
745 | switch (d->interfaceForName(name)) { |
746 | case Interface::XdgOutputUnstableV1: |
747 | return d->create<XdgOutputManager>(name, version, parent, bindMethod: &Registry::bindXdgOutputUnstableV1); |
748 | default: |
749 | return nullptr; |
750 | } |
751 | } |
752 | |
753 | XdgDecorationManager *Registry::createXdgDecorationManager(quint32 name, quint32 version, QObject *parent) |
754 | { |
755 | switch (d->interfaceForName(name)) { |
756 | case Interface::XdgDecorationUnstableV1: |
757 | return d->create<XdgDecorationManager>(name, version, parent, bindMethod: &Registry::bindXdgDecorationUnstableV1); |
758 | default: |
759 | return nullptr; |
760 | } |
761 | } |
762 | |
763 | namespace |
764 | { |
765 | static const wl_interface *wlInterface(Registry::Interface interface) |
766 | { |
767 | auto it = s_interfaces.find(key: interface); |
768 | if (it != s_interfaces.end()) { |
769 | return it.value().interface; |
770 | } |
771 | return nullptr; |
772 | } |
773 | } |
774 | |
775 | template<typename T> |
776 | T *Registry::Private::bind(Registry::Interface interface, uint32_t name, uint32_t version) const |
777 | { |
778 | auto it = std::find_if(m_interfaces.constBegin(), m_interfaces.constEnd(), [=](const InterfaceData &data) { |
779 | return data.interface == interface && data.name == name && data.version >= version; |
780 | }); |
781 | if (it == m_interfaces.constEnd()) { |
782 | qCDebug(KWAYLAND_CLIENT) << "Don't have interface " << int(interface) << "with name " << name << "and minimum version" << version; |
783 | return nullptr; |
784 | } |
785 | auto t = reinterpret_cast<T *>(wl_registry_bind(wl_registry: registry, name, interface: wlInterface(interface), version)); |
786 | if (queue) { |
787 | queue->addProxy(t); |
788 | } |
789 | return t; |
790 | } |
791 | |
792 | bool Registry::isValid() const |
793 | { |
794 | return d->registry.isValid(); |
795 | } |
796 | |
797 | wl_registry *Registry::registry() |
798 | { |
799 | return d->registry; |
800 | } |
801 | |
802 | Registry::operator wl_registry *() const |
803 | { |
804 | return d->registry; |
805 | } |
806 | |
807 | Registry::operator wl_registry *() |
808 | { |
809 | return d->registry; |
810 | } |
811 | |
812 | } |
813 | } |
814 | |
815 | #include "moc_registry.cpp" |
816 | |