File indexing completed on 2024-05-12 05:38:44

0001 /*  This file is part of the KDE project
0002  *    SPDX-FileCopyrightText: 2017 Dorian Vogel <dorianvogel@gmail.com>
0003  *
0004  *    SPDX-License-Identifier: LGPL-2.0-only
0005  *
0006  */
0007 
0008 #include "ddcutilbrightness.h"
0009 
0010 #include <powerdevil_debug.h>
0011 
0012 #ifdef WITH_DDCUTIL
0013 #include <ddcutil_macros.h> // for DDCUTIL_V{MAJOR,MINOR,MICRO}
0014 #define DDCUTIL_VERSION QT_VERSION_CHECK(DDCUTIL_VMAJOR, DDCUTIL_VMINOR, DDCUTIL_VMICRO)
0015 #endif
0016 
0017 #include <chrono>
0018 #include <span>
0019 
0020 using namespace std::chrono_literals;
0021 
0022 DDCutilBrightness::DDCutilBrightness(QObject *parent)
0023     : QObject(parent)
0024 {
0025 }
0026 
0027 DDCutilBrightness::~DDCutilBrightness()
0028 {
0029 }
0030 
0031 void DDCutilBrightness::detect()
0032 {
0033 #ifdef WITH_DDCUTIL
0034 
0035     if (qEnvironmentVariableIntValue("POWERDEVIL_NO_DDCUTIL") > 0) {
0036         return;
0037     }
0038 
0039 #if DDCUTIL_VERSION >= QT_VERSION_CHECK(2, 0, 0)
0040     qCDebug(POWERDEVIL) << "Initializing ddcutil API (create ddcutil configuration file for tracing & more)...";
0041     static DDCA_Status init_status = -1; // negative indicates error condition
0042     if (init_status < 0) {
0043         init_status = ddca_init(nullptr, DDCA_SYSLOG_NOTICE, DDCA_INIT_OPTIONS_CLIENT_OPENED_SYSLOG);
0044     }
0045     if (init_status < 0) {
0046         qCWarning(POWERDEVIL) << "Could not initialize ddcutil API. Not using DDC for monitor brightness.";
0047         return;
0048     }
0049 #endif
0050     qCDebug(POWERDEVIL) << "Check for monitors using ddca_get_display_info_list2()...";
0051     // Inquire about detected monitors.
0052     DDCA_Display_Info_List *displays = nullptr;
0053     ddca_get_display_info_list2(false, &displays);
0054     qCInfo(POWERDEVIL) << "[DDCutilBrightness]" << displays->ct << "display(s) were detected";
0055 
0056     for (auto &displayInfo : std::span(displays->info, displays->ct)) {
0057         DDCA_Display_Handle displayHandle = nullptr;
0058         DDCA_Status rc;
0059 
0060         qCDebug(POWERDEVIL) << "Opening the display reference, creating a display handle...";
0061         if ((rc = ddca_open_display2(displayInfo.dref, true, &displayHandle))) {
0062             qCWarning(POWERDEVIL) << "[DDCutilBrightness]: ddca_open_display2" << rc;
0063             continue;
0064         }
0065 
0066         auto display = std::make_unique<DDCutilDisplay>(displayInfo, displayHandle);
0067 
0068         if (!display->supportsBrightness()) {
0069             qCDebug(POWERDEVIL) << "[DDCutilBrightness]: This monitor does not seem to support brightness control";
0070             continue;
0071         }
0072 
0073         qCDebug(POWERDEVIL) << "Display supports Brightness, adding handle to list";
0074         QString displayId = generateDisplayId(displayInfo);
0075         qCDebug(POWERDEVIL) << "Create a Display Identifier:" << displayId << "for display:" << displayInfo.model_name;
0076 
0077         if (displayId.isEmpty()) {
0078             qCWarning(POWERDEVIL) << "Cannot generate ID for display with model name:" << displayInfo.model_name;
0079             continue;
0080         }
0081 
0082         m_displays[displayId] = std::move(display);
0083         m_displayIds += displayId;
0084     }
0085     ddca_free_display_info_list(displays);
0086 #else
0087     qCInfo(POWERDEVIL) << "[DDCutilBrightness] compiled without DDC/CI support";
0088     return;
0089 #endif
0090 }
0091 
0092 QStringList DDCutilBrightness::displayIds() const
0093 {
0094     return m_displayIds;
0095 }
0096 
0097 bool DDCutilBrightness::isSupported() const
0098 {
0099 #ifdef WITH_DDCUTIL
0100     return !m_displayIds.isEmpty();
0101 #else
0102     return false;
0103 #endif
0104 }
0105 
0106 int DDCutilBrightness::brightness(const QString &displayId)
0107 {
0108     if (!m_displayIds.contains(displayId)) {
0109         return -1;
0110     }
0111 
0112     return m_displays[displayId]->brightness();
0113 }
0114 
0115 int DDCutilBrightness::maxBrightness(const QString &displayId)
0116 {
0117     if (!m_displayIds.contains(displayId)) {
0118         return -1;
0119     }
0120 
0121     return m_displays[displayId]->maxBrightness();
0122 }
0123 
0124 void DDCutilBrightness::setBrightness(const QString &displayId, int value)
0125 {
0126     if (!m_displayIds.contains(displayId)) {
0127         return;
0128     }
0129 
0130     qCDebug(POWERDEVIL) << "setBrightness: displayId:" << displayId << "brightness:" << value;
0131     m_displays[displayId]->setBrightness(value);
0132 }
0133 
0134 #ifdef WITH_DDCUTIL
0135 QString DDCutilBrightness::generateDisplayId(const DDCA_Display_Info &displayInfo) const
0136 {
0137     switch (displayInfo.path.io_mode) {
0138     case DDCA_IO_I2C:
0139         return QString("i2c:%1").arg(displayInfo.path.path.i2c_busno);
0140     case DDCA_IO_USB:
0141         return QString("usb:%1").arg(displayInfo.path.path.hiddev_devno);
0142     }
0143     return QString();
0144 }
0145 #endif
0146 
0147 #include "moc_ddcutilbrightness.cpp"