/* SPDX-FileCopyrightText: 2014 Martin Gräßlin SPDX-FileCopyrightText: 2021 Méven Car SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "outputdevice_v2.h" #include "display.h" #include "display_p.h" #include "utils/common.h" #include "utils/resource.h" #include "core/output.h" #include #include #include #include "qwayland-server-kde-output-device-v2.h" namespace KWin { static const quint32 s_version = 9; static QtWaylandServer::kde_output_device_v2::transform kwinTransformToOutputDeviceTransform(OutputTransform transform) { return static_cast(transform.kind()); } static QtWaylandServer::kde_output_device_v2::subpixel kwinSubPixelToOutputDeviceSubPixel(Output::SubPixel subPixel) { return static_cast(subPixel); } static uint32_t kwinCapabilitiesToOutputDeviceCapabilities(Output::Capabilities caps) { uint32_t ret = 0; if (caps & Output::Capability::Overscan) { ret |= QtWaylandServer::kde_output_device_v2::capability_overscan; } if (caps & Output::Capability::Vrr) { ret |= QtWaylandServer::kde_output_device_v2::capability_vrr; } if (caps & Output::Capability::RgbRange) { ret |= QtWaylandServer::kde_output_device_v2::capability_rgb_range; } if (caps & Output::Capability::HighDynamicRange) { ret |= QtWaylandServer::kde_output_device_v2::capability_high_dynamic_range; } if (caps & Output::Capability::WideColorGamut) { ret |= QtWaylandServer::kde_output_device_v2::capability_wide_color_gamut; } if (caps & Output::Capability::AutoRotation) { ret |= QtWaylandServer::kde_output_device_v2::capability_auto_rotate; } if (caps & Output::Capability::IccProfile) { ret |= QtWaylandServer::kde_output_device_v2::capability_icc_profile; } if (caps & Output::Capability::BrightnessControl) { ret |= QtWaylandServer::kde_output_device_v2::capability_brightness; } return ret; } static QtWaylandServer::kde_output_device_v2::vrr_policy kwinVrrPolicyToOutputDeviceVrrPolicy(VrrPolicy policy) { return static_cast(policy); } static QtWaylandServer::kde_output_device_v2::rgb_range kwinRgbRangeToOutputDeviceRgbRange(Output::RgbRange range) { return static_cast(range); } static QtWaylandServer::kde_output_device_v2::auto_rotate_policy kwinAutoRotationToOutputDeviceAutoRotation(Output::AutoRotationPolicy policy) { return static_cast(policy); } class OutputDeviceV2InterfacePrivate : public QtWaylandServer::kde_output_device_v2 { public: OutputDeviceV2InterfacePrivate(OutputDeviceV2Interface *q, Display *display, Output *handle); ~OutputDeviceV2InterfacePrivate() override; void sendGeometry(Resource *resource); wl_resource *sendNewMode(Resource *resource, OutputDeviceModeV2Interface *mode); void sendCurrentMode(Resource *resource); void sendDone(Resource *resource); void sendUuid(Resource *resource); void sendEdid(Resource *resource); void sendEnabled(Resource *resource); void sendScale(Resource *resource); void sendEisaId(Resource *resource); void sendName(Resource *resource); void sendSerialNumber(Resource *resource); void sendCapabilities(Resource *resource); void sendOverscan(Resource *resource); void sendVrrPolicy(Resource *resource); void sendRgbRange(Resource *resource); void sendHighDynamicRange(Resource *resource); void sendSdrBrightness(Resource *resource); void sendWideColorGamut(Resource *resource); void sendAutoRotationPolicy(Resource *resource); void sendIccProfilePath(Resource *resource); void sendBrightnessMetadata(Resource *resource); void sendBrightnessOverrides(Resource *resource); void sendSdrGamutWideness(Resource *resource); void sendColorProfileSource(Resource *resource); void sendBrightness(Resource *resource); OutputDeviceV2Interface *q; QPointer m_display; Output *m_handle; QSize m_physicalSize; QPoint m_globalPosition; QString m_manufacturer = QStringLiteral("org.kde.kwin"); QString m_model = QStringLiteral("none"); qreal m_scale = 1.0; QString m_serialNumber; QString m_eisaId; QString m_name; subpixel m_subPixel = subpixel_unknown; transform m_transform = transform_normal; QList m_modes; OutputDeviceModeV2Interface *m_currentMode = nullptr; QByteArray m_edid; bool m_enabled = true; QUuid m_uuid; uint32_t m_capabilities = 0; uint32_t m_overscan = 0; vrr_policy m_vrrPolicy = vrr_policy_automatic; rgb_range m_rgbRange = rgb_range_automatic; bool m_highDynamicRange = false; uint32_t m_referenceLuminance = 200; bool m_wideColorGamut = false; auto_rotate_policy m_autoRotation = auto_rotate_policy::auto_rotate_policy_in_tablet_mode; QString m_iccProfilePath; std::optional m_maxPeakBrightness; std::optional m_maxAverageBrightness; double m_minBrightness = 0; double m_sdrGamutWideness = 0; std::optional m_maxPeakBrightnessOverride; std::optional m_maxAverageBrightnessOverride; std::optional m_minBrightnessOverride; color_profile_source m_colorProfile = color_profile_source::color_profile_source_sRGB; double m_brightness = 1.0; protected: void kde_output_device_v2_bind_resource(Resource *resource) override; void kde_output_device_v2_destroy_global() override; }; class OutputDeviceModeV2InterfacePrivate : public QtWaylandServer::kde_output_device_mode_v2 { public: struct ModeResource : Resource { OutputDeviceV2InterfacePrivate::Resource *output; }; OutputDeviceModeV2InterfacePrivate(OutputDeviceModeV2Interface *q, std::shared_ptr handle); ~OutputDeviceModeV2InterfacePrivate() override; Resource *createResource(OutputDeviceV2InterfacePrivate::Resource *output); Resource *findResource(OutputDeviceV2InterfacePrivate::Resource *output) const; void bindResource(wl_resource *resource); static OutputDeviceModeV2InterfacePrivate *get(OutputDeviceModeV2Interface *mode) { return mode->d.get(); } OutputDeviceModeV2Interface *q; std::weak_ptr m_handle; QSize m_size; int m_refreshRate = 60000; bool m_preferred = false; protected: Resource *kde_output_device_mode_v2_allocate() override; }; OutputDeviceV2InterfacePrivate::OutputDeviceV2InterfacePrivate(OutputDeviceV2Interface *q, Display *display, Output *handle) : QtWaylandServer::kde_output_device_v2(*display, s_version) , q(q) , m_display(display) , m_handle(handle) { DisplayPrivate *displayPrivate = DisplayPrivate::get(display); displayPrivate->outputdevicesV2.append(q); } OutputDeviceV2InterfacePrivate::~OutputDeviceV2InterfacePrivate() { if (m_display) { DisplayPrivate *displayPrivate = DisplayPrivate::get(m_display); displayPrivate->outputdevicesV2.removeOne(q); } } OutputDeviceV2Interface::OutputDeviceV2Interface(Display *display, Output *handle, QObject *parent) : QObject(parent) , d(new OutputDeviceV2InterfacePrivate(this, display, handle)) { updateEnabled(); updateManufacturer(); updateEdid(); updateUuid(); updateModel(); updatePhysicalSize(); updateGlobalPosition(); updateScale(); updateTransform(); updateEisaId(); updateSerialNumber(); updateSubPixel(); updateOverscan(); updateCapabilities(); updateVrrPolicy(); updateRgbRange(); updateName(); updateModes(); updateHighDynamicRange(); updateSdrBrightness(); updateWideColorGamut(); updateAutoRotate(); updateIccProfilePath(); updateBrightnessMetadata(); updateBrightnessOverrides(); updateSdrGamutWideness(); updateColorProfileSource(); updateBrightness(); connect(handle, &Output::geometryChanged, this, &OutputDeviceV2Interface::updateGlobalPosition); connect(handle, &Output::scaleChanged, this, &OutputDeviceV2Interface::updateScale); connect(handle, &Output::enabledChanged, this, &OutputDeviceV2Interface::updateEnabled); connect(handle, &Output::transformChanged, this, &OutputDeviceV2Interface::updateTransform); connect(handle, &Output::currentModeChanged, this, &OutputDeviceV2Interface::updateCurrentMode); connect(handle, &Output::capabilitiesChanged, this, &OutputDeviceV2Interface::updateCapabilities); connect(handle, &Output::overscanChanged, this, &OutputDeviceV2Interface::updateOverscan); connect(handle, &Output::vrrPolicyChanged, this, &OutputDeviceV2Interface::updateVrrPolicy); connect(handle, &Output::modesChanged, this, &OutputDeviceV2Interface::updateModes); connect(handle, &Output::rgbRangeChanged, this, &OutputDeviceV2Interface::updateRgbRange); connect(handle, &Output::highDynamicRangeChanged, this, &OutputDeviceV2Interface::updateHighDynamicRange); connect(handle, &Output::referenceLuminanceChanged, this, &OutputDeviceV2Interface::updateSdrBrightness); connect(handle, &Output::wideColorGamutChanged, this, &OutputDeviceV2Interface::updateWideColorGamut); connect(handle, &Output::autoRotationPolicyChanged, this, &OutputDeviceV2Interface::updateAutoRotate); connect(handle, &Output::iccProfileChanged, this, &OutputDeviceV2Interface::updateIccProfilePath); connect(handle, &Output::brightnessMetadataChanged, this, &OutputDeviceV2Interface::updateBrightnessMetadata); connect(handle, &Output::brightnessMetadataChanged, this, &OutputDeviceV2Interface::updateBrightnessOverrides); connect(handle, &Output::sdrGamutWidenessChanged, this, &OutputDeviceV2Interface::updateSdrGamutWideness); connect(handle, &Output::colorProfileSourceChanged, this, &OutputDeviceV2Interface::updateColorProfileSource); connect(handle, &Output::brightnessChanged, this, &OutputDeviceV2Interface::updateBrightness); } OutputDeviceV2Interface::~OutputDeviceV2Interface() { d->globalRemove(); } void OutputDeviceV2Interface::remove() { if (d->isGlobalRemoved()) { return; } if (d->m_display) { DisplayPrivate *displayPrivate = DisplayPrivate::get(d->m_display); displayPrivate->outputdevicesV2.removeOne(this); } d->globalRemove(); } Output *OutputDeviceV2Interface::handle() const { return d->m_handle; } void OutputDeviceV2InterfacePrivate::kde_output_device_v2_destroy_global() { delete q; } void OutputDeviceV2InterfacePrivate::kde_output_device_v2_bind_resource(Resource *resource) { sendGeometry(resource); sendScale(resource); sendEisaId(resource); sendName(resource); sendSerialNumber(resource); for (OutputDeviceModeV2Interface *mode : std::as_const(m_modes)) { sendNewMode(resource, mode); } sendCurrentMode(resource); sendUuid(resource); sendEdid(resource); sendEnabled(resource); sendCapabilities(resource); sendOverscan(resource); sendVrrPolicy(resource); sendRgbRange(resource); sendHighDynamicRange(resource); sendSdrBrightness(resource); sendWideColorGamut(resource); sendAutoRotationPolicy(resource); sendIccProfilePath(resource); sendBrightnessMetadata(resource); sendBrightnessOverrides(resource); sendSdrGamutWideness(resource); sendColorProfileSource(resource); sendBrightness(resource); sendDone(resource); } wl_resource *OutputDeviceV2InterfacePrivate::sendNewMode(Resource *resource, OutputDeviceModeV2Interface *mode) { auto privateMode = OutputDeviceModeV2InterfacePrivate::get(mode); // bind mode to client const auto modeResource = privateMode->createResource(resource); send_mode(resource->handle, modeResource->handle); privateMode->bindResource(modeResource->handle); return modeResource->handle; } void OutputDeviceV2InterfacePrivate::sendCurrentMode(Resource *outputResource) { const auto modeResource = OutputDeviceModeV2InterfacePrivate::get(m_currentMode)->findResource(outputResource); send_current_mode(outputResource->handle, modeResource->handle); } void OutputDeviceV2InterfacePrivate::sendGeometry(Resource *resource) { send_geometry(resource->handle, m_globalPosition.x(), m_globalPosition.y(), m_physicalSize.width(), m_physicalSize.height(), m_subPixel, m_manufacturer, m_model, m_transform); } void OutputDeviceV2InterfacePrivate::sendScale(Resource *resource) { send_scale(resource->handle, wl_fixed_from_double(m_scale)); } void OutputDeviceV2InterfacePrivate::sendSerialNumber(Resource *resource) { send_serial_number(resource->handle, m_serialNumber); } void OutputDeviceV2InterfacePrivate::sendEisaId(Resource *resource) { send_eisa_id(resource->handle, m_eisaId); } void OutputDeviceV2InterfacePrivate::sendName(Resource *resource) { if (resource->version() >= KDE_OUTPUT_DEVICE_V2_NAME_SINCE_VERSION) { send_name(resource->handle, m_name); } } void OutputDeviceV2InterfacePrivate::sendDone(Resource *resource) { send_done(resource->handle); } void OutputDeviceV2InterfacePrivate::sendEdid(Resource *resource) { send_edid(resource->handle, QString::fromStdString(m_edid.toBase64().toStdString())); } void OutputDeviceV2InterfacePrivate::sendEnabled(Resource *resource) { send_enabled(resource->handle, m_enabled); } void OutputDeviceV2InterfacePrivate::sendUuid(Resource *resource) { send_uuid(resource->handle, m_uuid.toString(QUuid::WithoutBraces)); } void OutputDeviceV2InterfacePrivate::sendCapabilities(Resource *resource) { send_capabilities(resource->handle, m_capabilities); } void OutputDeviceV2InterfacePrivate::sendOverscan(Resource *resource) { send_overscan(resource->handle, m_overscan); } void OutputDeviceV2InterfacePrivate::sendVrrPolicy(Resource *resource) { send_vrr_policy(resource->handle, m_vrrPolicy); } void OutputDeviceV2InterfacePrivate::sendRgbRange(Resource *resource) { send_rgb_range(resource->handle, m_rgbRange); } void OutputDeviceV2InterfacePrivate::sendHighDynamicRange(Resource *resource) { if (resource->version() >= KDE_OUTPUT_DEVICE_V2_HIGH_DYNAMIC_RANGE_SINCE_VERSION) { send_high_dynamic_range(resource->handle, m_highDynamicRange ? 1 : 0); } } void OutputDeviceV2InterfacePrivate::sendSdrBrightness(Resource *resource) { if (resource->version() >= KDE_OUTPUT_DEVICE_V2_SDR_BRIGHTNESS_SINCE_VERSION) { send_sdr_brightness(resource->handle, m_referenceLuminance); } } void OutputDeviceV2InterfacePrivate::sendWideColorGamut(Resource *resource) { if (resource->version() >= KDE_OUTPUT_DEVICE_V2_WIDE_COLOR_GAMUT_SINCE_VERSION) { send_wide_color_gamut(resource->handle, m_wideColorGamut ? 1 : 0); } } void OutputDeviceV2InterfacePrivate::sendAutoRotationPolicy(Resource *resource) { if (resource->version() >= KDE_OUTPUT_DEVICE_V2_AUTO_ROTATE_POLICY_SINCE_VERSION) { send_auto_rotate_policy(resource->handle, m_autoRotation); } } void OutputDeviceV2InterfacePrivate::sendIccProfilePath(Resource *resource) { if (resource->version() >= KDE_OUTPUT_DEVICE_V2_ICC_PROFILE_PATH_SINCE_VERSION) { send_icc_profile_path(resource->handle, m_iccProfilePath); } } void OutputDeviceV2InterfacePrivate::sendBrightnessMetadata(Resource *resource) { if (resource->version() >= KDE_OUTPUT_DEVICE_V2_BRIGHTNESS_METADATA_SINCE_VERSION) { send_brightness_metadata(resource->handle, std::round(m_maxPeakBrightness.value_or(0)), std::round(m_maxAverageBrightness.value_or(0)), std::round(m_minBrightness * 10'000)); } } void OutputDeviceV2InterfacePrivate::sendBrightnessOverrides(Resource *resource) { if (resource->version() >= KDE_OUTPUT_DEVICE_V2_BRIGHTNESS_OVERRIDES_SINCE_VERSION) { send_brightness_overrides(resource->handle, std::round(m_maxPeakBrightnessOverride.value_or(-1)), std::round(m_maxAverageBrightnessOverride.value_or(-1)), std::round(m_minBrightnessOverride.value_or(-0.000'1) * 10'000)); } } void OutputDeviceV2InterfacePrivate::sendSdrGamutWideness(Resource *resource) { if (resource->version() >= KDE_OUTPUT_DEVICE_V2_SDR_GAMUT_WIDENESS_SINCE_VERSION) { send_sdr_gamut_wideness(resource->handle, std::clamp(m_sdrGamutWideness * 10'000, 0, 10'000)); } } void OutputDeviceV2InterfacePrivate::sendColorProfileSource(Resource *resource) { if (resource->version() >= KDE_OUTPUT_DEVICE_V2_COLOR_PROFILE_SOURCE_SINCE_VERSION) { send_color_profile_source(resource->handle, m_colorProfile); } } void OutputDeviceV2InterfacePrivate::sendBrightness(Resource *resource) { if (resource->version() >= KDE_OUTPUT_DEVICE_V2_BRIGHTNESS_SINCE_VERSION) { send_brightness(resource->handle, m_brightness); } } void OutputDeviceV2Interface::updateGeometry() { const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendGeometry(resource); d->sendDone(resource); } } void OutputDeviceV2Interface::updatePhysicalSize() { d->m_physicalSize = d->m_handle->physicalSize(); } void OutputDeviceV2Interface::updateGlobalPosition() { const QPoint arg = d->m_handle->geometry().topLeft(); if (d->m_globalPosition == arg) { return; } d->m_globalPosition = arg; updateGeometry(); } void OutputDeviceV2Interface::updateManufacturer() { d->m_manufacturer = d->m_handle->manufacturer(); } void OutputDeviceV2Interface::updateModel() { d->m_model = d->m_handle->model(); } void OutputDeviceV2Interface::updateSerialNumber() { d->m_serialNumber = d->m_handle->serialNumber(); } void OutputDeviceV2Interface::updateEisaId() { d->m_eisaId = d->m_handle->eisaId(); } void OutputDeviceV2Interface::updateName() { d->m_name = d->m_handle->name(); } void OutputDeviceV2Interface::updateSubPixel() { const auto arg = kwinSubPixelToOutputDeviceSubPixel(d->m_handle->subPixel()); if (d->m_subPixel != arg) { d->m_subPixel = arg; updateGeometry(); } } void OutputDeviceV2Interface::updateTransform() { const auto arg = kwinTransformToOutputDeviceTransform(d->m_handle->transform()); if (d->m_transform != arg) { d->m_transform = arg; updateGeometry(); } } void OutputDeviceV2Interface::updateScale() { const qreal scale = d->m_handle->scale(); if (qFuzzyCompare(d->m_scale, scale)) { return; } d->m_scale = scale; const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendScale(resource); d->sendDone(resource); } } void OutputDeviceV2Interface::updateModes() { const auto oldModes = d->m_modes; d->m_modes.clear(); d->m_currentMode = nullptr; const auto clientResources = d->resourceMap(); const auto nativeModes = d->m_handle->modes(); for (const std::shared_ptr &mode : nativeModes) { OutputDeviceModeV2Interface *deviceMode = new OutputDeviceModeV2Interface(mode, this); d->m_modes.append(deviceMode); if (d->m_handle->currentMode() == mode) { d->m_currentMode = deviceMode; } for (auto resource : clientResources) { d->sendNewMode(resource, deviceMode); } } for (auto resource : clientResources) { d->sendCurrentMode(resource); } qDeleteAll(oldModes.crbegin(), oldModes.crend()); for (auto resource : clientResources) { d->sendDone(resource); } } void OutputDeviceV2Interface::updateCurrentMode() { for (OutputDeviceModeV2Interface *mode : std::as_const(d->m_modes)) { if (mode->handle().lock() == d->m_handle->currentMode()) { if (d->m_currentMode != mode) { d->m_currentMode = mode; const auto clientResources = d->resourceMap(); for (auto resource : clientResources) { d->sendCurrentMode(resource); d->sendDone(resource); } updateGeometry(); } return; } } } void OutputDeviceV2Interface::updateEdid() { d->m_edid = d->m_handle->edid().raw(); const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendEdid(resource); d->sendDone(resource); } } void OutputDeviceV2Interface::updateEnabled() { bool enabled = d->m_handle->isEnabled(); if (d->m_enabled != enabled) { d->m_enabled = enabled; const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendEnabled(resource); d->sendDone(resource); } } } void OutputDeviceV2Interface::updateUuid() { const QUuid uuid = d->m_handle->uuid(); if (d->m_uuid != uuid) { d->m_uuid = uuid; const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendUuid(resource); d->sendDone(resource); } } } void OutputDeviceV2Interface::updateCapabilities() { const uint32_t cap = kwinCapabilitiesToOutputDeviceCapabilities(d->m_handle->capabilities()); if (d->m_capabilities != cap) { d->m_capabilities = cap; const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendCapabilities(resource); d->sendDone(resource); } } } void OutputDeviceV2Interface::updateOverscan() { const uint32_t overscan = d->m_handle->overscan(); if (d->m_overscan != overscan) { d->m_overscan = overscan; const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendOverscan(resource); d->sendDone(resource); } } } void OutputDeviceV2Interface::updateVrrPolicy() { const auto policy = kwinVrrPolicyToOutputDeviceVrrPolicy(d->m_handle->vrrPolicy()); if (d->m_vrrPolicy != policy) { d->m_vrrPolicy = policy; const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendVrrPolicy(resource); d->sendDone(resource); } } } void OutputDeviceV2Interface::updateRgbRange() { const auto rgbRange = kwinRgbRangeToOutputDeviceRgbRange(d->m_handle->rgbRange()); if (d->m_rgbRange != rgbRange) { d->m_rgbRange = rgbRange; const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendRgbRange(resource); d->sendDone(resource); } } } void OutputDeviceV2Interface::updateHighDynamicRange() { if (d->m_highDynamicRange != d->m_handle->highDynamicRange()) { d->m_highDynamicRange = d->m_handle->highDynamicRange(); const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendHighDynamicRange(resource); d->sendDone(resource); } } } void OutputDeviceV2Interface::updateSdrBrightness() { if (d->m_referenceLuminance != d->m_handle->referenceLuminance()) { d->m_referenceLuminance = d->m_handle->referenceLuminance(); const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendSdrBrightness(resource); d->sendDone(resource); } } } void OutputDeviceV2Interface::updateWideColorGamut() { if (d->m_wideColorGamut != d->m_handle->wideColorGamut()) { d->m_wideColorGamut = d->m_handle->wideColorGamut(); const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendWideColorGamut(resource); d->sendDone(resource); } } } void OutputDeviceV2Interface::updateAutoRotate() { const auto policy = kwinAutoRotationToOutputDeviceAutoRotation(d->m_handle->autoRotationPolicy()); if (d->m_autoRotation != policy) { d->m_autoRotation = policy; const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendAutoRotationPolicy(resource); d->sendDone(resource); } } } void OutputDeviceV2Interface::updateIccProfilePath() { if (d->m_iccProfilePath != d->m_handle->iccProfilePath()) { d->m_iccProfilePath = d->m_handle->iccProfilePath(); const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendIccProfilePath(resource); d->sendDone(resource); } } } void OutputDeviceV2Interface::updateBrightnessMetadata() { if (d->m_maxPeakBrightness != d->m_handle->maxPeakBrightness() || d->m_maxAverageBrightness != d->m_handle->maxAverageBrightness() || d->m_minBrightness != d->m_handle->minBrightness()) { d->m_maxPeakBrightness = d->m_handle->maxPeakBrightness(); d->m_maxAverageBrightness = d->m_handle->maxAverageBrightness(); d->m_minBrightness = d->m_handle->minBrightness(); const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendBrightnessMetadata(resource); d->sendDone(resource); } } } void OutputDeviceV2Interface::updateBrightnessOverrides() { if (d->m_maxPeakBrightnessOverride != d->m_handle->maxPeakBrightnessOverride() || d->m_maxAverageBrightnessOverride != d->m_handle->maxAverageBrightnessOverride() || d->m_minBrightnessOverride != d->m_handle->minBrightnessOverride()) { d->m_maxPeakBrightnessOverride = d->m_handle->maxPeakBrightnessOverride(); d->m_maxAverageBrightnessOverride = d->m_handle->maxAverageBrightnessOverride(); d->m_minBrightnessOverride = d->m_handle->minBrightnessOverride(); const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendBrightnessOverrides(resource); d->sendDone(resource); } } } void OutputDeviceV2Interface::updateSdrGamutWideness() { if (d->m_sdrGamutWideness != d->m_handle->sdrGamutWideness()) { d->m_sdrGamutWideness = d->m_handle->sdrGamutWideness(); const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendSdrGamutWideness(resource); d->sendDone(resource); } } } void OutputDeviceV2Interface::updateColorProfileSource() { const auto waylandColorProfileSource = [this]() { switch (d->m_handle->colorProfileSource()) { case Output::ColorProfileSource::sRGB: return QtWaylandServer::kde_output_device_v2::color_profile_source_sRGB; case Output::ColorProfileSource::ICC: return QtWaylandServer::kde_output_device_v2::color_profile_source_ICC; case Output::ColorProfileSource::EDID: return QtWaylandServer::kde_output_device_v2::color_profile_source_EDID; }; Q_UNREACHABLE(); }(); if (d->m_colorProfile != waylandColorProfileSource) { d->m_colorProfile = waylandColorProfileSource; const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendColorProfileSource(resource); d->sendDone(resource); } } } void OutputDeviceV2Interface::updateBrightness() { const uint32_t newBrightness = std::round(d->m_handle->brightnessSetting() * 10'000); if (d->m_brightness != newBrightness) { d->m_brightness = newBrightness; const auto clientResources = d->resourceMap(); for (const auto &resource : clientResources) { d->sendBrightness(resource); d->sendDone(resource); } } } OutputDeviceV2Interface *OutputDeviceV2Interface::get(wl_resource *native) { if (auto devicePrivate = resource_cast(native); devicePrivate && !devicePrivate->isGlobalRemoved()) { return devicePrivate->q; } return nullptr; } OutputDeviceModeV2InterfacePrivate::OutputDeviceModeV2InterfacePrivate(OutputDeviceModeV2Interface *q, std::shared_ptr handle) : QtWaylandServer::kde_output_device_mode_v2() , q(q) , m_handle(handle) , m_size(handle->size()) , m_refreshRate(handle->refreshRate()) , m_preferred(handle->flags() & OutputMode::Flag::Preferred) { } OutputDeviceModeV2Interface::OutputDeviceModeV2Interface(std::shared_ptr handle, QObject *parent) : QObject(parent) , d(new OutputDeviceModeV2InterfacePrivate(this, handle)) { } OutputDeviceModeV2Interface::~OutputDeviceModeV2Interface() = default; OutputDeviceModeV2InterfacePrivate::~OutputDeviceModeV2InterfacePrivate() { const auto map = resourceMap(); for (Resource *resource : map) { send_removed(resource->handle); } } OutputDeviceModeV2InterfacePrivate::Resource *OutputDeviceModeV2InterfacePrivate::createResource(OutputDeviceV2InterfacePrivate::Resource *output) { const auto modeResource = static_cast(add(output->client(), output->version())); modeResource->output = output; return modeResource; } OutputDeviceModeV2InterfacePrivate::Resource *OutputDeviceModeV2InterfacePrivate::findResource(OutputDeviceV2InterfacePrivate::Resource *output) const { const auto resources = resourceMap(); for (const auto &resource : resources) { auto modeResource = static_cast(resource); if (modeResource->output == output) { return resource; } } return nullptr; } OutputDeviceModeV2InterfacePrivate::Resource *OutputDeviceModeV2InterfacePrivate::kde_output_device_mode_v2_allocate() { return new ModeResource; } std::weak_ptr OutputDeviceModeV2Interface::handle() const { return d->m_handle; } void OutputDeviceModeV2InterfacePrivate::bindResource(wl_resource *resource) { send_size(resource, m_size.width(), m_size.height()); send_refresh(resource, m_refreshRate); if (m_preferred) { send_preferred(resource); } } OutputDeviceModeV2Interface *OutputDeviceModeV2Interface::get(wl_resource *native) { if (auto devicePrivate = resource_cast(native)) { return devicePrivate->q; } return nullptr; } } #include "moc_outputdevice_v2.cpp"