| 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: 18, |
| 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 | if (i == Interface::Unknown) { |
| 490 | qCDebug(KWAYLAND_CLIENT) << "Unknown interface announced: " << interface << "/" << name << "/" << version; |
| 491 | } else { |
| 492 | qCDebug(KWAYLAND_CLIENT) << "Wayland Interface: " << interface << "/" << name << "/" << version; |
| 493 | m_interfaces.append(t: {.interface: i, .name: name, .version: version}); |
| 494 | auto it = s_interfaces.constFind(key: i); |
| 495 | if (it != s_interfaces.end()) { |
| 496 | Q_EMIT(q->*it.value().announcedSignal)(name, version); |
| 497 | } |
| 498 | } |
| 499 | Q_EMIT q->interfaceAnnounced(interface: QByteArray(interface), name, version); |
| 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 | |