diff --git a/daemon/backends/CMakeLists.txt b/daemon/backends/CMakeLists.txt --- a/daemon/backends/CMakeLists.txt +++ b/daemon/backends/CMakeLists.txt @@ -12,6 +12,7 @@ upower/xrandrxcbhelper.cpp upower/udevqtclient.cpp upower/udevqtdevice.cpp + upower/ddcutilbrightness.cpp ) set_source_files_properties( @@ -60,6 +61,7 @@ ${XCB_XCB_LIBRARY} ${XCB_RANDR_LIBRARY} powerdevilcore + ddcutil ) install(TARGETS powerdevilupowerbackend DESTINATION ${PLUGIN_INSTALL_DIR}/kf5/powerdevil) diff --git a/daemon/backends/upower/ddcutilbrightness.h b/daemon/backends/upower/ddcutilbrightness.h --- a/daemon/backends/upower/ddcutilbrightness.h +++ b/daemon/backends/upower/ddcutilbrightness.h @@ -1,32 +1,53 @@ +/* This file is part of the KDE project + * Copyright (C) 2017 Dorian Vogel + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ #ifndef DDCUTILBRIGHTNESS_H #define DDCUTILBRIGHTNESS_H -#include +#include #include class DDCutilBrightness { - + public: DDCutilBrightness(); void detect(); bool isSupported() const; - long brightness() const; - long brightnessMax() const; + long brightness(); + long brightnessMax(); void setBrightness(long value); - + private: - - QList m_displayHandleList; - QList m_displayInfoList; - + + QVector m_displayHandleList; + QVector m_displayInfoList; + //Per display properties //destription mapped to vcp values for easy retrieval - QList*> m_descrToVcp_perDisp; - QList*>*> m_vcpTovcpValueWithDescr_perDisp; - + QVector > m_descrToVcp_perDisp; + QVector > > m_vcpTovcpValueWithDescr_perDisp; + + int m_lastBrightnessKnown; + int m_lastMaxBrightnessKnown; + }; #endif //DDCUTILBRIGHTNESS_H diff --git a/daemon/backends/upower/ddcutilbrightness.cpp b/daemon/backends/upower/ddcutilbrightness.cpp --- a/daemon/backends/upower/ddcutilbrightness.cpp +++ b/daemon/backends/upower/ddcutilbrightness.cpp @@ -1,175 +1,194 @@ +/* This file is part of the KDE project + * Copyright (C) 2017 Dorian Vogel + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + #include #include "ddcutilbrightness.h" DDCutilBrightness::DDCutilBrightness() { - QList m_displayHandleList = QList(); - QList m_displayInfoList = QList(); - - //QList m_parsedCapabilities_perDisp = QList(); - - QList*> m_descrToVcp_perDisp = QList*>(); - QList*>*> m_vcpTovcpValueWithDescr_perDisp = - QList*>*>(); + } -void DDCutilBrightness::detect(){ - +void DDCutilBrightness::detect() +{ DDCA_Status rc; DDCA_Display_Identifier did; DDCA_Display_Ref dref; - DDCA_Display_Handle dh = NULL; // initialize to avoid clang analyzer warning - - - - qCWarning(POWERDEVIL)<<"\nCheck for monitors using ddca_get_displays()...\n"; + DDCA_Display_Handle dh = nullptr; // initialize to avoid clang analyzer warning + + + + qCDebug(POWERDEVIL) << "Check for monitors using ddca_get_displays()..."; // Inquire about detected monitors. DDCA_Display_Info_List * dlist = ddca_get_displays(); - qCWarning(POWERDEVIL)<<"ddca_get_displays() returned "<< dlist; - qCWarning(POWERDEVIL)<ct << "display(s) were detected"; - for(int iDisp=0;iDispct;iDisp++) - { - - qCWarning(POWERDEVIL)<<"\nCreate a Display Identifier for display"<ct << "display(s) were detected"; + + for (int iDisp=0;iDispct;iDisp++){ + qCDebug(POWERDEVIL) << "Create a Display Identifier for display"<info[iDisp].model_name; - + m_displayInfoList.append(dlist->info[iDisp]); - + rc = ddca_create_dispno_display_identifier(iDisp+1, &did); // ddcutil uses 1 paded indexing for displays - + char * did_repr = ddca_repr_display_identifier(did); - - qCWarning(POWERDEVIL)<<"did="<vcp_code_ct << "capabilities parsed"; + + + m_descrToVcp_perDisp.append(QMap()); + m_vcpTovcpValueWithDescr_perDisp.append(QMap >() ); + //fill the feature description to vcp LUT + + Version_Feature_Info* featureInfo; + for (int iVcp=0;iVcpvcp_code_ct;iVcp++) { + + int vcpCode=parsedCapabilities->vcp_codes[iVcp].feature_code; + + m_vcpTovcpValueWithDescr_perDisp[iDisp].insert(vcpCode, QMap()); + + m_descrToVcp_perDisp[iDisp].insert( + QString(ddca_get_feature_name(vcpCode)), vcpCode); + + + ddca_get_feature_info_by_display(m_displayHandleList.at(iDisp), vcpCode, &featureInfo); + if (featureInfo == nullptr) { + continue; + } + qCDebug(POWERDEVIL) << featureInfo->feature_code<<":"<desc; + if ((featureInfo->feature_flags & DDCA_SIMPLE_NC) != DDCA_SIMPLE_NC) { + continue; } - else { - qCWarning(POWERDEVIL)<<"adding handle to list"; - m_displayHandleList.append(dh); - qCWarning(POWERDEVIL)<<"handles nb: "<vcp_code_ct << "capabilities have been parsed"; - - - m_descrToVcp_perDisp.append(new QMap); - m_vcpTovcpValueWithDescr_perDisp.append(new QMap*>); - //fill the feature description to vcp LUT - - - - Version_Feature_Info* featureInfo; - for(int iVcp=0;iVcpvcp_code_ct;iVcp++) - { - - int vcpCode=parsedCapabilities->vcp_codes[iVcp].feature_code; - - m_vcpTovcpValueWithDescr_perDisp.at(iDisp)->insert(vcpCode, new QMap); - - m_descrToVcp_perDisp.at(iDisp)->insert( - QString(ddca_get_feature_name(vcpCode)), vcpCode); - - - ddca_get_feature_info_by_display(m_displayHandleList.at(iDisp), vcpCode, &featureInfo); - if(featureInfo != NULL) - { - qCWarning(POWERDEVIL)<feature_code<<":"<desc; - if((featureInfo->feature_flags & DDCA_SIMPLE_NC) == DDCA_SIMPLE_NC) - { - for(int iVcpVal=0;featureInfo->sl_values[iVcpVal].value_code!=0;++iVcpVal) - { - - - qCWarning(POWERDEVIL)<<"\t"<sl_values[iVcpVal].value_code - <<":"<< featureInfo->sl_values[iVcpVal].value_name; - - bool thisVcpValIsSupported=false; - - for(int iSupportedVcpVal=0; iSupportedVcpValvcp_codes[iVcp].value_ct; iSupportedVcpVal++) - { - if(parsedCapabilities->vcp_codes[iVcp].values[iSupportedVcpVal] - ==featureInfo->sl_values[iVcpVal].value_code) - { - thisVcpValIsSupported=true; - } - } - - if(thisVcpValIsSupported) - { - m_vcpTovcpValueWithDescr_perDisp.at(iDisp)->value(vcpCode)->insert( - featureInfo->sl_values[iVcpVal].value_code, - featureInfo->sl_values[iVcpVal].value_name); - qCWarning(POWERDEVIL)<<"ADDED !"; - } - } + for (int iVcpVal=0;featureInfo->sl_values[iVcpVal].value_code!=0;++iVcpVal) { + + qCDebug(POWERDEVIL) << "\t"<sl_values[iVcpVal].value_code + <<":"<< featureInfo->sl_values[iVcpVal].value_name; + + bool thisVcpValIsSupported=false; + + for (int iSupportedVcpVal=0; iSupportedVcpValvcp_codes[iVcp].value_ct; iSupportedVcpVal++) { + if(parsedCapabilities->vcp_codes[iVcp].values[iSupportedVcpVal] + ==featureInfo->sl_values[iVcpVal].value_code) { + thisVcpValIsSupported=true; } - } - - } - qCWarning(POWERDEVIL)<<"done"; - //is this needed ? are variables created in the method automatically free'd ? - ddca_free_parsed_capabilities(parsedCapabilities); + + if (thisVcpValIsSupported) { + (m_vcpTovcpValueWithDescr_perDisp[iDisp])[vcpCode].insert( + featureInfo->sl_values[iVcpVal].value_code, + featureInfo->sl_values[iVcpVal].value_name); + } } } + //is this needed ? are variables created in the method automatically free'd ? + ddca_free_parsed_capabilities(parsedCapabilities); } - qCWarning(POWERDEVIL)<<"done with display"; } + bool DDCutilBrightness::isSupported() const { - return (m_displayHandleList.count()!=0); - + return !m_displayHandleList.isEmpty(); } -long DDCutilBrightness::brightness() const +long DDCutilBrightness::brightness() { - + //FIXME: gets value for display 1 + DDCA_Status rc; Single_Vcp_Value *returnValue; - - ddca_get_vcp_value(m_displayHandleList.at(0), - m_descrToVcp_perDisp.at(0)->value("Brightness"), - NON_TABLE_VCP_VALUE, &returnValue); - - return (long)returnValue->val.c.cur_val; + + rc = ddca_get_vcp_value(m_displayHandleList.at(0), + m_descrToVcp_perDisp.at(0).value("Brightness"), + NON_TABLE_VCP_VALUE, &returnValue); + qCDebug(POWERDEVIL) << "[DDCutilBrightness::brightness]: ddca_get_vcp_value returned" << rc; + + //check rc to prevent crash on wake from idle and the monitor has gone to powersave mode + if (rc == 0) { + m_lastBrightnessKnown = (long)returnValue->val.c.cur_val; + } + + return m_lastBrightnessKnown; } -long DDCutilBrightness::brightnessMax() const +long DDCutilBrightness::brightnessMax() { + DDCA_Status rc; Single_Vcp_Value *returnValue; - - ddca_get_vcp_value(m_displayHandleList.at(0), - m_descrToVcp_perDisp.at(0)->value("Brightness"), - NON_TABLE_VCP_VALUE, &returnValue); - - return (long) returnValue->val.c.max_val; - + + rc = ddca_get_vcp_value(m_displayHandleList.at(0), + m_descrToVcp_perDisp.at(0).value("Brightness"), + NON_TABLE_VCP_VALUE, &returnValue); + qCDebug(POWERDEVIL) << "[DDCutilBrightness::brightnessMax]: ddca_get_vcp_value returned" << rc; + + //check rc to prevent crash on wake from idle and the monitor has gone to powersave mode + if (rc == 0) { + m_lastMaxBrightnessKnown = (long)returnValue->val.c.max_val; + } + + return m_lastMaxBrightnessKnown; } void DDCutilBrightness::setBrightness(long value) { - qCDebug(POWERDEVIL)<<"[ddcutilbrightness] setting brightness to "<value("Brightness"), + DDCA_Status rc; + qCDebug(POWERDEVIL) << "[DDCutilBrightness]: setting brightness "< m_cachedBrightnessMap; XRandrBrightness *m_brightnessControl; XRandRXCBHelper *m_randrHelper; + DDCutilBrightness *m_ddcBrightnessControl; OrgFreedesktopUPowerInterface *m_upowerInterface; OrgFreedesktopUPowerKbdBacklightInterface *m_kbdBacklight; diff --git a/daemon/backends/upower/powerdevilupowerbackend.cpp b/daemon/backends/upower/powerdevilupowerbackend.cpp --- a/daemon/backends/upower/powerdevilupowerbackend.cpp +++ b/daemon/backends/upower/powerdevilupowerbackend.cpp @@ -38,6 +38,7 @@ #include "xrandrxcbhelper.h" #include "xrandrbrightness.h" +#include "ddcutilbrightness.h" #include "upowersuspendjob.h" #include "login1suspendjob.h" #include "udevqt.h" @@ -152,63 +153,83 @@ m_upowerInterface = new OrgFreedesktopUPowerInterface(UPOWER_SERVICE, "/org/freedesktop/UPower", QDBusConnection::systemBus(), this); m_brightnessControl = new XRandrBrightness(); if (!m_brightnessControl->isSupported()) { - qCDebug(POWERDEVIL) << "Falling back to helper to get brightness"; - - KAuth::Action brightnessAction("org.kde.powerdevil.backlighthelper.brightness"); - brightnessAction.setHelperId(HELPER_ID); - KAuth::ExecuteJob *brightnessJob = brightnessAction.execute(); - connect(brightnessJob, &KJob::result, this, - [this, brightnessJob] { - if (brightnessJob->error()) { - qCWarning(POWERDEVIL) << "org.kde.powerdevil.backlighthelper.brightness failed"; - qCDebug(POWERDEVIL) << brightnessJob->errorText(); - Q_EMIT brightnessSupportQueried(false); - return; - } - m_cachedBrightnessMap.insert(Screen, brightnessJob->data()["brightness"].toFloat()); - - KAuth::Action brightnessMaxAction("org.kde.powerdevil.backlighthelper.brightnessmax"); - brightnessMaxAction.setHelperId(HELPER_ID); - KAuth::ExecuteJob *brightnessMaxJob = brightnessMaxAction.execute(); - connect(brightnessMaxJob, &KJob::result, this, - [this, brightnessMaxJob] { - if (brightnessMaxJob->error()) { - qCWarning(POWERDEVIL) << "org.kde.powerdevil.backlighthelper.brightnessmax failed"; - qCDebug(POWERDEVIL) << brightnessMaxJob->errorText(); - } else { - m_brightnessMax = brightnessMaxJob->data()["brightnessmax"].toInt(); - } - - KAuth::Action syspathAction("org.kde.powerdevil.backlighthelper.syspath"); - syspathAction.setHelperId(HELPER_ID); - KAuth::ExecuteJob* syspathJob = syspathAction.execute(); - connect(syspathJob, &KJob::result, this, - [this, syspathJob] { - if (syspathJob->error()) { - qCWarning(POWERDEVIL) << "org.kde.powerdevil.backlighthelper.syspath failed"; - qCDebug(POWERDEVIL) << syspathJob->errorText(); - Q_EMIT brightnessSupportQueried(false); - return; - } - m_syspath = syspathJob->data()["syspath"].toString(); - m_syspath = QFileInfo(m_syspath).readLink(); + qCWarning(POWERDEVIL)<<"Xrandr not supported, trying ddc, helper"; + m_ddcBrightnessControl = new DDCutilBrightness(); + m_ddcBrightnessControl->detect(); + if (!m_ddcBrightnessControl->isSupported()) { + qCDebug(POWERDEVIL) << "Falling back to helper to get brightness"; + + KAuth::Action brightnessAction("org.kde.powerdevil.backlighthelper.brightness"); + brightnessAction.setHelperId(HELPER_ID); + KAuth::ExecuteJob *brightnessJob = brightnessAction.execute(); + connect(brightnessJob, &KJob::result, this, + [this, brightnessJob] { + if (brightnessJob->error()) { + qCWarning(POWERDEVIL) << "org.kde.powerdevil.backlighthelper.brightness failed"; + qCDebug(POWERDEVIL) << brightnessJob->errorText(); + Q_EMIT brightnessSupportQueried(false); + return; + } + m_cachedBrightnessMap.insert(Screen, brightnessJob->data()["brightness"].toFloat()); + + KAuth::Action brightnessMaxAction("org.kde.powerdevil.backlighthelper.brightnessmax"); + brightnessMaxAction.setHelperId(HELPER_ID); + KAuth::ExecuteJob *brightnessMaxJob = brightnessMaxAction.execute(); + connect(brightnessMaxJob, &KJob::result, this, + [this, brightnessMaxJob] { + if (brightnessMaxJob->error()) { + qCWarning(POWERDEVIL) << "org.kde.powerdevil.backlighthelper.brightnessmax failed"; + qCDebug(POWERDEVIL) << brightnessMaxJob->errorText(); + } else { + m_brightnessMax = brightnessMaxJob->data()["brightnessmax"].toInt(); + } - m_isLedBrightnessControl = m_syspath.contains(QLatin1String("/leds/")); - if (!m_isLedBrightnessControl) { - UdevQt::Client *client = new UdevQt::Client(QStringList("backlight"), this); - connect(client, SIGNAL(deviceChanged(UdevQt::Device)), SLOT(onDeviceChanged(UdevQt::Device))); + KAuth::Action syspathAction("org.kde.powerdevil.backlighthelper.syspath"); + syspathAction.setHelperId(HELPER_ID); + KAuth::ExecuteJob* syspathJob = syspathAction.execute(); + connect(syspathJob, &KJob::result, this, + [this, syspathJob] { + if (syspathJob->error()) { + qCWarning(POWERDEVIL) << "org.kde.powerdevil.backlighthelper.syspath failed"; + qCDebug(POWERDEVIL) << syspathJob->errorText(); + Q_EMIT brightnessSupportQueried(false); + return; + } + m_syspath = syspathJob->data()["syspath"].toString(); + m_syspath = QFileInfo(m_syspath).readLink(); + + m_isLedBrightnessControl = m_syspath.contains(QLatin1String("/leds/")); + if (!m_isLedBrightnessControl) { + UdevQt::Client *client = new UdevQt::Client(QStringList("backlight"), this); + connect(client, SIGNAL(deviceChanged(UdevQt::Device)), SLOT(onDeviceChanged(UdevQt::Device))); + } + + Q_EMIT brightnessSupportQueried(m_brightnessMax > 0); } - - Q_EMIT brightnessSupportQueried(m_brightnessMax > 0); - } - ); - syspathJob->start(); - } - ); - brightnessMaxJob->start(); + ); + syspathJob->start(); + } + ); + brightnessMaxJob->start(); + } + ); + brightnessJob->start(); + } + else{ + qCDebug(POWERDEVIL) << "Using DDCutillib"; + m_cachedBrightnessMap.insert(Screen, brightness(Screen)); + + const int duration = PowerDevilSettings::brightnessAnimationDuration(); + if (duration > 0 && brightnessMax() >= PowerDevilSettings::brightnessAnimationThreshold()) { + m_brightnessAnimation = new QPropertyAnimation(this); + m_brightnessAnimation->setTargetObject(this); + m_brightnessAnimation->setDuration(duration); + m_brightnessAnimation->setEasingCurve(QEasingCurve::InOutQuad); + connect(m_brightnessAnimation, &QPropertyAnimation::valueChanged, this, &PowerDevilUPowerBackend::animationValueChanged); + connect(m_brightnessAnimation, &QPropertyAnimation::finished, this, &PowerDevilUPowerBackend::slotScreenBrightnessChanged); } - ); - brightnessJob->start(); + Q_EMIT brightnessSupportQueried(true); + } } else { qCDebug(POWERDEVIL) << "Using XRandR"; m_randrHelper = XRandRXCBHelper::self(); @@ -398,7 +419,13 @@ //qCDebug(POWERDEVIL) << "Calling xrandr brightness"; result = (int) m_brightnessControl->brightness(); } - } else { + } else if (m_ddcBrightnessControl->isSupported()){ + if (m_brightnessAnimation && m_brightnessAnimation->state() == QPropertyAnimation::Running) { + result = m_brightnessAnimation->endValue().toInt(); + } else { + result = (int)m_ddcBrightnessControl->brightness(); + } + }else{ result = m_cachedBrightnessMap[Screen]; } qCDebug(POWERDEVIL) << "Screen brightness value: " << result; @@ -418,7 +445,9 @@ if (m_brightnessControl->isSupported()) { //qCDebug(POWERDEVIL) << "Calling xrandr brightness"; result = (int) m_brightnessControl->brightnessMax(); - } else { + } else if (m_ddcBrightnessControl->isSupported()){ + result = (int)m_ddcBrightnessControl->brightnessMax(); + }else{ result = m_brightnessMax; } qCDebug(POWERDEVIL) << "Screen brightness value max: " << result; @@ -445,6 +474,17 @@ } else { m_brightnessControl->setBrightness(value); } + } else if (m_ddcBrightnessControl->isSupported()){ + if (m_brightnessAnimation) { + m_brightnessAnimation->stop(); + disconnect(m_brightnessAnimation, &QPropertyAnimation::valueChanged, this, &PowerDevilUPowerBackend::animationValueChanged); + m_brightnessAnimation->setStartValue(brightness()); + m_brightnessAnimation->setEndValue(value); + connect(m_brightnessAnimation, &QPropertyAnimation::valueChanged, this, &PowerDevilUPowerBackend::animationValueChanged); + m_brightnessAnimation->start(); + } else { + m_ddcBrightnessControl->setBrightness((long)value); + } } else { //qCDebug(POWERDEVIL) << "Falling back to helper to set brightness"; KAuth::Action action("org.kde.powerdevil.backlighthelper.setbrightness"); @@ -471,7 +511,6 @@ } int value = brightness(Screen); - qCDebug(POWERDEVIL) << "Brightness changed!!"; if (value != m_cachedBrightnessMap[Screen] || m_isLedBrightnessControl) { m_cachedBrightnessMap[Screen] = value; onBrightnessChanged(Screen, value, brightnessMax(Screen)); @@ -674,5 +713,12 @@ void PowerDevilUPowerBackend::animationValueChanged(const QVariant &value) { - m_brightnessControl->setBrightness(value.toInt()); + if (m_brightnessControl->isSupported()) { + m_brightnessControl->setBrightness(value.toInt()); + }else if (m_ddcBrightnessControl->isSupported()) { + m_ddcBrightnessControl->setBrightness(value.toInt()); + } + else{ + qCInfo(POWERDEVIL)<<"PowerDevilUPowerBackend::animationValueChanged: brightness control not supported"; + } }