diff --git a/CMakeLists.txt b/CMakeLists.txt index 7cea1647..b6aca6cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,78 +1,79 @@ cmake_minimum_required(VERSION 3.0) project(PowerDevil) set(PROJECT_VERSION "5.15.80") set(PROJECT_VERSION_MAJOR 5) set(QT_MIN_VERSION "5.11.0") set(KF5_MIN_VERSION "5.56.0") find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) include(ECMSetupVersion) include(FeatureSummary) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Widgets DBus X11Extras) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Activities Auth IdleTime Config DBusAddons Solid I18n GlobalAccel KIO NotifyConfig Wayland DocTools Crash Notifications) find_package(KF5Screen CONFIG REQUIRED) find_package(LibKWorkspace CONFIG REQUIRED) find_package(KF5BluezQt ${KF5_MIN_VERSION}) set_package_properties(KF5BluezQt PROPERTIES DESCRIPTION "Qt wrapper for BlueZ 5 DBus API" TYPE OPTIONAL PURPOSE "Support for wireless energy saving actions" ) find_package(KF5NetworkManagerQt ${KF5_MIN_VERSION}) set_package_properties(KF5NetworkManagerQt PROPERTIES DESCRIPTION "Qt wrapper for NetworkManager API" TYPE OPTIONAL PURPOSE "Support for wireless energy saving actions" ) set(HAVE_WIRELESS_SUPPORT FALSE) if(KF5NetworkManagerQt_FOUND AND KF5BluezQt_FOUND) set(HAVE_WIRELESS_SUPPORT TRUE) endif() add_feature_info( "Wireless power saving" HAVE_WIRELESS_SUPPORT "Support turning off signal-transmitting devices to save energy" ) find_package(LibKWorkspace ${PROJECT_VERSION} REQUIRED) find_package(UDev REQUIRED) find_package(XCB REQUIRED COMPONENTS XCB RANDR DPMS) -option(WITH_DDCUTIL "DDCUtil library support" OFF) -if(WITH_DDCUTIL) - find_package(DDCUtil REQUIRED) - set_package_properties(DDCUtil - PROPERTIES DESCRIPTION "DDCUtil library support" - TYPE OPTIONAL - PURPOSE "Set monitor settings over DDC/CI channel" - ) +option(HAVE_DDCUTIL "DDCUtil library support" OFF) +if(HAVE_DDCUTIL) + find_package(DDCUtil REQUIRED) + add_compile_definitions(WITH_DDCUTIL) + set_package_properties(DDCUtil + PROPERTIES DESCRIPTION "DDCUtil library support" + TYPE OPTIONAL + PURPOSE "Set monitor settings over DDC/CI channel" + ) else() - add_feature_info("DDCUtil" "Off" "DDCUtil library support is disabled by default as recomemded by authors, add -DWITH_DDCUTIL=On to enable") + add_feature_info("DDCUtil" HAVE_DDCUTIL "DDCUtil library support is disabled by default as recomended by authors, add -DHAVE_DDCUTIL=On to enable") endif() include_directories ( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/daemon ) add_definitions(-DQT_NO_KEYWORDS) add_subdirectory(daemon) add_subdirectory(kcmodule) add_subdirectory(doc) install( FILES powerdevil.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFY5RCDIR} ) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/backends/upower/ddcutilbrightness.cpp b/backends/upower/ddcutilbrightness.cpp new file mode 100644 index 00000000..e712c05a --- /dev/null +++ b/backends/upower/ddcutilbrightness.cpp @@ -0,0 +1,169 @@ +/* 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() + : m_usedVcp({0x10}) +{ + m_setBrightnessEventFilter.setInterval(100); + m_setBrightnessEventFilter.setSingleShot(true); + connect(&m_setBrightnessEventFilter, &QTimer::timeout, this, &DDCutilBrightness::setBrightnessAfterFilter); +} + +void DDCutilBrightness::detect() +{ +#ifdef WITH_DDCUTIL + DDCA_Status rc; + + qCDebug(POWERDEVIL) << "Check for monitors using ddca_get_displays()..."; + // Inquire about detected monitors. + DDCA_Display_Info_List * dlist = nullptr; + ddca_get_display_info_list2(true, &dlist); + qCInfo(POWERDEVIL) << "[DDCutilBrightness] " << dlist->ct << "display(s) were detected"; + + for (int iDisp = 0; iDisp < dlist->ct; ++iDisp) { + DDCA_Display_Handle dh = nullptr; // initialize to avoid clang analyzer warning + + qCDebug(POWERDEVIL) << "Create a Display Identifier for display"<info[iDisp].model_name; + + m_displayInfoList.append(dlist->info[iDisp]); + + qCDebug(POWERDEVIL) << "Opening the display reference, creating a display handle..."; + rc = ddca_open_display2(dlist->info[iDisp].dref, true, &dh); + if (rc != 0) { + qCWarning(POWERDEVIL) << "[DDCutilBrightness]: ddct_open_display"<< rc; + continue; + } + + DDCA_Feature_List vcpList; + ddca_get_feature_list_by_dref(DDCA_SUBSET_COLOR, dh, false, &vcpList); + qCDebug(POWERDEVIL) << "ddca_feature_list: "<< ddca_feature_list_string(&vcpList, "0x", ","); + QVector tmpVcpList; + for (int iVcp = 0; iVcp < m_usedVcp.count(); ++iVcp) { + DDCA_Non_Table_Vcp_Value returnValue; + rc = ddca_get_non_table_vcp_value(dh,m_usedVcp.value(iVcp), &returnValue); + + if (rc < 0) { + qCDebug(POWERDEVIL) << "[DDCutilBrightness]: This monitor does not seem to support " << m_usedVcp[iVcp]; + } else { + qCDebug(POWERDEVIL) << "[DDCutilBrightness]: This monitor supports " << m_usedVcp[iVcp]; + tmpVcpList.append(m_usedVcp.value(iVcp)); + } + } + //we only store displays that actually support the features we want. + if (tmpVcpList.contains(0x10)) { + qCDebug(POWERDEVIL) << "Display supports Brightness, adding handle to list"; + m_displayHandleList.append(dh); + m_supportedVcp_perDisp.value(iDisp).append(tmpVcpList); + } + } +#else + qCInfo(POWERDEVIL) << "[DDCutilBrightness] compiled without DDC/CI support"; + return; +#endif +} + +bool DDCutilBrightness::isSupported() const +{ +#ifdef WITH_DDCUTIL + return !m_displayHandleList.isEmpty(); +#else + return false; +#endif +} + +long DDCutilBrightness::brightness() +{ +#ifdef WITH_DDCUTIL + //we check whether the timer is running, this means we received new values but did not send them yet to the monitor + //not checking that results in the brightness slider jump to the previous value when changing. + if (m_setBrightnessEventFilter.isActive()) { + m_lastBrightnessKnown = m_tmpCurrentBrightness; + } else { //FIXME: gets value for display 1 + DDCA_Status rc; + DDCA_Non_Table_Vcp_Value returnValue; + + rc = ddca_get_non_table_vcp_value(m_displayHandleList.at(0), + 0x10, &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.sh <<8|returnValue.sl); + } + } + return m_lastBrightnessKnown; +#else + return 0; +#endif +} + +long DDCutilBrightness::brightnessMax() +{ +#ifdef WITH_DDCUTIL + DDCA_Status rc; + DDCA_Non_Table_Vcp_Value returnValue; + + rc = ddca_get_non_table_vcp_value(m_displayHandleList.at(0) + , 0x10, &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.mh <<8|returnValue.ml); + } + + return m_lastMaxBrightnessKnown; +#else + return 100.0; +#endif +} + +void DDCutilBrightness::setBrightness(long value) +{ + m_tmpCurrentBrightness = value; + qCDebug(POWERDEVIL) << "[DDCutilBrightness]: saving brightness value: " << value; + m_setBrightnessEventFilter.start(); +} + +void DDCutilBrightness::setBrightnessAfterFilter() +{ +#ifdef WITH_DDCUTIL + DDCA_Status rc; + for (int iDisp = 0; iDisp < m_displayHandleList.count(); ++iDisp) { //FIXME: we set the same brightness to all monitors, plugin architecture needed + qCDebug(POWERDEVIL) << "[DDCutilBrightness]: setting brightness "<> 8; + uint8_t newsl = (uint16_t)m_tmpCurrentBrightness & 0x00ff; + rc = ddca_set_non_table_vcp_value(m_displayHandleList.at(iDisp), 0x10, + newsh, newsl); + + if (rc < 0) { + qCWarning(POWERDEVIL) << "[DDCutilBrightness::setBrightness] failed, trying to detect()"; + detect(); + } else { + m_lastBrightnessKnown = m_tmpCurrentBrightness; + } + } +#else + return; +#endif +} diff --git a/daemon/backends/upower/ddcutilbrightness.h b/backends/upower/ddcutilbrightness.h similarity index 92% rename from daemon/backends/upower/ddcutilbrightness.h rename to backends/upower/ddcutilbrightness.h index 4c029641..885a3b0e 100644 --- a/daemon/backends/upower/ddcutilbrightness.h +++ b/backends/upower/ddcutilbrightness.h @@ -1,62 +1,61 @@ /* 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 #ifdef WITH_DDCUTIL #include #endif class DDCutilBrightness: public QObject { Q_OBJECT public: DDCutilBrightness(); void detect(); bool isSupported() const; long brightness(); long brightnessMax(); void setBrightness(long value); private Q_SLOTS: void setBrightnessAfterFilter(); private: #ifdef WITH_DDCUTIL QVector m_displayHandleList; QVector m_displayInfoList; #endif //ifdef WITH_DDCUTIL //Per display properties //destription mapped to vcp values for easy retrieval - QVector > m_descrToVcp_perDisp; - QVector > > m_vcpTovcpValueWithDescr_perDisp; - + QVector m_usedVcp; + QVector> m_supportedVcp_perDisp; long m_tmpCurrentBrightness; QTimer m_setBrightnessEventFilter; int m_lastBrightnessKnown; int m_lastMaxBrightnessKnown; }; #endif //DDCUTILBRIGHTNESS_H diff --git a/daemon/backends/upower/ddcutilbrightness.cpp b/daemon/backends/upower/ddcutilbrightness.cpp deleted file mode 100644 index 70d316ba..00000000 --- a/daemon/backends/upower/ddcutilbrightness.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* 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() -{ - m_setBrightnessEventFilter.setInterval(100); - m_setBrightnessEventFilter.setSingleShot(true); - connect(&m_setBrightnessEventFilter, &QTimer::timeout, this, &DDCutilBrightness::setBrightnessAfterFilter); -} - -void DDCutilBrightness::detect() -{ -#ifndef WITH_DDCUTIL - qCInfo(POWERDEVIL) << "[DDCutilBrightness] compiled without DDC/CI support"; - return; -#else - DDCA_Status rc; - - qCDebug(POWERDEVIL) << "Check for monitors using ddca_get_displays()..."; - // Inquire about detected monitors. - DDCA_Display_Info_List * dlist = ddca_get_display_info_list(); - qCDebug(POWERDEVIL) << "ddca_get_display_info_list() returned "<< dlist; - qCInfo(POWERDEVIL) << "[DDCutilBrightness] " << dlist->ct << "display(s) were detected"; - - for (int iDisp=0;iDispct;iDisp++) { - DDCA_Display_Identifier did; - DDCA_Display_Ref dref; - DDCA_Display_Handle dh = nullptr; // initialize to avoid clang analyzer warning - - 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_did_repr(did); - - qCDebug(POWERDEVIL) << "did="<vcp_code_ct << "capabilities parsed"; - - - m_descrToVcp_perDisp.append(QMap()); - m_vcpTovcpValueWithDescr_perDisp.append(QMap >() ); - //fill the feature description to vcp LUT - - DDCA_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; - } - 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; - } - } - - if (thisVcpValIsSupported) { - (m_vcpTovcpValueWithDescr_perDisp[iDisp])[vcpCode].insert( - featureInfo->sl_values[iVcpVal].value_code, - featureInfo->sl_values[iVcpVal].value_name); - } - } - } - ddca_free_display_identifier(did); - ddca_free_parsed_capabilities(parsedCapabilities); - } -#endif -} - - -bool DDCutilBrightness::isSupported() const -{ -#ifndef WITH_DDCUTIL - return false; -#else - return !m_displayHandleList.isEmpty(); -#endif -} - - -long DDCutilBrightness::brightness() -{ -#ifdef WITH_DDCUTIL - //we check whether the timer is running, this means we received new values but did not send them yet to the monitor - //not checking that results in the brightness slider jump to the previous vqlue when changing. - if(m_setBrightnessEventFilter.isActive()) { - m_lastBrightnessKnown = m_tmpCurrentBrightness; - } - else { //FIXME: gets value for display 1 - DDCA_Status rc; - DDCA_Single_Vcp_Value *returnValue; - - rc = ddca_get_vcp_value(m_displayHandleList.at(0), - m_descrToVcp_perDisp.at(0).value("Brightness"), - DDCA_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; -#else - return 0; -#endif -} - -long DDCutilBrightness::brightnessMax() -{ -#ifdef WITH_DDCUTIL - DDCA_Status rc; - DDCA_Single_Vcp_Value *returnValue; - - rc = ddca_get_vcp_value(m_displayHandleList.at(0), - m_descrToVcp_perDisp.at(0).value("Brightness"), - DDCA_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; -#else - return 100.0; -#endif -} - -void DDCutilBrightness::setBrightness(long value) -{ - m_tmpCurrentBrightness = value; - qCDebug(POWERDEVIL) << "[DDCutilBrightness]: saving brightness value: " << value; - m_setBrightnessEventFilter.start(); -} - -void DDCutilBrightness::setBrightnessAfterFilter() -{ -#ifdef WITH_DDCUTIL - DDCA_Status rc; - for (int iDisp=0;iDisp