From 126c0bbd4b8310234df7f64ed0be0b3a90aa9c6b Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Fri, 11 Jun 2021 03:15:40 +0300 Subject: [PATCH] powerdevil: use X11 video mode extension as fallback for brightness control Signed-off-by: Ivailo Monev --- CMakeLists.txt | 1 + ConfigureChecks.cmake | 1 + appveyor.yml | 2 +- config-X11.h.cmake | 3 + powerdevil/daemon/BackendConfig.cmake | 17 ++- .../upower/powerdevilupowerbackend.cpp | 37 +++++- .../backends/upower/powerdevilupowerbackend.h | 6 + .../daemon/backends/upower/xf86vmodegamma.cpp | 108 ++++++++++++++++++ .../daemon/backends/upower/xf86vmodegamma.h | 43 +++++++ .../daemon/backends/upower/xlibandxrandr.h | 4 - .../backends/upower/xrandrbrightness.cpp | 61 +++++----- 11 files changed, 237 insertions(+), 46 deletions(-) create mode 100644 powerdevil/daemon/backends/upower/xf86vmodegamma.cpp create mode 100644 powerdevil/daemon/backends/upower/xf86vmodegamma.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1881d974..e7d34e53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,7 @@ if(Q_WS_X11) add_feature_info("libXft" X11_Xft_FOUND "The X11 font API library may be used by kfontinst KCM") add_feature_info("libXinerama" X11_Xinerama_FOUND "The X11 XINERAMA extension library may be used by ksplash") add_feature_info("libXRes" X11_XRes_FOUND "The X Resource library may be used by ksysguard") + add_feature_info("libxf86vmode" X11_xf86vmode_FOUND "The X video mode extension library used by powerdevil") if(NOT X11_Xdamage_FOUND) message(FATAL_ERROR "The X11 damaged region extension library was not found. Required for compositing support in KWin.") diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index fb13c6c2..cf8861d7 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -64,6 +64,7 @@ macro_bool_to_01(X11_xf86misc_FOUND HAVE_XF86MISC) # kcontrol/keyboard macro_bool_to_01(X11_dpms_FOUND HAVE_DPMS) # powerdevil macro_bool_to_01(X11_XSync_FOUND HAVE_XSYNC) # kwin macro_bool_to_01(X11_XRes_FOUND HAVE_XRES) # ksysguard +macro_bool_to_01(X11_xf86vmode_FOUND HAVE_XF86VMODE) # powerdevil check_function_exists(setpriority HAVE_SETPRIORITY) # kscreenlocker diff --git a/appveyor.yml b/appveyor.yml index 93409516..f9892f19 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,7 +15,7 @@ build_script: sudo apt-get update -qq sudo apt-get install -qq cmake katie-dev katanalibs \ - katana-baseapps xorg-dev libnm-dev libqalculate-dev \ + katana-baseapps xorg-dev libnm-dev libqalculate-dev libxxf86vm-dev \ libx11-xcb-dev libxcb-icccm4-dev libxcb-composite0-dev libxcb-damage0-dev \ libxcb-xfixes0-dev libxcb-render0-dev libxcb-randr0-dev libxcb-shape0-dev \ libxcb-shape0-dev libxcb-shm0-dev libxcb-sync-dev libxcb-image0-dev \ diff --git a/config-X11.h.cmake b/config-X11.h.cmake index ef861d8a..167de9d5 100644 --- a/config-X11.h.cmake +++ b/config-X11.h.cmake @@ -39,3 +39,6 @@ /* Define if you have the XRes extension */ #cmakedefine HAVE_XRES 1 + +/* Define if you have the xf86vmode extension */ +#cmakedefine HAVE_XF86VMODE diff --git a/powerdevil/daemon/BackendConfig.cmake b/powerdevil/daemon/BackendConfig.cmake index 6e5bdfc6..7d27223e 100644 --- a/powerdevil/daemon/BackendConfig.cmake +++ b/powerdevil/daemon/BackendConfig.cmake @@ -3,9 +3,15 @@ ########################## UPower Backend ##################################### -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/backends/upower - ${X11_INCLUDE_DIR} - ${X11_Xrandr_INCLUDE_PATH}) +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/backends/upower + ${X11_INCLUDE_DIR} + ${X11_Xrandr_INCLUDE_PATH} +) + +if(X11_xf86vmode_FOUND) + include_directories(${X11_xf86vmode_INCLUDE_PATH}) +endif() set(powerdevilupowerbackend_SRCS backends/upower/upowersuspendjob.cpp @@ -34,6 +40,11 @@ upower_kbdbacklight_interface) set(powerdevilupowerbackend_LIBS ${X11_LIBRARIES} ${QT_QTGUI_LIBRARY} ${X11_Xrandr_LIB} ${KDE4_KDEUI_LIBS}) +if(X11_xf86vmode_FOUND) + set(powerdevilupowerbackend_SRCS ${powerdevilupowerbackend_SRCS} backends/upower/xf86vmodegamma.cpp) + set(powerdevilupowerbackend_LIBS ${X11_Xxf86vm_LIB} ${X11_Xrandr_LIB}) +endif() + ########################## Daemon variables ################################ set(POWERDEVIL_BACKEND_SRCS ${powerdevilupowerbackend_SRCS}) diff --git a/powerdevil/daemon/backends/upower/powerdevilupowerbackend.cpp b/powerdevil/daemon/backends/upower/powerdevilupowerbackend.cpp index fbcaadeb..64491452 100644 --- a/powerdevil/daemon/backends/upower/powerdevilupowerbackend.cpp +++ b/powerdevil/daemon/backends/upower/powerdevilupowerbackend.cpp @@ -37,6 +37,10 @@ #include "upowersuspendjob.h" #include "login1suspendjob.h" +#ifdef HAVE_XF86VMODE +#include "xf86vmodegamma.h" +#endif + bool checkSystemdVersion(uint requiredVersion) { @@ -57,8 +61,11 @@ bool checkSystemdVersion(uint requiredVersion) PowerDevilUPowerBackend::PowerDevilUPowerBackend(QObject* parent) : BackendInterface(parent), - m_brightnessControl(0), m_kbdMaxBrightness(0), - m_lidIsPresent(false), m_lidIsClosed(false), m_onBattery(false) + m_brightnessControl(0), m_randrHelper(0), +#ifdef HAVE_XF86VMODE + m_gammaControl(0), +#endif + m_kbdMaxBrightness(0), m_lidIsPresent(false), m_lidIsClosed(false), m_onBattery(false) { } @@ -66,6 +73,9 @@ PowerDevilUPowerBackend::PowerDevilUPowerBackend(QObject* parent) PowerDevilUPowerBackend::~PowerDevilUPowerBackend() { delete m_brightnessControl; +#ifdef HAVE_XF86VMODE + delete m_gammaControl; +#endif } bool PowerDevilUPowerBackend::isAvailable() @@ -151,6 +161,16 @@ void PowerDevilUPowerBackend::init() screenBrightnessAvailable = true; } +#ifdef HAVE_XF86VMODE + if (!m_brightnessControl->isSupported()) { + m_gammaControl = new XF86VModeGamma(); + if (m_gammaControl->isSupported()) { + kDebug() << "Using X Video Mode"; + screenBrightnessAvailable = true; + } + } +#endif + // Capabilities setCapabilities(SignalResumeFromSuspend); @@ -306,9 +326,15 @@ float PowerDevilUPowerBackend::brightness(PowerDevil::BackendInterface::Brightne if (type == Screen) { if (m_brightnessControl->isSupported()) { - //kDebug() << "Calling xrandr brightness"; + kDebug() << "Calling XRandr brightness"; result = m_brightnessControl->brightness(); } +#ifdef HAVE_XF86VMODE + else if (m_gammaControl->isSupported()) { + kDebug() << "Calling XF86VidMode gamma"; + result = m_gammaControl->gamma(); + } +#endif kDebug() << "Screen brightness: " << result; } else if (type == Keyboard) { kDebug() << "Kbd backlight brightness: " << m_kbdBacklight->GetBrightness(); @@ -326,6 +352,11 @@ bool PowerDevilUPowerBackend::setBrightness(float brightnessValue, PowerDevil::B if (m_brightnessControl->isSupported()) { m_brightnessControl->setBrightness(brightnessValue); success = true; +#ifdef HAVE_XF86VMODE + } else if (m_gammaControl->isSupported()) { + m_gammaControl->setGamma(brightnessValue); + success = true; +#endif } else { success = false; } diff --git a/powerdevil/daemon/backends/upower/powerdevilupowerbackend.h b/powerdevil/daemon/backends/upower/powerdevilupowerbackend.h index ab078a37..48375130 100644 --- a/powerdevil/daemon/backends/upower/powerdevilupowerbackend.h +++ b/powerdevil/daemon/backends/upower/powerdevilupowerbackend.h @@ -22,6 +22,8 @@ #ifndef POWERDEVILUPOWERBACKEND_H #define POWERDEVILUPOWERBACKEND_H +#include + #include #include @@ -44,6 +46,7 @@ class UdevHelper; class XRandRX11Helper; class XRandrBrightness; +class XF86VModeGamma; class KDE_EXPORT PowerDevilUPowerBackend : public PowerDevil::BackendInterface { @@ -88,6 +91,9 @@ private: QMap m_cachedBrightnessMap; XRandrBrightness *m_brightnessControl; XRandRX11Helper *m_randrHelper; +#ifdef HAVE_XF86VMODE + XF86VModeGamma *m_gammaControl; +#endif OrgFreedesktopUPowerInterface *m_upowerInterface; OrgFreedesktopUPowerKbdBacklightInterface *m_kbdBacklight; diff --git a/powerdevil/daemon/backends/upower/xf86vmodegamma.cpp b/powerdevil/daemon/backends/upower/xf86vmodegamma.cpp new file mode 100644 index 00000000..3d17a7c7 --- /dev/null +++ b/powerdevil/daemon/backends/upower/xf86vmodegamma.cpp @@ -0,0 +1,108 @@ +/* This file is part of the KDE project + * Copyright (C) 2021 Ivailo Monev + * + * 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 "xf86vmodegamma.h" + +#include + +#include + +// for reference: +// https://cgit.freedesktop.org/xorg/app/xgamma/plain/xgamma.c + +// 50 means normal screen gamma, anything lower than that should make it darker +// and higher should make it brighter +static const float xgammaratio = 50.0; + +XF86VModeGamma::XF86VModeGamma() + : m_supported(false) +{ + int majorversion, minorversion; + if (!XF86VidModeQueryVersion(m_x11info.display(), &majorversion, &minorversion)) { + kWarning() << "XF86VidMode version query failed"; + return; + } + + int eventbase, errorbase; + if (!XF86VidModeQueryExtension(m_x11info.display(), &eventbase, &errorbase)) { + kWarning() << "XF86VidMode extension missing"; + return; + } + Q_UNUSED(eventbase); + Q_UNUSED(errorbase); + + // same version requirement as xgamma application + if (majorversion < 2) { + kWarning() << "XF86VidMode version too old" << majorversion << minorversion; + return; + } + + m_supported = true; +} + +XF86VModeGamma::~XF86VModeGamma() +{ +} + +bool XF86VModeGamma::isSupported() const +{ + return m_supported; +} + +float XF86VModeGamma::gamma() const +{ + float result = 0; + + if (!m_supported) { + return result; + } + + XF86VidModeGamma xgamma; + if (!XF86VidModeGetGamma(m_x11info.display(), m_x11info.screen(), &xgamma)) { + kWarning() << "Could not query gamma via XF86VidMode"; + return result; + } + // result should be in the [0-100] range + result = (xgammaratio * xgamma.red * xgamma.green * xgamma.blue); + + return result; +} + +void XF86VModeGamma::setGamma(float gamma) +{ + if (!m_supported) { + return; + } + + XF86VidModeGamma xgamma; + // in case new member is added + ::memset(&xgamma, 0, sizeof(XF86VidModeGamma)); + // values should be in the [0.1-10.0] range + xgamma.red = (gamma / xgammaratio); + xgamma.green = (gamma / xgammaratio); + xgamma.blue = (gamma / xgammaratio); + if (!XF86VidModeSetGamma(m_x11info.display(), m_x11info.screen(), &xgamma)) { + kWarning() << "Could not set gamma via XF86VidMode"; + return; + } + + XSync(m_x11info.display(), False); +} diff --git a/powerdevil/daemon/backends/upower/xf86vmodegamma.h b/powerdevil/daemon/backends/upower/xf86vmodegamma.h new file mode 100644 index 00000000..8da3f43a --- /dev/null +++ b/powerdevil/daemon/backends/upower/xf86vmodegamma.h @@ -0,0 +1,43 @@ +/* This file is part of the KDE project + * Copyright (C) 2021 Ivailo Monev + * + * 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 XF86VMODEGAMMA_H +#define XF86VMODEGAMMA_H + +#include + +#include +#include +#include + +class XF86VModeGamma +{ +public: + XF86VModeGamma(); + ~XF86VModeGamma(); + bool isSupported() const; + float gamma() const; + void setGamma(float gamma); + +private: + bool m_supported; + QX11Info m_x11info; +}; + +#endif // XF86VMODEGAMMA_H diff --git a/powerdevil/daemon/backends/upower/xlibandxrandr.h b/powerdevil/daemon/backends/upower/xlibandxrandr.h index 0dab3672..9a52eb06 100644 --- a/powerdevil/daemon/backends/upower/xlibandxrandr.h +++ b/powerdevil/daemon/backends/upower/xlibandxrandr.h @@ -23,11 +23,7 @@ extern "C" { #include #include -#define INT8 _X11INT8 -#define INT32 _X11INT32 #include -#undef INT8 -#undef INT32 #include } diff --git a/powerdevil/daemon/backends/upower/xrandrbrightness.cpp b/powerdevil/daemon/backends/upower/xrandrbrightness.cpp index f18092e7..84c989f2 100644 --- a/powerdevil/daemon/backends/upower/xrandrbrightness.cpp +++ b/powerdevil/daemon/backends/upower/xrandrbrightness.cpp @@ -17,13 +17,14 @@ * */ +#include + #include "xrandrbrightness.h" #include #include #include - #include #include #include @@ -33,15 +34,13 @@ XRandrBrightness::XRandrBrightness() { // init int major, minor; - if (!XRRQueryVersion (QX11Info::display(), &major, &minor)) - { - qWarning("RandR extension missing"); + if (!XRRQueryVersion (QX11Info::display(), &major, &minor)) { + kWarning() << "RandR extension missing"; return; } - if (major < 1 || (major == 1 && minor < 2)) - { - qWarning("RandR version %d.%d too old", major, minor); + if (major < 1 || (major == 1 && minor < 2)) { + kWarning() << "RandR version %d.%d too old" << major << minor; return; } @@ -49,17 +48,15 @@ XRandrBrightness::XRandrBrightness() if (m_backlight == None) m_backlight = XInternAtom(QX11Info::display(), "BACKLIGHT", True); // try with legacy atom - if (m_backlight == None) - { - qWarning("No outputs have backlight property"); + if (m_backlight == None) { + kWarning() << "No outputs have backlight property"; return; } m_resources = XRRGetScreenResources(QX11Info::display(), QX11Info::appRootWindow()); - if (!m_resources) - { - qWarning("No available Randr resources"); + if (!m_resources) { + kWarning() << "No available Randr resources"; return; } } @@ -77,8 +74,7 @@ bool XRandrBrightness::isSupported() const return false; // Verify that there are outputs that actually support backlight control... - for (int o = 0; o < m_resources->noutput; o++) - { + for (int o = 0; o < m_resources->noutput; o++) { if (backlight_get(m_resources->outputs[o]) != -1) { return true; } @@ -91,20 +87,17 @@ float XRandrBrightness::brightness() const { float result = 0; - if (!m_resources) + if (!m_resources) { return result; + } - for (int o = 0; o < m_resources->noutput; o++) - { + for (int o = 0; o < m_resources->noutput; o++) { RROutput output = m_resources->outputs[o]; double cur = backlight_get(output); - if (cur != -1) - { + if (cur != -1) { XRRPropertyInfo * info = XRRQueryOutputProperty(QX11Info::display(), output, m_backlight); - if (info) - { - if (info->range && info->num_values == 2) - { + if (info) { + if (info->range && info->num_values == 2) { double min = info->values[0]; double max = info->values[1]; XFree(info); @@ -126,17 +119,13 @@ void XRandrBrightness::setBrightness(float brightness) if (!m_resources) return; - for (int o = 0; o < m_resources->noutput; o++) - { + for (int o = 0; o < m_resources->noutput; o++) { RROutput output = m_resources->outputs[o]; double cur = backlight_get(output); - if (cur != -1) - { + if (cur != -1) { XRRPropertyInfo * info = XRRQueryOutputProperty(QX11Info::display(), output, m_backlight); - if (info) - { - if (info->range && info->num_values == 2) - { + if (info) { + if (info->range && info->num_values == 2) { double min = info->values[0]; double max = info->values[1]; @@ -164,13 +153,15 @@ long XRandrBrightness::backlight_get(RROutput output) const if (!m_backlight || XRRGetOutputProperty (QX11Info::display(), output, m_backlight, 0, 4, False, False, None, &actual_type, &actual_format, - &nitems, &bytes_after, &prop) != Success) + &nitems, &bytes_after, &prop) != Success) { return -1; + } - if (actual_type != XA_INTEGER || nitems != 1 || actual_format != 32) + if (actual_type != XA_INTEGER || nitems != 1 || actual_format != 32) { value = -1; - else + } else { value = *((long *) prop); + } XFree (prop); return value; }