File indexing completed on 2024-04-28 16:49:43

0001 // SPDX-FileCopyrightText: 2010 by Dario Freddi <drf@kde.org>
0002 // SPDX-FileCopyrightText: 2015 by Kai Uwe Broulik <kde@privat.broulik.de>
0003 // SPDX-FileCopyrightText: 2015 by Martin Gräßlin <mgraesslin@kde.org>
0004 // SPDX-FileCopyrightText: 2022 Aleix Pol Gonzalez <aleixpol@kde.org>
0005 //
0006 // SPDX-License-Identifier: LGPL-2.1-or-later
0007 
0008 #include "xcbdpmshelper_p.h"
0009 
0010 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0011 #include <QX11Info>
0012 #else
0013 #include <private/qtx11extras_p.h>
0014 #endif
0015 #include <QGuiApplication>
0016 
0017 #include "kscreendpms_debug.h"
0018 
0019 #include <xcb/dpms.h>
0020 
0021 template<typename T>
0022 using ScopedCPointer = QScopedPointer<T, QScopedPointerPodDeleter>;
0023 
0024 XcbDpmsHelper::XcbDpmsHelper()
0025     : AbstractDpmsHelper()
0026 {
0027     auto *c = QX11Info::connection();
0028 
0029     xcb_prefetch_extension_data(c, &xcb_dpms_id);
0030     auto *extension = xcb_get_extension_data(c, &xcb_dpms_id);
0031     if (!extension || !extension->present) {
0032         qCWarning(KSCREEN_DPMS) << "DPMS extension not available";
0033         setSupported(false);
0034         return;
0035     }
0036 
0037     ScopedCPointer<xcb_dpms_capable_reply_t> capableReply(xcb_dpms_capable_reply(c, xcb_dpms_capable(c), nullptr));
0038     setSupported(capableReply && capableReply->capable);
0039 
0040     // Disable a default timeout, if any
0041     xcb_dpms_set_timeouts(QX11Info::connection(), 0, 0, 0);
0042 }
0043 
0044 XcbDpmsHelper::~XcbDpmsHelper() = default;
0045 
0046 void XcbDpmsHelper::trigger(KScreen::Dpms::Mode mode, const QList<QScreen *> &screens)
0047 {
0048     setHasPendingChanges(true);
0049     auto *c = QX11Info::connection();
0050 
0051     if (screens != qGuiApp->screens()) {
0052         qCWarning(KSCREEN_DPMS) << "DPMS actions are applied to all screens on X11";
0053     }
0054 
0055     ScopedCPointer<xcb_dpms_info_reply_t> infoReply(xcb_dpms_info_reply(c, xcb_dpms_info(c), nullptr));
0056 
0057     if (!infoReply) {
0058         qCWarning(KSCREEN_DPMS) << "Failed to query DPMS state, cannot trigger";
0059         return;
0060     }
0061 
0062     xcb_dpms_dpms_mode_t level = XCB_DPMS_DPMS_MODE_ON;
0063     switch (mode) {
0064     case KScreen::Dpms::Toggle:
0065         if (infoReply->power_level == XCB_DPMS_DPMS_MODE_ON) {
0066             level = XCB_DPMS_DPMS_MODE_OFF;
0067         } else {
0068             level = XCB_DPMS_DPMS_MODE_ON;
0069         }
0070         break;
0071     case KScreen::Dpms::Off:
0072         level = XCB_DPMS_DPMS_MODE_OFF;
0073         break;
0074     case KScreen::Dpms::Standby:
0075         level = XCB_DPMS_DPMS_MODE_STANDBY;
0076         break;
0077     case KScreen::Dpms::Suspend:
0078         level = XCB_DPMS_DPMS_MODE_SUSPEND;
0079         break;
0080     case KScreen::Dpms::On:
0081         level = XCB_DPMS_DPMS_MODE_ON;
0082         break;
0083     }
0084 
0085     if (!infoReply->state) {
0086         xcb_dpms_enable(c);
0087     }
0088 
0089     xcb_dpms_force_level(c, level);
0090 
0091     setHasPendingChanges(false);
0092 }