[powerdevil/Plasma/5.14] /: Revert "Remove XRandrBrightness"

Kai Uwe Broulik null at kde.org
Tue Sep 25 14:58:43 BST 2018


Git commit 6b93d74675aeb8f6fad26f62f300e4ed6b155ad4 by Kai Uwe Broulik.
Committed on 25/09/2018 at 13:57.
Pushed by broulik into branch 'Plasma/5.14'.

Revert "Remove XRandrBrightness"

Apparently there's still graphics cards that rely on this :'(

This was the only real change in this cycle, so just reverting it is safe,
albeit technically being a dependency change.

BUG: 399018
CCMAIL: kde-distro-packagers at kde.org

This reverts commit 7e29869329184d9e2bae6019939e2ecb0eceac0d.

M  +1    -1    CMakeLists.txt
M  +6    -1    daemon/backends/CMakeLists.txt
M  +113  -59   daemon/backends/upower/powerdevilupowerbackend.cpp
M  +4    -0    daemon/backends/upower/powerdevilupowerbackend.h
A  +221  -0    daemon/backends/upower/xrandrbrightness.cpp     [License: LGPL (v2)]
A  +51   -0    daemon/backends/upower/xrandrbrightness.h     [License: LGPL (v2)]
A  +124  -0    daemon/backends/upower/xrandrxcbhelper.cpp     [License: GPL (v2+)]
A  +99   -0    daemon/backends/upower/xrandrxcbhelper.h     [License: GPL (v2+)]

https://commits.kde.org/powerdevil/6b93d74675aeb8f6fad26f62f300e4ed6b155ad4

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2d73ce4..2782a09 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -54,7 +54,7 @@ find_package(LibKWorkspace ${PROJECT_VERSION} REQUIRED)
 
 find_package(UDev REQUIRED)
 
-find_package(XCB REQUIRED COMPONENTS XCB DPMS)
+find_package(XCB REQUIRED COMPONENTS XCB RANDR DPMS)
 
 option(WITH_DDCUTIL "DDCUtil library support" OFF)
 if(WITH_DDCUTIL)
diff --git a/daemon/backends/CMakeLists.txt b/daemon/backends/CMakeLists.txt
index 2dc465a..8c5e203 100644
--- a/daemon/backends/CMakeLists.txt
+++ b/daemon/backends/CMakeLists.txt
@@ -1,12 +1,15 @@
 ########################## UPower Backend #####################################
 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/upower
-                    ${X11_INCLUDE_DIR})
+                    ${X11_INCLUDE_DIR}
+                    ${X11_Xrandr_INCLUDE_PATH})
 
 set(powerdevilupowerbackend_SRCS
     ${PowerDevil_SOURCE_DIR}/daemon/powerdevil_debug.cpp
     upower/upowersuspendjob.cpp
     upower/login1suspendjob.cpp
     upower/powerdevilupowerbackend.cpp
+    upower/xrandrbrightness.cpp
+    upower/xrandrxcbhelper.cpp
     upower/udevqtclient.cpp
     upower/udevqtdevice.cpp
     upower/ddcutilbrightness.cpp
@@ -54,7 +57,9 @@ target_link_libraries(powerdevilupowerbackend
     KF5::I18n
     ${UDEV_LIBS}
     ${X11_LIBRARIES}
+    ${X11_Xrandr_LIB}
     ${XCB_XCB_LIBRARY}
+    ${XCB_RANDR_LIBRARY}
     powerdevilcore
 )
 if(DDCUTIL_FOUND)
diff --git a/daemon/backends/upower/powerdevilupowerbackend.cpp b/daemon/backends/upower/powerdevilupowerbackend.cpp
index 454ba69..7af7059 100644
--- a/daemon/backends/upower/powerdevilupowerbackend.cpp
+++ b/daemon/backends/upower/powerdevilupowerbackend.cpp
@@ -36,6 +36,8 @@
 #include <KSharedConfig>
 #include <KAuthAction>
 
+#include "xrandrxcbhelper.h"
+#include "xrandrbrightness.h"
 #include "ddcutilbrightness.h"
 #include "upowersuspendjob.h"
 #include "login1suspendjob.h"
@@ -46,6 +48,8 @@
 PowerDevilUPowerBackend::PowerDevilUPowerBackend(QObject* parent)
     : BackendInterface(parent)
     , m_displayDevice(nullptr)
+    , m_brightnessControl(nullptr)
+    , m_randrHelper(nullptr)
     , m_upowerInterface(nullptr)
     , m_kbdBacklight(nullptr)
     , m_kbdMaxBrightness(0)
@@ -57,7 +61,10 @@ PowerDevilUPowerBackend::PowerDevilUPowerBackend(QObject* parent)
 
 }
 
-PowerDevilUPowerBackend::~PowerDevilUPowerBackend() = default;
+PowerDevilUPowerBackend::~PowerDevilUPowerBackend()
+{
+    delete m_brightnessControl;
+}
 
 bool PowerDevilUPowerBackend::isAvailable()
 {
@@ -144,66 +151,90 @@ void PowerDevilUPowerBackend::init()
 
     connect(this, &PowerDevilUPowerBackend::brightnessSupportQueried, this, &PowerDevilUPowerBackend::initWithBrightness);
     m_upowerInterface = new OrgFreedesktopUPowerInterface(UPOWER_SERVICE, "/org/freedesktop/UPower", QDBusConnection::systemBus(), this);
-    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_brightnessControl = new XRandrBrightness();
+    if (!m_brightnessControl->isSupported()) {
+        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;
                     }
-
-                    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_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_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);
+                            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);
+                                }
+                            );
+                            syspathJob->start();
                         }
                     );
-                    syspathJob->start();
+                    brightnessMaxJob->start();
                 }
             );
-            brightnessMaxJob->start();
-        });
-        brightnessJob->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);
+            }
+            Q_EMIT brightnessSupportQueried(true);
+        }
     } else {
-        qCDebug(POWERDEVIL) << "Using DDCutillib";
+        qCDebug(POWERDEVIL) << "Using XRandR";
+        m_randrHelper = XRandRXCBHelper::self();
+        Q_ASSERT(m_randrHelper);
+        connect(m_randrHelper, &XRandRXCBHelper::brightnessChanged, this, &PowerDevilUPowerBackend::slotScreenBrightnessChanged);
         m_cachedBrightnessMap.insert(Screen, brightness(Screen));
 
         const int duration = PowerDevilSettings::brightnessAnimationDuration();
@@ -381,13 +412,20 @@ int PowerDevilUPowerBackend::brightness(PowerDevil::BackendInterface::Brightness
     int result = 0;
 
     if (type == Screen) {
-        if (m_ddcBrightnessControl->isSupported()){
+        if (m_brightnessControl->isSupported()) {
+            if (m_brightnessAnimation && m_brightnessAnimation->state() == QPropertyAnimation::Running) {
+                result = m_brightnessAnimation->endValue().toInt();
+            } else {
+                //qCDebug(POWERDEVIL) << "Calling xrandr brightness";
+                result = (int) m_brightnessControl->brightness();
+            }
+        } 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 {
+        }else{
             result = m_cachedBrightnessMap[Screen];
         }
         qCDebug(POWERDEVIL) << "Screen brightness value: " << result;
@@ -404,9 +442,12 @@ int PowerDevilUPowerBackend::brightnessMax(PowerDevil::BackendInterface::Brightn
     int result = 0;
 
     if (type == Screen) {
-        if (m_ddcBrightnessControl->isSupported()){
+        if (m_brightnessControl->isSupported()) {
+            //qCDebug(POWERDEVIL) << "Calling xrandr brightness";
+            result = (int) m_brightnessControl->brightnessMax();
+        } else if (m_ddcBrightnessControl->isSupported()){
             result = (int)m_ddcBrightnessControl->brightnessMax();
-        } else {
+        }else{
             result = m_brightnessMax;
         }
         qCDebug(POWERDEVIL) << "Screen brightness value max: " << result;
@@ -422,7 +463,18 @@ void PowerDevilUPowerBackend::setBrightness(int value, PowerDevil::BackendInterf
 {
     if (type == Screen) {
         qCDebug(POWERDEVIL) << "set screen brightness value: " << value;
-        if (m_ddcBrightnessControl->isSupported()){
+        if (m_brightnessControl->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_brightnessControl->setBrightness(value);
+            }
+        } else if (m_ddcBrightnessControl->isSupported()){
             if (m_brightnessAnimation) {
                 m_brightnessAnimation->stop();
                 disconnect(m_brightnessAnimation, &QPropertyAnimation::valueChanged, this, &PowerDevilUPowerBackend::animationValueChanged);
@@ -661,7 +713,9 @@ void PowerDevilUPowerBackend::slotLogin1PrepareForSleep(bool active)
 
 void PowerDevilUPowerBackend::animationValueChanged(const QVariant &value)
 {
-    if (m_ddcBrightnessControl->isSupported()) {
+    if (m_brightnessControl->isSupported()) {
+        m_brightnessControl->setBrightness(value.toInt());
+    }else if (m_ddcBrightnessControl->isSupported()) {
         m_ddcBrightnessControl->setBrightness(value.toInt());
     }
     else{
diff --git a/daemon/backends/upower/powerdevilupowerbackend.h b/daemon/backends/upower/powerdevilupowerbackend.h
index cdddbf9..bf90097 100644
--- a/daemon/backends/upower/powerdevilupowerbackend.h
+++ b/daemon/backends/upower/powerdevilupowerbackend.h
@@ -42,6 +42,8 @@
 #define CONSOLEKIT2_SERVICE "org.freedesktop.ConsoleKit"
 
 class UdevHelper;
+class XRandRXCBHelper;
+class XRandrBrightness;
 class QPropertyAnimation;
 class DDCutilBrightness;
 class Q_DECL_EXPORT PowerDevilUPowerBackend : public PowerDevil::BackendInterface
@@ -97,6 +99,8 @@ private:
 
     // brightness
     QMap<BrightnessControlType, int> m_cachedBrightnessMap;
+    XRandrBrightness         *m_brightnessControl;
+    XRandRXCBHelper *m_randrHelper;
     DDCutilBrightness *m_ddcBrightnessControl;
 
     OrgFreedesktopUPowerInterface *m_upowerInterface;
diff --git a/daemon/backends/upower/xrandrbrightness.cpp b/daemon/backends/upower/xrandrbrightness.cpp
new file mode 100644
index 0000000..586801c
--- /dev/null
+++ b/daemon/backends/upower/xrandrbrightness.cpp
@@ -0,0 +1,221 @@
+/*  This file is part of the KDE project
+ *    Copyright (C) 2010 Lukas Tinkl <ltinkl at redhat.com>
+ *    Copyright (C) 2015 Kai Uwe Broulik <kde at privat.broulik.de>
+ * 
+ *    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 <powerdevil_debug.h>
+
+#include <QX11Info>
+
+#include "xrandrbrightness.h"
+
+XRandrBrightness::XRandrBrightness()
+{
+    if (!QX11Info::isPlatformX11()) {
+        return;
+    }
+
+    auto *c = QX11Info::connection();
+
+    xcb_prefetch_extension_data(c, &xcb_randr_id);
+    // this reply, for once, does not need to be managed by us
+    auto *extension = xcb_get_extension_data(c, &xcb_randr_id);
+    if (!extension || !extension->present) {
+        qCWarning(POWERDEVIL) << "XRandR extension not available";
+        return;
+    }
+
+    ScopedCPointer<xcb_randr_query_version_reply_t> versionReply(xcb_randr_query_version_reply(c,
+        xcb_randr_query_version(c, 1, 2),
+    nullptr));
+
+    if (!versionReply) {
+        qCWarning(POWERDEVIL) << "RandR Query version returned null";
+        return;
+    }
+
+    if (versionReply->major_version < 1 || (versionReply->major_version == 1 && versionReply->minor_version < 2)) {
+        qCWarning(POWERDEVIL, "RandR version %d.%d too old", versionReply->major_version, versionReply->minor_version);
+        return;
+    }
+
+    ScopedCPointer<xcb_intern_atom_reply_t> backlightReply(xcb_intern_atom_reply(c,
+        xcb_intern_atom(c, 1, strlen("Backlight"), "Backlight"),
+    nullptr));
+
+    if (!backlightReply) {
+        qCWarning(POWERDEVIL, "Intern Atom for Backlight returned null");
+        return;
+    }
+
+    m_backlight = backlightReply->atom;
+
+    if (m_backlight == XCB_NONE) {
+        qCWarning(POWERDEVIL, "No outputs have backlight property");
+        return;
+    }
+
+    xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(c));
+    if (!iter.rem) {
+        qCWarning(POWERDEVIL, "XCB Screen Roots Iterator rem was null");
+        return;
+    }
+
+    xcb_screen_t *screen = iter.data;
+    xcb_window_t root = screen->root;
+
+    m_resources.reset(xcb_randr_get_screen_resources_current_reply(c,
+        xcb_randr_get_screen_resources_current(c, root)
+    , nullptr));
+
+    if (!m_resources) {
+        qCWarning(POWERDEVIL, "RANDR Get Screen Resources returned null");
+        return;
+    }
+}
+
+bool XRandrBrightness::isSupported() const
+{
+    if (!m_resources) {
+        return false;
+    }
+
+    auto *outputs = xcb_randr_get_screen_resources_current_outputs(m_resources.data());
+    for (int i = 0; i < m_resources->num_outputs; ++i) {
+        if (backlight_get(outputs[i]) != -1) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+long XRandrBrightness::brightness() const
+{
+    if (!m_resources) {
+        return 0;
+    }
+
+    auto *outputs = xcb_randr_get_screen_resources_current_outputs(m_resources.data());
+    for (int i = 0; i < m_resources->num_outputs; ++i) {
+        auto output = outputs[i];
+
+        long cur, min, max;
+        if (backlight_get_with_range(output, cur, min, max)) {
+            // FIXME for now just return the first output's value
+            return cur - min;
+        }
+    }
+
+    return 0;
+}
+
+long XRandrBrightness::brightnessMax() const
+{
+    if (!m_resources) {
+        return 0;
+    }
+
+    auto *outputs = xcb_randr_get_screen_resources_current_outputs(m_resources.data());
+    for (int i = 0; i < m_resources->num_outputs; ++i) {
+        auto output = outputs[i];
+
+        long cur, min, max;
+        if (backlight_get_with_range(output, cur, min, max)) {
+            // FIXME for now just return the first output's value
+            return max - min;
+        }
+    }
+
+    return 0;
+}
+
+void XRandrBrightness::setBrightness(long value)
+{
+    if (!m_resources) {
+        return;
+    }
+
+    auto *outputs = xcb_randr_get_screen_resources_current_outputs(m_resources.data());
+    for (int i = 0; i < m_resources->num_outputs; ++i) {
+        auto output = outputs[i];
+
+        long cur, min, max;
+        if (backlight_get_with_range(output, cur, min, max)) {
+            // FIXME for now just set the first output's value
+            backlight_set(output, min + value);
+        }
+    }
+
+    free(xcb_get_input_focus_reply(QX11Info::connection(), xcb_get_input_focus(QX11Info::connection()), nullptr)); // sync
+}
+
+bool XRandrBrightness::backlight_get_with_range(xcb_randr_output_t output, long &value, long &min, long &max) const {
+    long cur = backlight_get(output);
+    if (cur == -1) {
+       return false;
+    }
+
+    ScopedCPointer<xcb_randr_query_output_property_reply_t> propertyReply(xcb_randr_query_output_property_reply(QX11Info::connection(),
+        xcb_randr_query_output_property(QX11Info::connection(), output, m_backlight)
+    , nullptr));
+
+    if (!propertyReply) {
+        return -1;
+    }
+
+    if (propertyReply->range && xcb_randr_query_output_property_valid_values_length(propertyReply.data()) == 2) {
+        int32_t *values = xcb_randr_query_output_property_valid_values(propertyReply.data());
+        value = cur;
+        min = values[0];
+        max = values[1];
+        return true;
+    }
+
+    return false;
+}
+
+long XRandrBrightness::backlight_get(xcb_randr_output_t output) const
+{
+    ScopedCPointer<xcb_randr_get_output_property_reply_t> propertyReply;
+    long value;
+
+    if (m_backlight != XCB_ATOM_NONE) {
+        propertyReply.reset(xcb_randr_get_output_property_reply(QX11Info::connection(),
+            xcb_randr_get_output_property(QX11Info::connection(), output, m_backlight, XCB_ATOM_NONE, 0, 4, 0, 0)
+        , nullptr));
+
+        if (!propertyReply) {
+            return -1;
+        }
+    }
+
+    if (!propertyReply || propertyReply->type != XCB_ATOM_INTEGER || propertyReply->num_items != 1 || propertyReply->format != 32) {
+        value = -1;
+    } else {
+        value = *(reinterpret_cast<long *>(xcb_randr_get_output_property_data(propertyReply.data())));
+    }
+    return value;
+}
+
+void XRandrBrightness::backlight_set(xcb_randr_output_t output, long value)
+{
+    xcb_randr_change_output_property(QX11Info::connection(), output, m_backlight, XCB_ATOM_INTEGER,
+                                     32, XCB_PROP_MODE_REPLACE,
+                                     1, reinterpret_cast<unsigned char *>(&value));
+}
diff --git a/daemon/backends/upower/xrandrbrightness.h b/daemon/backends/upower/xrandrbrightness.h
new file mode 100644
index 0000000..67d44a8
--- /dev/null
+++ b/daemon/backends/upower/xrandrbrightness.h
@@ -0,0 +1,51 @@
+/*  This file is part of the KDE project
+ *    Copyright (C) 2010 Lukas Tinkl <ltinkl at redhat.com>
+ *    Copyright (C) 2015 Kai Uwe Broulik <kde at privat.broulik.de>
+ * 
+ *    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 XRANDRBRIGHTNESS_H
+#define XRANDRBRIGHTNESS_H
+
+#include <xcb/xcb.h>
+#include <xcb/randr.h>
+
+#include <QScopedPointer>
+
+template <typename T> using ScopedCPointer = QScopedPointer<T, QScopedPointerPodDeleter>;
+
+class XRandrBrightness
+{
+public:
+    XRandrBrightness();
+    ~XRandrBrightness() = default;
+    bool isSupported() const;
+    long brightness() const;
+    long brightnessMax() const;
+    void setBrightness(long value);
+
+private:
+    bool backlight_get_with_range(xcb_randr_output_t output, long &value, long &min, long &max) const;
+    long backlight_get(xcb_randr_output_t output) const;
+    void backlight_set(xcb_randr_output_t output, long value);
+
+    xcb_atom_t m_backlight = XCB_ATOM_NONE;
+    ScopedCPointer<xcb_randr_get_screen_resources_current_reply_t> m_resources;
+
+};
+
+#endif // XRANDRBRIGHTNESS_H
diff --git a/daemon/backends/upower/xrandrxcbhelper.cpp b/daemon/backends/upower/xrandrxcbhelper.cpp
new file mode 100644
index 0000000..ee8c2fe
--- /dev/null
+++ b/daemon/backends/upower/xrandrxcbhelper.cpp
@@ -0,0 +1,124 @@
+/*************************************************************************************
+ *  Copyright (C) 2013 by Alejandro Fiestas Olivares <afiestas at kde.org>              *
+ *                                                                                   *
+ *  This program is free software; you can redistribute it and/or                    *
+ *  modify it under the terms of the GNU General Public License                      *
+ *  as published by the Free Software Foundation; either version 2                   *
+ *  of the License, or (at your option) any later version.                           *
+ *                                                                                   *
+ *  This program 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 General Public License for more details.                                     *
+ *                                                                                   *
+ *  You should have received a copy of the GNU General Public License                *
+ *  along with this program; if not, write to the Free Software                      *
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
+ *************************************************************************************/
+
+#include "xrandrxcbhelper.h"
+
+#include <xcb/randr.h>
+#include <QCoreApplication>
+#include <QLatin1String>
+
+bool XRandRXCBHelper::s_init = false;
+XRandRInfo XRandRXCBHelper::s_xrandrInfo;
+
+XRandRXCBHelper::XRandRXCBHelper() : QObject()
+    , m_window(0)
+{
+    if (!s_init) {
+        init();
+    }
+}
+
+XRandRXCBHelper::~XRandRXCBHelper()
+{
+    xcb_destroy_window(conn(), m_window);
+}
+
+bool XRandRXCBHelper::nativeEventFilter(const QByteArray& eventType, void* message, long int* result)
+{
+    Q_UNUSED(result);
+
+    if (eventType != "xcb_generic_event_t") {
+        return false;
+    }
+
+    xcb_generic_event_t* e = static_cast<xcb_generic_event_t *>(message);
+    const uint8_t xEventType = e->response_type & ~0x80;
+
+    //If this event is not xcb_randr_notify, we don't want it
+    if (xEventType != s_xrandrInfo.eventType) {
+        return false;
+    }
+
+    xcb_randr_notify_event_t*
+    randrEvent = reinterpret_cast<xcb_randr_notify_event_t*>(e);
+
+    //If the event is not about a change in an output property, we don't want it
+    if (randrEvent->subCode != XCB_RANDR_NOTIFY_OUTPUT_PROPERTY) {
+        return false;
+    }
+
+    //If the event is not about a new value, we don't want it
+    if (randrEvent->u.op.status != XCB_PROPERTY_NEW_VALUE) {
+        return false;
+    }
+
+    //If the modified property is not backlight, we don't care
+    if (randrEvent->u.op.atom != s_xrandrInfo.backlightAtom) {
+        return false;
+    }
+
+    Q_EMIT brightnessChanged();
+
+    return false;
+}
+
+void XRandRXCBHelper::init()
+{
+    xcb_connection_t* c = conn();
+
+    xcb_prefetch_extension_data(c, &xcb_randr_id);
+    const xcb_query_extension_reply_t *reply = xcb_get_extension_data(c, &xcb_randr_id);
+    if (!reply) {
+        s_xrandrInfo.isPresent = false;
+        return;
+    }
+
+    s_xrandrInfo.isPresent = reply->present;
+    s_xrandrInfo.eventBase = reply->first_event;
+    s_xrandrInfo.errorBase = reply->first_error;
+    s_xrandrInfo.eventType = s_xrandrInfo.eventBase + XCB_RANDR_NOTIFY;
+    s_xrandrInfo.majorOpcode = reply->major_opcode;
+
+    QByteArray backlight = QByteArrayLiteral("Backlight");
+
+    /*This is KDE5... the world of opengl and wayland (almost), I don't think we really need to
+    check the old BACKLIGHT atom*/
+//     QByteArray backlightCaps("BACKLIGHT");
+//     xcb_intern_atom(c, true, backlightCaps.length(), backlightCaps.constData());
+    xcb_intern_atom_reply_t* atomReply =
+    xcb_intern_atom_reply(c, xcb_intern_atom(c, true, backlight.length(), backlight.constData()), nullptr);
+
+    //If backlight atom doesn't exist, means that no driver is actually supporting it
+    if (!atomReply) {
+        return;
+    }
+
+    s_xrandrInfo.backlightAtom = atomReply->atom;
+
+    uint32_t rWindow = rootWindow(c, 0);
+    m_window = xcb_generate_id(c);
+    xcb_create_window(c, XCB_COPY_FROM_PARENT, m_window,
+                      rWindow,
+                      0, 0, 1, 1, 0, XCB_COPY_FROM_PARENT,
+                      XCB_COPY_FROM_PARENT, 0, nullptr);
+
+    xcb_randr_select_input(c, m_window, XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY);
+    qApp->installNativeEventFilter(this);
+
+    s_init = true;
+}
diff --git a/daemon/backends/upower/xrandrxcbhelper.h b/daemon/backends/upower/xrandrxcbhelper.h
new file mode 100644
index 0000000..ce0e129
--- /dev/null
+++ b/daemon/backends/upower/xrandrxcbhelper.h
@@ -0,0 +1,99 @@
+/*************************************************************************************
+ *  Copyright (C) 2013 by Alejandro Fiestas Olivares <afiestas at kde.org>              *
+ *                                                                                   *
+ *  This program is free software; you can redistribute it and/or                    *
+ *  modify it under the terms of the GNU General Public License                      *
+ *  as published by the Free Software Foundation; either version 2                   *
+ *  of the License, or (at your option) any later version.                           *
+ *                                                                                   *
+ *  This program 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 General Public License for more details.                                     *
+ *                                                                                   *
+ *  You should have received a copy of the GNU General Public License                *
+ *  along with this program; if not, write to the Free Software                      *
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
+ *************************************************************************************/
+
+#ifndef XRANDR_XCB_HELPER_H
+#define XRANDR_XCB_HELPER_H
+
+#include <xcb/xcb.h>
+#include <xcb/xproto.h>
+#include <QX11Info>
+#include <QObject>
+#include <QAbstractNativeEventFilter>
+
+class XRandRInfo
+{
+public:
+    int version;
+    int eventBase;
+    int errorBase;
+    int majorOpcode;
+    int eventType;
+    xcb_atom_t backlightAtom;
+    bool isPresent;
+};
+
+class XRandRXCBHelper : public QObject, public QAbstractNativeEventFilter
+{
+    Q_OBJECT
+public:
+    static inline XRandRXCBHelper* self()
+    {
+        static XRandRXCBHelper* s_instance = nullptr;
+        if (!s_instance) {
+            s_instance = new XRandRXCBHelper();
+            if (!s_instance->isValid()) {
+                s_instance = nullptr;
+            }
+        }
+
+        return s_instance;
+    }
+
+    bool nativeEventFilter(const QByteArray& eventType, void* message, long int* result) override;
+
+Q_SIGNALS:
+        void brightnessChanged();
+
+private:
+    XRandRXCBHelper();
+    ~XRandRXCBHelper() override;
+    void init();
+
+    inline bool isValid()
+    {
+        return s_xrandrInfo.isPresent;
+    }
+
+    inline xcb_connection_t *conn()
+    {
+        static xcb_connection_t *s_con = nullptr;
+        if (!s_con) {
+            s_con = QX11Info::connection();
+        }
+        return s_con;
+    }
+
+    inline xcb_window_t rootWindow(xcb_connection_t *c, int screen)
+    {
+        xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(c));
+        for (xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(c));
+                it.rem;
+                --screen, xcb_screen_next(&it)) {
+            if (screen == 0) {
+                return iter.data->root;
+            }
+        }
+        return XCB_WINDOW_NONE;
+    }
+
+    uint32_t m_window;
+    static bool s_init;
+    static XRandRInfo s_xrandrInfo;
+};
+
+#endif //XRANDR_XCB_HELPER_H



More information about the Distributions mailing list