File indexing completed on 2024-05-19 16:35:22

0001 /*
0002     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
0003     SPDX-FileCopyrightText: 2021 Méven Car <meven.car@enioka.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 #include "outputdevice_v2_interface.h"
0008 
0009 #include "display.h"
0010 #include "display_p.h"
0011 #include "utils.h"
0012 #include "utils/common.h"
0013 
0014 #include "core/output.h"
0015 
0016 #include <QDebug>
0017 #include <QPointer>
0018 #include <QString>
0019 
0020 #include "qwayland-server-kde-output-device-v2.h"
0021 
0022 using namespace KWin;
0023 
0024 namespace KWaylandServer
0025 {
0026 
0027 static const quint32 s_version = 2;
0028 
0029 static QtWaylandServer::kde_output_device_v2::transform kwinTransformToOutputDeviceTransform(Output::Transform transform)
0030 {
0031     return static_cast<QtWaylandServer::kde_output_device_v2::transform>(transform);
0032 }
0033 
0034 static QtWaylandServer::kde_output_device_v2::subpixel kwinSubPixelToOutputDeviceSubPixel(Output::SubPixel subPixel)
0035 {
0036     return static_cast<QtWaylandServer::kde_output_device_v2::subpixel>(subPixel);
0037 }
0038 
0039 static uint32_t kwinCapabilitiesToOutputDeviceCapabilities(Output::Capabilities caps)
0040 {
0041     uint32_t ret = 0;
0042     if (caps & Output::Capability::Overscan) {
0043         ret |= QtWaylandServer::kde_output_device_v2::capability_overscan;
0044     }
0045     if (caps & Output::Capability::Vrr) {
0046         ret |= QtWaylandServer::kde_output_device_v2::capability_vrr;
0047     }
0048     if (caps & Output::Capability::RgbRange) {
0049         ret |= QtWaylandServer::kde_output_device_v2::capability_rgb_range;
0050     }
0051     return ret;
0052 }
0053 
0054 static QtWaylandServer::kde_output_device_v2::vrr_policy kwinVrrPolicyToOutputDeviceVrrPolicy(RenderLoop::VrrPolicy policy)
0055 {
0056     return static_cast<QtWaylandServer::kde_output_device_v2::vrr_policy>(policy);
0057 }
0058 
0059 static QtWaylandServer::kde_output_device_v2::rgb_range kwinRgbRangeToOutputDeviceRgbRange(Output::RgbRange range)
0060 {
0061     return static_cast<QtWaylandServer::kde_output_device_v2::rgb_range>(range);
0062 }
0063 
0064 class OutputDeviceV2InterfacePrivate : public QtWaylandServer::kde_output_device_v2
0065 {
0066 public:
0067     OutputDeviceV2InterfacePrivate(OutputDeviceV2Interface *q, Display *display, KWin::Output *handle);
0068     ~OutputDeviceV2InterfacePrivate() override;
0069 
0070     void sendGeometry(Resource *resource);
0071     wl_resource *sendNewMode(Resource *resource, OutputDeviceModeV2Interface *mode);
0072     void sendCurrentMode(Resource *resource);
0073     void sendDone(Resource *resource);
0074     void sendUuid(Resource *resource);
0075     void sendEdid(Resource *resource);
0076     void sendEnabled(Resource *resource);
0077     void sendScale(Resource *resource);
0078     void sendEisaId(Resource *resource);
0079     void sendName(Resource *resource);
0080     void sendSerialNumber(Resource *resource);
0081     void sendCapabilities(Resource *resource);
0082     void sendOverscan(Resource *resource);
0083     void sendVrrPolicy(Resource *resource);
0084     void sendRgbRange(Resource *resource);
0085 
0086     OutputDeviceV2Interface *q;
0087     QPointer<Display> m_display;
0088     KWin::Output *m_handle;
0089     QSize m_physicalSize;
0090     QPoint m_globalPosition;
0091     QString m_manufacturer = QStringLiteral("org.kde.kwin");
0092     QString m_model = QStringLiteral("none");
0093     qreal m_scale = 1.0;
0094     QString m_serialNumber;
0095     QString m_eisaId;
0096     QString m_name;
0097     subpixel m_subPixel = subpixel_unknown;
0098     transform m_transform = transform_normal;
0099     QList<OutputDeviceModeV2Interface *> m_modes;
0100     OutputDeviceModeV2Interface *m_currentMode = nullptr;
0101     QByteArray m_edid;
0102     bool m_enabled = true;
0103     QUuid m_uuid;
0104     uint32_t m_capabilities = 0;
0105     uint32_t m_overscan = 0;
0106     vrr_policy m_vrrPolicy = vrr_policy_automatic;
0107     rgb_range m_rgbRange = rgb_range_automatic;
0108 
0109 protected:
0110     void kde_output_device_v2_bind_resource(Resource *resource) override;
0111     void kde_output_device_v2_destroy_global() override;
0112 };
0113 
0114 class OutputDeviceModeV2InterfacePrivate : public QtWaylandServer::kde_output_device_mode_v2
0115 {
0116 public:
0117     struct ModeResource : Resource
0118     {
0119         OutputDeviceV2InterfacePrivate::Resource *output;
0120     };
0121 
0122     OutputDeviceModeV2InterfacePrivate(OutputDeviceModeV2Interface *q, std::shared_ptr<KWin::OutputMode> handle);
0123     ~OutputDeviceModeV2InterfacePrivate() override;
0124 
0125     Resource *createResource(OutputDeviceV2InterfacePrivate::Resource *output);
0126     Resource *findResource(OutputDeviceV2InterfacePrivate::Resource *output) const;
0127 
0128     void bindResource(wl_resource *resource);
0129 
0130     static OutputDeviceModeV2InterfacePrivate *get(OutputDeviceModeV2Interface *mode)
0131     {
0132         return mode->d.get();
0133     }
0134 
0135     OutputDeviceModeV2Interface *q;
0136     std::weak_ptr<KWin::OutputMode> m_handle;
0137     QSize m_size;
0138     int m_refreshRate = 60000;
0139     bool m_preferred = false;
0140 
0141 protected:
0142     Resource *kde_output_device_mode_v2_allocate() override;
0143 };
0144 
0145 OutputDeviceV2InterfacePrivate::OutputDeviceV2InterfacePrivate(OutputDeviceV2Interface *q, Display *display, KWin::Output *handle)
0146     : QtWaylandServer::kde_output_device_v2(*display, s_version)
0147     , q(q)
0148     , m_display(display)
0149     , m_handle(handle)
0150 {
0151     DisplayPrivate *displayPrivate = DisplayPrivate::get(display);
0152     displayPrivate->outputdevicesV2.append(q);
0153 }
0154 
0155 OutputDeviceV2InterfacePrivate::~OutputDeviceV2InterfacePrivate()
0156 {
0157     if (m_display) {
0158         DisplayPrivate *displayPrivate = DisplayPrivate::get(m_display);
0159         displayPrivate->outputdevicesV2.removeOne(q);
0160     }
0161 }
0162 
0163 OutputDeviceV2Interface::OutputDeviceV2Interface(Display *display, KWin::Output *handle, QObject *parent)
0164     : QObject(parent)
0165     , d(new OutputDeviceV2InterfacePrivate(this, display, handle))
0166 {
0167     updateEnabled();
0168     updateManufacturer();
0169     updateEdid();
0170     updateUuid();
0171     updateModel();
0172     updatePhysicalSize();
0173     updateGlobalPosition();
0174     updateScale();
0175     updateTransform();
0176     updateEisaId();
0177     updateSerialNumber();
0178     updateSubPixel();
0179     updateOverscan();
0180     updateCapabilities();
0181     updateVrrPolicy();
0182     updateRgbRange();
0183     updateName();
0184     updateModes();
0185 
0186     connect(handle, &Output::geometryChanged,
0187             this, &OutputDeviceV2Interface::updateGlobalPosition);
0188     connect(handle, &Output::scaleChanged,
0189             this, &OutputDeviceV2Interface::updateScale);
0190     connect(handle, &Output::enabledChanged,
0191             this, &OutputDeviceV2Interface::updateEnabled);
0192     connect(handle, &Output::transformChanged,
0193             this, &OutputDeviceV2Interface::updateTransform);
0194     connect(handle, &Output::currentModeChanged,
0195             this, &OutputDeviceV2Interface::updateCurrentMode);
0196     connect(handle, &Output::capabilitiesChanged,
0197             this, &OutputDeviceV2Interface::updateCapabilities);
0198     connect(handle, &Output::overscanChanged,
0199             this, &OutputDeviceV2Interface::updateOverscan);
0200     connect(handle, &Output::vrrPolicyChanged,
0201             this, &OutputDeviceV2Interface::updateVrrPolicy);
0202     connect(handle, &Output::modesChanged,
0203             this, &OutputDeviceV2Interface::updateModes);
0204     connect(handle, &Output::rgbRangeChanged,
0205             this, &OutputDeviceV2Interface::updateRgbRange);
0206 }
0207 
0208 OutputDeviceV2Interface::~OutputDeviceV2Interface()
0209 {
0210     d->globalRemove();
0211 }
0212 
0213 void OutputDeviceV2Interface::remove()
0214 {
0215     if (d->isGlobalRemoved()) {
0216         return;
0217     }
0218 
0219     if (d->m_display) {
0220         DisplayPrivate *displayPrivate = DisplayPrivate::get(d->m_display);
0221         displayPrivate->outputdevicesV2.removeOne(this);
0222     }
0223 
0224     d->globalRemove();
0225 }
0226 
0227 KWin::Output *OutputDeviceV2Interface::handle() const
0228 {
0229     return d->m_handle;
0230 }
0231 
0232 void OutputDeviceV2InterfacePrivate::kde_output_device_v2_destroy_global()
0233 {
0234     delete q;
0235 }
0236 
0237 void OutputDeviceV2InterfacePrivate::kde_output_device_v2_bind_resource(Resource *resource)
0238 {
0239     sendGeometry(resource);
0240     sendScale(resource);
0241     sendEisaId(resource);
0242     sendName(resource);
0243     sendSerialNumber(resource);
0244 
0245     for (OutputDeviceModeV2Interface *mode : std::as_const(m_modes)) {
0246         sendNewMode(resource, mode);
0247     }
0248     sendCurrentMode(resource);
0249     sendUuid(resource);
0250     sendEdid(resource);
0251     sendEnabled(resource);
0252     sendCapabilities(resource);
0253     sendOverscan(resource);
0254     sendVrrPolicy(resource);
0255     sendRgbRange(resource);
0256     sendDone(resource);
0257 }
0258 
0259 wl_resource *OutputDeviceV2InterfacePrivate::sendNewMode(Resource *resource, OutputDeviceModeV2Interface *mode)
0260 {
0261     auto privateMode = OutputDeviceModeV2InterfacePrivate::get(mode);
0262     // bind mode to client
0263     const auto modeResource = privateMode->createResource(resource);
0264 
0265     send_mode(resource->handle, modeResource->handle);
0266 
0267     privateMode->bindResource(modeResource->handle);
0268 
0269     return modeResource->handle;
0270 }
0271 
0272 void OutputDeviceV2InterfacePrivate::sendCurrentMode(Resource *outputResource)
0273 {
0274     const auto modeResource = OutputDeviceModeV2InterfacePrivate::get(m_currentMode)->findResource(outputResource);
0275     send_current_mode(outputResource->handle, modeResource->handle);
0276 }
0277 
0278 void OutputDeviceV2InterfacePrivate::sendGeometry(Resource *resource)
0279 {
0280     send_geometry(resource->handle,
0281                   m_globalPosition.x(),
0282                   m_globalPosition.y(),
0283                   m_physicalSize.width(),
0284                   m_physicalSize.height(),
0285                   m_subPixel,
0286                   m_manufacturer,
0287                   m_model,
0288                   m_transform);
0289 }
0290 
0291 void OutputDeviceV2InterfacePrivate::sendScale(Resource *resource)
0292 {
0293     send_scale(resource->handle, wl_fixed_from_double(m_scale));
0294 }
0295 
0296 void OutputDeviceV2InterfacePrivate::sendSerialNumber(Resource *resource)
0297 {
0298     send_serial_number(resource->handle, m_serialNumber);
0299 }
0300 
0301 void OutputDeviceV2InterfacePrivate::sendEisaId(Resource *resource)
0302 {
0303     send_eisa_id(resource->handle, m_eisaId);
0304 }
0305 
0306 void OutputDeviceV2InterfacePrivate::sendName(Resource *resource)
0307 {
0308     if (resource->version() >= KDE_OUTPUT_DEVICE_V2_NAME_SINCE_VERSION) {
0309         send_name(resource->handle, m_name);
0310     }
0311 }
0312 
0313 void OutputDeviceV2InterfacePrivate::sendDone(Resource *resource)
0314 {
0315     send_done(resource->handle);
0316 }
0317 
0318 void OutputDeviceV2InterfacePrivate::sendEdid(Resource *resource)
0319 {
0320     send_edid(resource->handle, QString::fromStdString(m_edid.toBase64().toStdString()));
0321 }
0322 
0323 void OutputDeviceV2InterfacePrivate::sendEnabled(Resource *resource)
0324 {
0325     send_enabled(resource->handle, m_enabled);
0326 }
0327 
0328 void OutputDeviceV2InterfacePrivate::sendUuid(Resource *resource)
0329 {
0330     send_uuid(resource->handle, m_uuid.toString(QUuid::WithoutBraces));
0331 }
0332 
0333 void OutputDeviceV2InterfacePrivate::sendCapabilities(Resource *resource)
0334 {
0335     send_capabilities(resource->handle, m_capabilities);
0336 }
0337 
0338 void OutputDeviceV2InterfacePrivate::sendOverscan(Resource *resource)
0339 {
0340     send_overscan(resource->handle, m_overscan);
0341 }
0342 
0343 void OutputDeviceV2InterfacePrivate::sendVrrPolicy(Resource *resource)
0344 {
0345     send_vrr_policy(resource->handle, m_vrrPolicy);
0346 }
0347 
0348 void OutputDeviceV2InterfacePrivate::sendRgbRange(Resource *resource)
0349 {
0350     send_rgb_range(resource->handle, m_rgbRange);
0351 }
0352 
0353 void OutputDeviceV2Interface::updateGeometry()
0354 {
0355     const auto clientResources = d->resourceMap();
0356     for (const auto &resource : clientResources) {
0357         d->sendGeometry(resource);
0358         d->sendDone(resource);
0359     }
0360 }
0361 
0362 void OutputDeviceV2Interface::updatePhysicalSize()
0363 {
0364     d->m_physicalSize = d->m_handle->physicalSize();
0365 }
0366 
0367 void OutputDeviceV2Interface::updateGlobalPosition()
0368 {
0369     const QPoint arg = d->m_handle->geometry().topLeft();
0370     if (d->m_globalPosition == arg) {
0371         return;
0372     }
0373     d->m_globalPosition = arg;
0374     updateGeometry();
0375 }
0376 
0377 void OutputDeviceV2Interface::updateManufacturer()
0378 {
0379     d->m_manufacturer = d->m_handle->manufacturer();
0380 }
0381 
0382 void OutputDeviceV2Interface::updateModel()
0383 {
0384     d->m_model = d->m_handle->model();
0385 }
0386 
0387 void OutputDeviceV2Interface::updateSerialNumber()
0388 {
0389     d->m_serialNumber = d->m_handle->serialNumber();
0390 }
0391 
0392 void OutputDeviceV2Interface::updateEisaId()
0393 {
0394     d->m_eisaId = d->m_handle->eisaId();
0395 }
0396 
0397 void OutputDeviceV2Interface::updateName()
0398 {
0399     d->m_name = d->m_handle->name();
0400 }
0401 
0402 void OutputDeviceV2Interface::updateSubPixel()
0403 {
0404     const auto arg = kwinSubPixelToOutputDeviceSubPixel(d->m_handle->subPixel());
0405     if (d->m_subPixel != arg) {
0406         d->m_subPixel = arg;
0407         updateGeometry();
0408     }
0409 }
0410 
0411 void OutputDeviceV2Interface::updateTransform()
0412 {
0413     const auto arg = kwinTransformToOutputDeviceTransform(d->m_handle->transform());
0414     if (d->m_transform != arg) {
0415         d->m_transform = arg;
0416         updateGeometry();
0417     }
0418 }
0419 
0420 void OutputDeviceV2Interface::updateScale()
0421 {
0422     const qreal scale = d->m_handle->scale();
0423     if (qFuzzyCompare(d->m_scale, scale)) {
0424         return;
0425     }
0426     d->m_scale = scale;
0427     const auto clientResources = d->resourceMap();
0428     for (const auto &resource : clientResources) {
0429         d->sendScale(resource);
0430         d->sendDone(resource);
0431     }
0432 }
0433 
0434 void OutputDeviceV2Interface::updateModes()
0435 {
0436     const auto oldModes = d->m_modes;
0437     d->m_modes.clear();
0438     d->m_currentMode = nullptr;
0439 
0440     const auto clientResources = d->resourceMap();
0441     const auto nativeModes = d->m_handle->modes();
0442 
0443     for (const std::shared_ptr<OutputMode> &mode : nativeModes) {
0444         OutputDeviceModeV2Interface *deviceMode = new OutputDeviceModeV2Interface(mode, this);
0445         d->m_modes.append(deviceMode);
0446 
0447         if (d->m_handle->currentMode() == mode) {
0448             d->m_currentMode = deviceMode;
0449         }
0450 
0451         for (auto resource : clientResources) {
0452             d->sendNewMode(resource, deviceMode);
0453         }
0454     }
0455 
0456     for (auto resource : clientResources) {
0457         d->sendCurrentMode(resource);
0458     }
0459 
0460     qDeleteAll(oldModes.crbegin(), oldModes.crend());
0461 
0462     for (auto resource : clientResources) {
0463         d->sendDone(resource);
0464     }
0465 }
0466 
0467 void OutputDeviceV2Interface::updateCurrentMode()
0468 {
0469     for (OutputDeviceModeV2Interface *mode : std::as_const(d->m_modes)) {
0470         if (mode->handle().lock() == d->m_handle->currentMode()) {
0471             if (d->m_currentMode != mode) {
0472                 d->m_currentMode = mode;
0473                 const auto clientResources = d->resourceMap();
0474                 for (auto resource : clientResources) {
0475                     d->sendCurrentMode(resource);
0476                     d->sendDone(resource);
0477                 }
0478                 updateGeometry();
0479             }
0480             return;
0481         }
0482     }
0483 }
0484 
0485 void OutputDeviceV2Interface::updateEdid()
0486 {
0487     d->m_edid = d->m_handle->edid();
0488     const auto clientResources = d->resourceMap();
0489     for (const auto &resource : clientResources) {
0490         d->sendEdid(resource);
0491         d->sendDone(resource);
0492     }
0493 }
0494 
0495 void OutputDeviceV2Interface::updateEnabled()
0496 {
0497     bool enabled = d->m_handle->isEnabled();
0498     if (d->m_enabled != enabled) {
0499         d->m_enabled = enabled;
0500         const auto clientResources = d->resourceMap();
0501         for (const auto &resource : clientResources) {
0502             d->sendEnabled(resource);
0503             d->sendDone(resource);
0504         }
0505     }
0506 }
0507 
0508 void OutputDeviceV2Interface::updateUuid()
0509 {
0510     const QUuid uuid = d->m_handle->uuid();
0511     if (d->m_uuid != uuid) {
0512         d->m_uuid = uuid;
0513         const auto clientResources = d->resourceMap();
0514         for (const auto &resource : clientResources) {
0515             d->sendUuid(resource);
0516             d->sendDone(resource);
0517         }
0518     }
0519 }
0520 
0521 void OutputDeviceV2Interface::updateCapabilities()
0522 {
0523     const uint32_t cap = kwinCapabilitiesToOutputDeviceCapabilities(d->m_handle->capabilities());
0524     if (d->m_capabilities != cap) {
0525         d->m_capabilities = cap;
0526         const auto clientResources = d->resourceMap();
0527         for (const auto &resource : clientResources) {
0528             d->sendCapabilities(resource);
0529             d->sendDone(resource);
0530         }
0531     }
0532 }
0533 
0534 void OutputDeviceV2Interface::updateOverscan()
0535 {
0536     const uint32_t overscan = d->m_handle->overscan();
0537     if (d->m_overscan != overscan) {
0538         d->m_overscan = overscan;
0539         const auto clientResources = d->resourceMap();
0540         for (const auto &resource : clientResources) {
0541             d->sendOverscan(resource);
0542             d->sendDone(resource);
0543         }
0544     }
0545 }
0546 
0547 void OutputDeviceV2Interface::updateVrrPolicy()
0548 {
0549     const auto policy = kwinVrrPolicyToOutputDeviceVrrPolicy(d->m_handle->vrrPolicy());
0550     if (d->m_vrrPolicy != policy) {
0551         d->m_vrrPolicy = policy;
0552         const auto clientResources = d->resourceMap();
0553         for (const auto &resource : clientResources) {
0554             d->sendVrrPolicy(resource);
0555             d->sendDone(resource);
0556         }
0557     }
0558 }
0559 
0560 void OutputDeviceV2Interface::updateRgbRange()
0561 {
0562     const auto rgbRange = kwinRgbRangeToOutputDeviceRgbRange(d->m_handle->rgbRange());
0563     if (d->m_rgbRange != rgbRange) {
0564         d->m_rgbRange = rgbRange;
0565         const auto clientResources = d->resourceMap();
0566         for (const auto &resource : clientResources) {
0567             d->sendRgbRange(resource);
0568             d->sendDone(resource);
0569         }
0570     }
0571 }
0572 
0573 OutputDeviceV2Interface *OutputDeviceV2Interface::get(wl_resource *native)
0574 {
0575     if (auto devicePrivate = resource_cast<OutputDeviceV2InterfacePrivate *>(native); devicePrivate && !devicePrivate->isGlobalRemoved()) {
0576         return devicePrivate->q;
0577     }
0578     return nullptr;
0579 }
0580 
0581 OutputDeviceModeV2InterfacePrivate::OutputDeviceModeV2InterfacePrivate(OutputDeviceModeV2Interface *q, std::shared_ptr<KWin::OutputMode> handle)
0582     : QtWaylandServer::kde_output_device_mode_v2()
0583     , q(q)
0584     , m_handle(handle)
0585     , m_size(handle->size())
0586     , m_refreshRate(handle->refreshRate())
0587     , m_preferred(handle->flags() & OutputMode::Flag::Preferred)
0588 {
0589 }
0590 
0591 OutputDeviceModeV2Interface::OutputDeviceModeV2Interface(std::shared_ptr<KWin::OutputMode> handle, QObject *parent)
0592     : QObject(parent)
0593     , d(new OutputDeviceModeV2InterfacePrivate(this, handle))
0594 {
0595 }
0596 
0597 OutputDeviceModeV2Interface::~OutputDeviceModeV2Interface() = default;
0598 
0599 OutputDeviceModeV2InterfacePrivate::~OutputDeviceModeV2InterfacePrivate()
0600 {
0601     const auto map = resourceMap();
0602     for (Resource *resource : map) {
0603         send_removed(resource->handle);
0604     }
0605 }
0606 
0607 OutputDeviceModeV2InterfacePrivate::Resource *OutputDeviceModeV2InterfacePrivate::createResource(OutputDeviceV2InterfacePrivate::Resource *output)
0608 {
0609     const auto modeResource = static_cast<ModeResource *>(add(output->client(), output->version()));
0610     modeResource->output = output;
0611     return modeResource;
0612 }
0613 
0614 OutputDeviceModeV2InterfacePrivate::Resource *OutputDeviceModeV2InterfacePrivate::findResource(OutputDeviceV2InterfacePrivate::Resource *output) const
0615 {
0616     const auto resources = resourceMap();
0617     for (const auto &resource : resources) {
0618         auto modeResource = static_cast<ModeResource *>(resource);
0619         if (modeResource->output == output) {
0620             return resource;
0621         }
0622     }
0623     return nullptr;
0624 }
0625 
0626 OutputDeviceModeV2InterfacePrivate::Resource *OutputDeviceModeV2InterfacePrivate::kde_output_device_mode_v2_allocate()
0627 {
0628     return new ModeResource;
0629 }
0630 
0631 std::weak_ptr<KWin::OutputMode> OutputDeviceModeV2Interface::handle() const
0632 {
0633     return d->m_handle;
0634 }
0635 
0636 void OutputDeviceModeV2InterfacePrivate::bindResource(wl_resource *resource)
0637 {
0638     send_size(resource, m_size.width(), m_size.height());
0639     send_refresh(resource, m_refreshRate);
0640 
0641     if (m_preferred) {
0642         send_preferred(resource);
0643     }
0644 }
0645 
0646 OutputDeviceModeV2Interface *OutputDeviceModeV2Interface::get(wl_resource *native)
0647 {
0648     if (auto devicePrivate = resource_cast<OutputDeviceModeV2InterfacePrivate *>(native)) {
0649         return devicePrivate->q;
0650     }
0651     return nullptr;
0652 }
0653 
0654 }