File indexing completed on 2024-05-12 05:32:30

0001 /*
0002     SPDX-FileCopyrightText: 2019 Aleix Pol Gonzalez <aleixpol@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include "tablet_v2.h"
0008 #include "clientconnection.h"
0009 #include "display.h"
0010 #include "seat.h"
0011 #include "surface.h"
0012 #include "utils/resource.h"
0013 
0014 #include "qwayland-server-tablet-unstable-v2.h"
0015 
0016 #include <QHash>
0017 #include <QPointer>
0018 #include <ranges>
0019 
0020 namespace KWin
0021 {
0022 static int s_version = 1;
0023 
0024 class TabletV2InterfacePrivate : public QtWaylandServer::zwp_tablet_v2
0025 {
0026 public:
0027     TabletV2InterfacePrivate(TabletV2Interface *q, uint32_t vendorId, uint32_t productId, const QString &name, const QStringList &paths)
0028         : zwp_tablet_v2()
0029         , q(q)
0030         , m_vendorId(vendorId)
0031         , m_productId(productId)
0032         , m_name(name)
0033         , m_paths(paths)
0034     {
0035     }
0036 
0037     wl_resource *resourceForSurface(SurfaceInterface *surface) const
0038     {
0039         ClientConnection *client = surface->client();
0040         Resource *r = resourceMap().value(*client);
0041         return r ? r->handle : nullptr;
0042     }
0043 
0044     TabletV2Interface *const q;
0045     TabletPadV2Interface *m_pad = nullptr;
0046     const uint32_t m_vendorId;
0047     const uint32_t m_productId;
0048     const QString m_name;
0049     const QStringList m_paths;
0050 };
0051 
0052 TabletV2Interface::TabletV2Interface(uint32_t vendorId, uint32_t productId, const QString &name, const QStringList &paths, QObject *parent)
0053     : QObject(parent)
0054     , d(new TabletV2InterfacePrivate(this, vendorId, productId, name, paths))
0055 {
0056 }
0057 
0058 TabletV2Interface::~TabletV2Interface()
0059 {
0060     const auto tabletResources = d->resourceMap();
0061     for (TabletV2InterfacePrivate::Resource *resource : tabletResources) {
0062         d->send_removed(resource->handle);
0063     }
0064 }
0065 
0066 bool TabletV2Interface::isSurfaceSupported(SurfaceInterface *surface) const
0067 {
0068     return d->resourceForSurface(surface);
0069 }
0070 
0071 TabletPadV2Interface *TabletV2Interface::pad() const
0072 {
0073     return d->m_pad;
0074 }
0075 
0076 class TabletSurfaceCursorV2Private
0077 {
0078 public:
0079     TabletSurfaceCursorV2Private(TabletSurfaceCursorV2 *q)
0080         : q(q)
0081     {
0082     }
0083 
0084     void update(quint32 serial, SurfaceInterface *surface, const QPoint &hotspot)
0085     {
0086         const bool diff = m_serial != serial || m_surface != surface || m_hotspot != hotspot;
0087         if (diff) {
0088             m_serial = serial;
0089             m_surface = surface;
0090             m_hotspot = hotspot;
0091 
0092             Q_EMIT q->changed();
0093         }
0094     }
0095 
0096     TabletSurfaceCursorV2 *const q;
0097 
0098     quint32 m_serial = 0;
0099     QPointer<SurfaceInterface> m_surface;
0100     QPoint m_hotspot;
0101 };
0102 
0103 TabletSurfaceCursorV2::TabletSurfaceCursorV2()
0104     : QObject()
0105     , d(new TabletSurfaceCursorV2Private(this))
0106 {
0107 }
0108 
0109 TabletSurfaceCursorV2::~TabletSurfaceCursorV2() = default;
0110 
0111 QPoint TabletSurfaceCursorV2::hotspot() const
0112 {
0113     return d->m_hotspot;
0114 }
0115 
0116 quint32 TabletSurfaceCursorV2::enteredSerial() const
0117 {
0118     return d->m_serial;
0119 }
0120 
0121 SurfaceInterface *TabletSurfaceCursorV2::surface() const
0122 {
0123     return d->m_surface;
0124 }
0125 
0126 class TabletToolV2InterfacePrivate : public QtWaylandServer::zwp_tablet_tool_v2
0127 {
0128 public:
0129     TabletToolV2InterfacePrivate(TabletToolV2Interface *q,
0130                                  Display *display,
0131                                  TabletToolV2Interface::Type type,
0132                                  uint32_t hsh,
0133                                  uint32_t hsl,
0134                                  uint32_t hih,
0135                                  uint32_t hil,
0136                                  const QList<TabletToolV2Interface::Capability> &capabilities)
0137         : zwp_tablet_tool_v2()
0138         , m_display(display)
0139         , m_type(type)
0140         , m_hardwareSerialHigh(hsh)
0141         , m_hardwareSerialLow(hsl)
0142         , m_hardwareIdHigh(hih)
0143         , m_hardwareIdLow(hil)
0144         , m_capabilities(capabilities)
0145         , q(q)
0146     {
0147     }
0148 
0149     std::ranges::subrange<QMultiMap<struct ::wl_client *, Resource *>::const_iterator> targetResources() const
0150     {
0151         if (!m_surface)
0152             return {};
0153 
0154         ClientConnection *client = m_surface->client();
0155         const auto [start, end] = resourceMap().equal_range(*client);
0156         return std::ranges::subrange(start, end);
0157     }
0158 
0159     quint64 hardwareId() const
0160     {
0161         return quint64(quint64(m_hardwareIdHigh) << 32) + m_hardwareIdLow;
0162     }
0163     quint64 hardwareSerial() const
0164     {
0165         return quint64(quint64(m_hardwareSerialHigh) << 32) + m_hardwareSerialLow;
0166     }
0167 
0168     void zwp_tablet_tool_v2_bind_resource(QtWaylandServer::zwp_tablet_tool_v2::Resource *resource) override
0169     {
0170         TabletSurfaceCursorV2 *&c = m_cursors[resource->client()];
0171         if (!c)
0172             c = new TabletSurfaceCursorV2;
0173     }
0174 
0175     void zwp_tablet_tool_v2_set_cursor(Resource *resource, uint32_t serial, struct ::wl_resource *_surface, int32_t hotspot_x, int32_t hotspot_y) override
0176     {
0177         SurfaceInterface *surface = SurfaceInterface::get(_surface);
0178         if (surface) {
0179             static SurfaceRole cursorRole(QByteArrayLiteral("tablet_cursor_v2"));
0180             if (const SurfaceRole *role = surface->role()) {
0181                 if (role != &cursorRole) {
0182                     wl_resource_post_error(resource->handle, 0,
0183                                            "the wl_surface already has a role assigned %s", role->name().constData());
0184                     return;
0185                 }
0186             } else {
0187                 surface->setRole(&cursorRole);
0188             }
0189         }
0190 
0191         TabletSurfaceCursorV2 *c = m_cursors[resource->client()];
0192         c->d->update(serial, surface, {hotspot_x, hotspot_y});
0193         const auto resources = targetResources();
0194         if (std::any_of(resources.begin(), resources.end(), [resource](const Resource *res) {
0195                 return res->handle == resource->handle;
0196             })) {
0197             Q_EMIT q->cursorChanged(c);
0198         }
0199     }
0200 
0201     void zwp_tablet_tool_v2_destroy_resource(Resource *resource) override
0202     {
0203         if (!resourceMap().contains(resource->client())) {
0204             delete m_cursors.take(resource->client());
0205         }
0206         if (m_removed && resourceMap().isEmpty()) {
0207             delete q;
0208         }
0209     }
0210 
0211     void zwp_tablet_tool_v2_destroy(Resource *resource) override
0212     {
0213         wl_resource_destroy(resource->handle);
0214     }
0215 
0216     Display *const m_display;
0217     quint32 m_proximitySerial = 0;
0218     std::optional<quint32> m_downSerial;
0219     bool m_cleanup = false;
0220     bool m_removed = false;
0221     QPointer<SurfaceInterface> m_surface;
0222     QPointer<TabletV2Interface> m_lastTablet;
0223     const uint32_t m_type;
0224     const uint32_t m_hardwareSerialHigh, m_hardwareSerialLow;
0225     const uint32_t m_hardwareIdHigh, m_hardwareIdLow;
0226     const QList<TabletToolV2Interface::Capability> m_capabilities;
0227     QHash<wl_client *, TabletSurfaceCursorV2 *> m_cursors;
0228     TabletToolV2Interface *const q;
0229 };
0230 
0231 TabletToolV2Interface::TabletToolV2Interface(Display *display,
0232                                              Type type,
0233                                              uint32_t hsh,
0234                                              uint32_t hsl,
0235                                              uint32_t hih,
0236                                              uint32_t hil,
0237                                              const QList<Capability> &capabilities)
0238     : d(new TabletToolV2InterfacePrivate(this, display, type, hsh, hsl, hih, hil, capabilities))
0239 {
0240 }
0241 
0242 TabletToolV2Interface::~TabletToolV2Interface()
0243 {
0244     const auto toolResources = d->resourceMap();
0245     for (TabletToolV2InterfacePrivate::Resource *resource : toolResources) {
0246         d->send_removed(resource->handle);
0247     }
0248 }
0249 
0250 TabletToolV2Interface *TabletToolV2Interface::get(wl_resource *resource)
0251 {
0252     if (TabletToolV2InterfacePrivate *tabletToolPrivate = resource_cast<TabletToolV2InterfacePrivate *>(resource)) {
0253         return tabletToolPrivate->q;
0254     }
0255     return nullptr;
0256 }
0257 
0258 bool TabletToolV2Interface::hasCapability(Capability capability) const
0259 {
0260     return d->m_capabilities.contains(capability);
0261 }
0262 
0263 SurfaceInterface *TabletToolV2Interface::currentSurface() const
0264 {
0265     return d->m_surface;
0266 }
0267 
0268 void TabletToolV2Interface::setCurrentSurface(SurfaceInterface *surface)
0269 {
0270     if (d->m_surface == surface)
0271         return;
0272 
0273     TabletV2Interface *const lastTablet = d->m_lastTablet;
0274     if (d->m_surface && d->resourceMap().contains(*d->m_surface->client())) {
0275         sendProximityOut();
0276         sendFrame(0);
0277     }
0278 
0279     d->m_surface = surface;
0280 
0281     if (lastTablet && lastTablet->d->resourceForSurface(surface)) {
0282         sendProximityIn(lastTablet);
0283     } else {
0284         d->m_lastTablet = lastTablet;
0285     }
0286 
0287     if (surface != nullptr) {
0288         if (auto *const cursor = d->m_cursors.value(*surface->client())) {
0289             Q_EMIT cursorChanged(cursor);
0290         }
0291     }
0292 }
0293 
0294 quint32 TabletToolV2Interface::proximitySerial() const
0295 {
0296     return d->m_proximitySerial;
0297 }
0298 
0299 std::optional<quint32> TabletToolV2Interface::downSerial() const
0300 {
0301     return d->m_downSerial;
0302 }
0303 
0304 bool TabletToolV2Interface::isClientSupported() const
0305 {
0306     return d->m_surface && !d->targetResources().empty();
0307 }
0308 
0309 void TabletToolV2Interface::sendButton(uint32_t button, bool pressed)
0310 {
0311     const auto serial = d->m_display->nextSerial();
0312     for (auto *resource : d->targetResources()) {
0313         d->send_button(resource->handle,
0314                        serial,
0315                        button,
0316                        pressed ? QtWaylandServer::zwp_tablet_tool_v2::button_state_pressed : QtWaylandServer::zwp_tablet_tool_v2::button_state_released);
0317     }
0318 }
0319 
0320 void TabletToolV2Interface::sendMotion(const QPointF &pos)
0321 {
0322     const QPointF surfacePos = d->m_surface->toSurfaceLocal(pos);
0323     for (auto *resource : d->targetResources()) {
0324         d->send_motion(resource->handle, wl_fixed_from_double(surfacePos.x()), wl_fixed_from_double(surfacePos.y()));
0325     }
0326 }
0327 
0328 void TabletToolV2Interface::sendDistance(uint32_t distance)
0329 {
0330     for (auto *resource : d->targetResources()) {
0331         d->send_distance(resource->handle, distance);
0332     }
0333 }
0334 
0335 void TabletToolV2Interface::sendFrame(uint32_t time)
0336 {
0337     for (auto *resource : d->targetResources()) {
0338         d->send_frame(resource->handle, time);
0339     }
0340 
0341     if (d->m_cleanup) {
0342         d->m_surface = nullptr;
0343         d->m_lastTablet = nullptr;
0344         d->m_cleanup = false;
0345     }
0346 }
0347 
0348 void TabletToolV2Interface::sendPressure(uint32_t pressure)
0349 {
0350     for (auto *resource : d->targetResources()) {
0351         d->send_pressure(resource->handle, pressure);
0352     }
0353 }
0354 
0355 void TabletToolV2Interface::sendRotation(qreal rotation)
0356 {
0357     for (auto *resource : d->targetResources()) {
0358         d->send_rotation(resource->handle, wl_fixed_from_double(rotation));
0359     }
0360 }
0361 
0362 void TabletToolV2Interface::sendSlider(int32_t position)
0363 {
0364     for (auto *resource : d->targetResources()) {
0365         d->send_slider(resource->handle, position);
0366     }
0367 }
0368 
0369 void TabletToolV2Interface::sendTilt(qreal degreesX, qreal degreesY)
0370 {
0371     for (auto *resource : d->targetResources()) {
0372         d->send_tilt(resource->handle, wl_fixed_from_double(degreesX), wl_fixed_from_double(degreesY));
0373     }
0374 }
0375 
0376 void TabletToolV2Interface::sendWheel(int32_t degrees, int32_t clicks)
0377 {
0378     for (auto *resource : d->targetResources()) {
0379         d->send_wheel(resource->handle, degrees, clicks);
0380     }
0381 }
0382 
0383 void TabletToolV2Interface::sendProximityIn(TabletV2Interface *tablet)
0384 {
0385     wl_resource *tabletResource = tablet->d->resourceForSurface(d->m_surface);
0386     const auto serial = d->m_display->nextSerial();
0387     for (auto *resource : d->targetResources()) {
0388         d->send_proximity_in(resource->handle, serial, tabletResource, d->m_surface->resource());
0389     }
0390     d->m_proximitySerial = serial;
0391     d->m_lastTablet = tablet;
0392 }
0393 
0394 void TabletToolV2Interface::sendProximityOut()
0395 {
0396     for (auto *resource : d->targetResources()) {
0397         d->send_proximity_out(resource->handle);
0398     }
0399     d->m_cleanup = true;
0400 }
0401 
0402 void TabletToolV2Interface::sendDown()
0403 {
0404     const auto serial = d->m_display->nextSerial();
0405     for (auto *resource : d->targetResources()) {
0406         d->send_down(resource->handle, serial);
0407     }
0408     d->m_downSerial = serial;
0409 }
0410 
0411 void TabletToolV2Interface::sendUp()
0412 {
0413     for (auto *resource : d->targetResources()) {
0414         d->send_up(resource->handle);
0415     }
0416     d->m_downSerial.reset();
0417 }
0418 
0419 class TabletPadRingV2InterfacePrivate : public QtWaylandServer::zwp_tablet_pad_ring_v2
0420 {
0421 public:
0422     TabletPadRingV2InterfacePrivate(TabletPadRingV2Interface *q)
0423         : zwp_tablet_pad_ring_v2()
0424         , q(q)
0425     {
0426     }
0427 
0428     std::ranges::subrange<QMultiMap<struct ::wl_client *, Resource *>::const_iterator> resourcesForSurface(SurfaceInterface *surface) const
0429     {
0430         ClientConnection *client = surface->client();
0431         const auto [start, end] = resourceMap().equal_range(*client);
0432         return std::ranges::subrange(start, end);
0433     }
0434 
0435     void zwp_tablet_pad_ring_v2_destroy(Resource *resource) override
0436     {
0437         wl_resource_destroy(resource->handle);
0438     }
0439     TabletPadRingV2Interface *const q;
0440     TabletPadV2Interface *m_pad;
0441 };
0442 
0443 TabletPadRingV2Interface::TabletPadRingV2Interface(TabletPadV2Interface *parent)
0444     : QObject(parent)
0445     , d(new TabletPadRingV2InterfacePrivate(this))
0446 {
0447     d->m_pad = parent;
0448 }
0449 
0450 TabletPadRingV2Interface::~TabletPadRingV2Interface() = default;
0451 
0452 void TabletPadRingV2Interface::sendAngle(qreal angle)
0453 {
0454     for (auto *resource : d->resourcesForSurface(d->m_pad->currentSurface())) {
0455         d->send_angle(resource->handle, wl_fixed_from_double(angle));
0456     }
0457 }
0458 
0459 void TabletPadRingV2Interface::sendFrame(quint32 time)
0460 {
0461     for (auto *resource : d->resourcesForSurface(d->m_pad->currentSurface())) {
0462         d->send_frame(resource->handle, time);
0463     }
0464 }
0465 
0466 void TabletPadRingV2Interface::sendSource(Source source)
0467 {
0468     for (auto *resource : d->resourcesForSurface(d->m_pad->currentSurface())) {
0469         d->send_source(resource->handle, source);
0470     }
0471 }
0472 
0473 void TabletPadRingV2Interface::sendStop()
0474 {
0475     for (auto *resource : d->resourcesForSurface(d->m_pad->currentSurface())) {
0476         d->send_stop(resource->handle);
0477     }
0478 }
0479 
0480 class TabletPadStripV2InterfacePrivate : public QtWaylandServer::zwp_tablet_pad_strip_v2
0481 {
0482 public:
0483     TabletPadStripV2InterfacePrivate(TabletPadStripV2Interface *q)
0484         : zwp_tablet_pad_strip_v2()
0485         , q(q)
0486     {
0487     }
0488 
0489     std::ranges::subrange<QMultiMap<struct ::wl_client *, Resource *>::const_iterator> resourcesForSurface(SurfaceInterface *surface) const
0490     {
0491         ClientConnection *client = surface->client();
0492         const auto [start, end] = resourceMap().equal_range(*client);
0493         return std::ranges::subrange(start, end);
0494     }
0495 
0496     void zwp_tablet_pad_strip_v2_destroy(Resource *resource) override
0497     {
0498         wl_resource_destroy(resource->handle);
0499     }
0500     TabletPadV2Interface *m_pad = nullptr;
0501     TabletPadStripV2Interface *const q;
0502 };
0503 
0504 TabletPadStripV2Interface::TabletPadStripV2Interface(TabletPadV2Interface *parent)
0505     : QObject(parent)
0506     , d(new TabletPadStripV2InterfacePrivate(this))
0507 {
0508     d->m_pad = parent;
0509 }
0510 
0511 TabletPadStripV2Interface::~TabletPadStripV2Interface() = default;
0512 
0513 void TabletPadStripV2Interface::sendFrame(quint32 time)
0514 {
0515     for (auto *resource : d->resourcesForSurface(d->m_pad->currentSurface())) {
0516         d->send_frame(resource->handle, time);
0517     }
0518 }
0519 
0520 void TabletPadStripV2Interface::sendPosition(quint32 position)
0521 {
0522     for (auto *resource : d->resourcesForSurface(d->m_pad->currentSurface())) {
0523         d->send_position(resource->handle, position);
0524     }
0525 }
0526 
0527 void TabletPadStripV2Interface::sendSource(Source source)
0528 {
0529     for (auto *resource : d->resourcesForSurface(d->m_pad->currentSurface())) {
0530         d->send_source(resource->handle, source);
0531     }
0532 }
0533 
0534 void TabletPadStripV2Interface::sendStop()
0535 {
0536     for (auto *resource : d->resourcesForSurface(d->m_pad->currentSurface())) {
0537         d->send_stop(resource->handle);
0538     }
0539 }
0540 
0541 class TabletPadGroupV2InterfacePrivate : public QtWaylandServer::zwp_tablet_pad_group_v2
0542 {
0543 public:
0544     TabletPadGroupV2InterfacePrivate(quint32 currentMode, TabletPadGroupV2Interface *q)
0545         : zwp_tablet_pad_group_v2()
0546         , q(q)
0547         , m_currentMode(currentMode)
0548     {
0549     }
0550 
0551     std::ranges::subrange<QMultiMap<struct ::wl_client *, Resource *>::const_iterator> resourcesForSurface(SurfaceInterface *surface) const
0552     {
0553         ClientConnection *client = surface->client();
0554         const auto [start, end] = resourceMap().equal_range(*client);
0555         return std::ranges::subrange(start, end);
0556     }
0557 
0558     void zwp_tablet_pad_group_v2_destroy(Resource *resource) override
0559     {
0560         wl_resource_destroy(resource->handle);
0561     }
0562 
0563     TabletPadGroupV2Interface *const q;
0564     TabletPadV2Interface *m_pad = nullptr;
0565     quint32 m_currentMode;
0566 };
0567 
0568 TabletPadGroupV2Interface::TabletPadGroupV2Interface(quint32 currentMode, TabletPadV2Interface *parent)
0569     : QObject(parent)
0570     , d(new TabletPadGroupV2InterfacePrivate(currentMode, this))
0571 {
0572     d->m_pad = parent;
0573 }
0574 
0575 TabletPadGroupV2Interface::~TabletPadGroupV2Interface() = default;
0576 
0577 void TabletPadGroupV2Interface::sendModeSwitch(quint32 time, quint32 serial, quint32 mode)
0578 {
0579     d->m_currentMode = mode;
0580     for (auto *resource : d->resourcesForSurface(d->m_pad->currentSurface())) {
0581         d->send_mode_switch(resource->handle, time, serial, mode);
0582     }
0583 }
0584 
0585 class TabletPadV2InterfacePrivate : public QtWaylandServer::zwp_tablet_pad_v2
0586 {
0587 public:
0588     TabletPadV2InterfacePrivate(const QString &path,
0589                                 quint32 buttons,
0590                                 quint32 rings,
0591                                 quint32 strips,
0592                                 quint32 modes,
0593                                 quint32 currentMode,
0594                                 Display *display,
0595                                 TabletPadV2Interface *q)
0596         : zwp_tablet_pad_v2()
0597         , q(q)
0598         , m_path(path)
0599         , m_buttons(buttons)
0600         , m_modes(modes)
0601         , m_padGroup(new TabletPadGroupV2Interface(currentMode, q))
0602         , m_display(display)
0603     {
0604         for (uint i = 0; i < buttons; ++i) {
0605             m_buttons[i] = i;
0606         }
0607 
0608         m_rings.reserve(rings);
0609         for (quint32 i = 0; i < rings; ++i) {
0610             m_rings += new TabletPadRingV2Interface(q);
0611         }
0612 
0613         m_strips.reserve(strips);
0614         for (quint32 i = 0; i < strips; ++i) {
0615             m_strips += new TabletPadStripV2Interface(q);
0616         }
0617     }
0618 
0619     ~TabletPadV2InterfacePrivate() override
0620     {
0621         qDeleteAll(m_rings);
0622         qDeleteAll(m_strips);
0623     }
0624 
0625     void zwp_tablet_pad_v2_destroy(Resource *resource) override
0626     {
0627         wl_resource_destroy(resource->handle);
0628     }
0629 
0630     void zwp_tablet_pad_v2_set_feedback(Resource *resource, quint32 button, const QString &description, quint32 serial) override
0631     {
0632         Q_EMIT q->feedback(m_display->getConnection(resource->client()), button, description, serial);
0633     }
0634 
0635     std::ranges::subrange<QMultiMap<struct ::wl_client *, Resource *>::const_iterator> resourcesForSurface(SurfaceInterface *surface) const
0636     {
0637         ClientConnection *client = surface->client();
0638         const auto [start, end] = resourceMap().equal_range(*client);
0639         return std::ranges::subrange(start, end);
0640     }
0641 
0642     TabletPadV2Interface *const q;
0643 
0644     const QString m_path;
0645     QList<quint32> m_buttons;
0646     const int m_modes;
0647 
0648     QList<TabletPadRingV2Interface *> m_rings;
0649     QList<TabletPadStripV2Interface *> m_strips;
0650     TabletPadGroupV2Interface *const m_padGroup;
0651     TabletSeatV2Interface *m_seat = nullptr;
0652     QPointer<SurfaceInterface> m_currentSurface;
0653     Display *const m_display;
0654 };
0655 
0656 TabletPadV2Interface::TabletPadV2Interface(const QString &path,
0657                                            quint32 buttons,
0658                                            quint32 rings,
0659                                            quint32 strips,
0660                                            quint32 modes,
0661                                            quint32 currentMode,
0662                                            Display *display,
0663                                            TabletSeatV2Interface *parent)
0664     : QObject(parent)
0665     , d(new TabletPadV2InterfacePrivate(path, buttons, rings, strips, modes, currentMode, display, this))
0666 {
0667     d->m_seat = parent;
0668 }
0669 
0670 TabletPadV2Interface::~TabletPadV2Interface()
0671 {
0672     const auto tabletPadResources = d->resourceMap();
0673     for (TabletPadV2InterfacePrivate::Resource *resource : tabletPadResources) {
0674         d->send_removed(resource->handle);
0675     }
0676 }
0677 
0678 void TabletPadV2Interface::sendButton(std::chrono::microseconds time, quint32 button, bool pressed)
0679 {
0680     const auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(time).count();
0681     for (auto *resource : d->resourcesForSurface(currentSurface())) {
0682         d->send_button(resource->handle, milliseconds, button, pressed);
0683     }
0684 }
0685 
0686 TabletPadRingV2Interface *TabletPadV2Interface::ring(uint at) const
0687 {
0688     return d->m_rings[at];
0689 }
0690 
0691 TabletPadStripV2Interface *TabletPadV2Interface::strip(uint at) const
0692 {
0693     return d->m_strips[at];
0694 }
0695 
0696 void TabletPadV2Interface::setCurrentSurface(SurfaceInterface *surface, TabletV2Interface *tablet)
0697 {
0698     if (surface == d->m_currentSurface) {
0699         return;
0700     }
0701 
0702     if (d->m_currentSurface) {
0703         auto serial = d->m_display->nextSerial();
0704         for (auto *resource : d->resourcesForSurface(d->m_currentSurface)) {
0705             d->send_leave(resource->handle, serial, d->m_currentSurface->resource());
0706         }
0707     }
0708 
0709     d->m_currentSurface = surface;
0710     if (surface) {
0711         wl_resource *tabletResource = tablet->d->resourceForSurface(surface);
0712 
0713         auto serial = d->m_display->nextSerial();
0714         for (auto *resource : d->resourcesForSurface(surface)) {
0715             d->send_enter(resource->handle, serial, tabletResource, surface->resource());
0716         }
0717         d->m_padGroup->sendModeSwitch(0, d->m_display->nextSerial(), d->m_padGroup->d->m_currentMode);
0718     }
0719 }
0720 
0721 SurfaceInterface *TabletPadV2Interface::currentSurface() const
0722 {
0723     return d->m_currentSurface;
0724 }
0725 
0726 class TabletSeatV2InterfacePrivate : public QtWaylandServer::zwp_tablet_seat_v2
0727 {
0728 public:
0729     TabletSeatV2InterfacePrivate(Display *display, TabletSeatV2Interface *q)
0730         : zwp_tablet_seat_v2()
0731         , q(q)
0732         , m_display(display)
0733     {
0734     }
0735 
0736     void zwp_tablet_seat_v2_bind_resource(Resource *resource) override
0737     {
0738         for (auto tablet : std::as_const(m_tablets)) {
0739             sendTabletAdded(resource, tablet);
0740         }
0741 
0742         for (auto pad : std::as_const(m_pads)) {
0743             sendPadAdded(resource, pad);
0744         }
0745 
0746         for (const auto &tools : std::as_const(m_tools)) {
0747             for (auto *tool : tools) {
0748                 sendToolAdded(resource, tool);
0749             }
0750         }
0751     }
0752 
0753     void zwp_tablet_seat_v2_destroy(Resource *resource) override
0754     {
0755         wl_resource_destroy(resource->handle);
0756     }
0757 
0758     void sendToolAdded(Resource *resource, TabletToolV2Interface *tool)
0759     {
0760         wl_resource *toolResource = tool->d->add(resource->client(), resource->version())->handle;
0761         send_tool_added(resource->handle, toolResource);
0762 
0763         tool->d->send_type(toolResource, tool->d->m_type);
0764         tool->d->send_hardware_serial(toolResource, tool->d->m_hardwareSerialHigh, tool->d->m_hardwareSerialLow);
0765         tool->d->send_hardware_id_wacom(toolResource, tool->d->m_hardwareIdHigh, tool->d->m_hardwareIdLow);
0766         for (uint32_t cap : std::as_const(tool->d->m_capabilities)) {
0767             tool->d->send_capability(toolResource, cap);
0768         }
0769         tool->d->send_done(toolResource);
0770     }
0771     void sendTabletAdded(Resource *resource, TabletV2Interface *tablet)
0772     {
0773         wl_resource *tabletResource = tablet->d->add(resource->client(), resource->version())->handle;
0774         send_tablet_added(resource->handle, tabletResource);
0775 
0776         tablet->d->send_name(tabletResource, tablet->d->m_name);
0777         if (tablet->d->m_vendorId && tablet->d->m_productId) {
0778             tablet->d->send_id(tabletResource, tablet->d->m_vendorId, tablet->d->m_productId);
0779         }
0780         for (const QString &path : std::as_const(tablet->d->m_paths)) {
0781             tablet->d->send_path(tabletResource, path);
0782         }
0783         tablet->d->send_done(tabletResource);
0784     }
0785 
0786     void sendPadAdded(Resource *resource, TabletPadV2Interface *pad)
0787     {
0788         wl_resource *tabletResource = pad->d->add(resource->client(), resource->version())->handle;
0789         send_pad_added(resource->handle, tabletResource);
0790 
0791         pad->d->send_buttons(tabletResource, pad->d->m_buttons.size());
0792         pad->d->send_path(tabletResource, pad->d->m_path);
0793 
0794         auto groupResource = pad->d->m_padGroup->d->add(resource->client(), resource->version());
0795         pad->d->send_group(tabletResource, groupResource->handle);
0796         pad->d->m_padGroup->d->send_modes(groupResource->handle, pad->d->m_modes);
0797 
0798         pad->d->m_padGroup->d->send_buttons(
0799             groupResource->handle,
0800             QByteArray::fromRawData(reinterpret_cast<const char *>(pad->d->m_buttons.data()), pad->d->m_buttons.size() * sizeof(quint32)));
0801 
0802         for (auto ring : std::as_const(pad->d->m_rings)) {
0803             auto ringResource = ring->d->add(resource->client(), resource->version());
0804             pad->d->m_padGroup->d->send_ring(groupResource->handle, ringResource->handle);
0805         }
0806 
0807         for (auto strip : std::as_const(pad->d->m_strips)) {
0808             auto stripResource = strip->d->add(resource->client(), resource->version());
0809             pad->d->m_padGroup->d->send_strip(groupResource->handle, stripResource->handle);
0810         }
0811         pad->d->m_padGroup->d->send_done(groupResource->handle);
0812         pad->d->send_done(tabletResource);
0813     }
0814 
0815     TabletSeatV2Interface *const q;
0816     QHash<QString, QList<TabletToolV2Interface *>> m_tools;
0817     QHash<QString, TabletV2Interface *> m_tablets;
0818     QHash<QString, TabletPadV2Interface *> m_pads;
0819     Display *const m_display;
0820 };
0821 
0822 TabletSeatV2Interface::TabletSeatV2Interface(Display *display, QObject *parent)
0823     : QObject(parent)
0824     , d(new TabletSeatV2InterfacePrivate(display, this))
0825 {
0826 }
0827 
0828 TabletSeatV2Interface::~TabletSeatV2Interface() = default;
0829 
0830 TabletToolV2Interface *TabletSeatV2Interface::addTool(TabletToolV2Interface::Type type,
0831                                                       quint64 hardwareSerial,
0832                                                       quint64 hardwareId,
0833                                                       const QList<TabletToolV2Interface::Capability> &capabilities,
0834                                                       const QString &deviceSysName)
0835 {
0836     constexpr auto MAX_UINT_32 = std::numeric_limits<quint32>::max();
0837     auto tool = new TabletToolV2Interface(d->m_display,
0838                                           type,
0839                                           hardwareSerial >> 32,
0840                                           hardwareSerial & MAX_UINT_32,
0841                                           hardwareId >> 32,
0842                                           hardwareId & MAX_UINT_32,
0843                                           capabilities);
0844     for (QtWaylandServer::zwp_tablet_seat_v2::Resource *resource : d->resourceMap()) {
0845         d->sendToolAdded(resource, tool);
0846     }
0847 
0848     d->m_tools[deviceSysName].append(tool);
0849     return tool;
0850 }
0851 
0852 TabletV2Interface *
0853 TabletSeatV2Interface::addTablet(uint32_t vendorId, uint32_t productId, const QString &sysname, const QString &name, const QStringList &paths)
0854 {
0855     Q_ASSERT(!d->m_tablets.contains(sysname));
0856 
0857     auto iface = new TabletV2Interface(vendorId, productId, name, paths, this);
0858 
0859     for (QtWaylandServer::zwp_tablet_seat_v2::Resource *r : d->resourceMap()) {
0860         d->sendTabletAdded(r, iface);
0861     }
0862 
0863     d->m_tablets[sysname] = iface;
0864     return iface;
0865 }
0866 
0867 TabletPadV2Interface *TabletSeatV2Interface::addTabletPad(const QString &sysname,
0868                                                           const QString &name,
0869                                                           const QStringList &paths,
0870                                                           quint32 buttons,
0871                                                           quint32 rings,
0872                                                           quint32 strips,
0873                                                           quint32 modes,
0874                                                           quint32 currentMode,
0875                                                           TabletV2Interface *tablet)
0876 {
0877     auto iface = new TabletPadV2Interface(paths.at(0), buttons, rings, strips, modes, currentMode, d->m_display, this);
0878     iface->d->m_seat = this;
0879     for (auto r : d->resourceMap()) {
0880         d->sendPadAdded(r, iface);
0881     }
0882 
0883     tablet->d->m_pad = iface;
0884 
0885     d->m_pads[sysname] = iface;
0886     return iface;
0887 }
0888 
0889 void TabletSeatV2Interface::removeDevice(const QString &sysname)
0890 {
0891     delete d->m_tablets.take(sysname);
0892     delete d->m_pads.take(sysname);
0893 
0894     qDeleteAll(d->m_tools.take(sysname));
0895 }
0896 
0897 TabletToolV2Interface *TabletSeatV2Interface::toolByHardwareId(quint64 hardwareId) const
0898 {
0899     for (const auto &tools : std::as_const(d->m_tools)) {
0900         for (TabletToolV2Interface *tool : tools) {
0901             if (tool->d->hardwareId() == hardwareId) {
0902                 return tool;
0903             }
0904         }
0905     }
0906     return nullptr;
0907 }
0908 
0909 TabletToolV2Interface *TabletSeatV2Interface::toolByHardwareSerial(quint64 hardwareSerial, TabletToolV2Interface::Type type) const
0910 {
0911     for (const auto &tools : std::as_const(d->m_tools)) {
0912         for (TabletToolV2Interface *tool : tools) {
0913             if (tool->d->hardwareSerial() == hardwareSerial && tool->d->m_type == type) {
0914                 return tool;
0915             }
0916         }
0917     }
0918     return nullptr;
0919 }
0920 
0921 TabletPadV2Interface *TabletSeatV2Interface::padByName(const QString &name) const
0922 {
0923     Q_ASSERT(d->m_pads.contains(name));
0924     return d->m_pads.value(name);
0925 }
0926 
0927 class TabletManagerV2InterfacePrivate : public QtWaylandServer::zwp_tablet_manager_v2
0928 {
0929 public:
0930     TabletManagerV2InterfacePrivate(Display *display, TabletManagerV2Interface *q)
0931         : zwp_tablet_manager_v2(*display, s_version)
0932         , q(q)
0933         , m_display(display)
0934     {
0935     }
0936 
0937     void zwp_tablet_manager_v2_get_tablet_seat(Resource *resource, uint32_t tablet_seat, struct ::wl_resource *seat_resource) override
0938     {
0939         SeatInterface *seat = SeatInterface::get(seat_resource);
0940         TabletSeatV2Interface *tsi = get(seat);
0941         tsi->d->add(resource->client(), tablet_seat, s_version);
0942     }
0943 
0944     TabletSeatV2Interface *get(SeatInterface *seat)
0945     {
0946         TabletSeatV2Interface *&tabletSeat = m_seats[seat];
0947         if (!tabletSeat) {
0948             tabletSeat = new TabletSeatV2Interface(m_display, q);
0949         }
0950         return tabletSeat;
0951     }
0952 
0953     TabletManagerV2Interface *const q;
0954     Display *const m_display;
0955     QHash<SeatInterface *, TabletSeatV2Interface *> m_seats;
0956 };
0957 
0958 TabletManagerV2Interface::TabletManagerV2Interface(Display *display, QObject *parent)
0959     : QObject(parent)
0960     , d(new TabletManagerV2InterfacePrivate(display, this))
0961 {
0962 }
0963 
0964 TabletSeatV2Interface *TabletManagerV2Interface::seat(SeatInterface *seat) const
0965 {
0966     return d->get(seat);
0967 }
0968 
0969 bool TabletSeatV2Interface::isClientSupported(ClientConnection *client) const
0970 {
0971     return d->resourceMap().value(*client);
0972 }
0973 
0974 bool TabletSeatV2Interface::hasImplicitGrab(quint32 serial) const
0975 {
0976     return std::any_of(d->m_tools.cbegin(), d->m_tools.cend(), [serial](const auto &tools) {
0977         return std::any_of(tools.cbegin(), tools.cend(), [serial](const auto tool) {
0978             return tool->downSerial() == serial;
0979         });
0980     });
0981 }
0982 
0983 TabletManagerV2Interface::~TabletManagerV2Interface() = default;
0984 
0985 } // namespace KWin
0986 
0987 #include "moc_tablet_v2.cpp"