From 03854853a114ada1fa089d6a8d67d31f83bad9ec Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Wed, 3 Aug 2022 10:03:37 +0300 Subject: [PATCH] kscreensaver: reimplement via X11 DPMS Signed-off-by: Ivailo Monev --- CMakeLists.txt | 7 +- ConfigureChecks.cmake | 1 + appveyor.yml | 10 +- config-X11.h.cmake | 3 + kscreensaver/CMakeLists.txt | 4 + kscreensaver/kscreensaver.cpp | 232 +++++++++++++++++++++------------- kscreensaver/kscreensaver.h | 12 +- 7 files changed, 161 insertions(+), 108 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f1db2a4b..ab3b7e72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,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("libXext" X11_dpms_FOUND "The X extensions library may be used by kscreensaver") if(NOT X11_Xau_FOUND) message(FATAL_ERROR "The X11 authorization extension library was not found. Required for authorization in kworkspace library") @@ -235,12 +236,6 @@ add_feature_info(qrencode "QR Code support in klipper" ) -find_program(XSCREENSAVER_EXECUTABLE xscreensaver) -add_feature_info(xscreensaver - XSCREENSAVER_EXECUTABLE - "Screen saver and screen locking support" -) - find_program(GDB_OR_LLDB_EXECUTABLE NAMES gdb lldb) add_feature_info(gdb_or_lldb GDB_OR_LLDB_EXECUTABLE diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index 9f1591f7..a6f4e6ee 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -37,6 +37,7 @@ macro_bool_to_01(X11_Xrender_FOUND HAVE_XRENDER) # kcontrol/style, kicker macro_bool_to_01(X11_xf86misc_FOUND HAVE_XF86MISC) # kcontrol/keyboard 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_dpms_FOUND HAVE_DPMS) # kscreensaver cmake_reset_check_state() set(CMAKE_REQUIRED_INCLUDES ${X11_Xrandr_INCLUDE_PATH}) diff --git a/appveyor.yml b/appveyor.yml index 08c8cbe4..40df2a16 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,11 +19,11 @@ build_script: sudo apt-get update -qq sudo apt-get install -qq cmake katie-dev katanalibs \ - xorg-dev libqalculate-dev libxxf86vm-dev libx11-xcb-dev libxcb-composite0-dev \ - libxcb-damage0-dev libxcb-xfixes0-dev libxcb-render0-dev libxcb-randr0-dev \ - libxcb-shape0-dev libxcb-sync-dev libxcb-render-util0-dev libxcb-keysyms1-dev \ - libglu1-mesa-dev mesa-common-dev libmtp-dev libusb-1.0-0-dev libssh-dev \ - libdrm-dev libraw1394-dev libsensors4-dev libgphoto2-dev libegl-dev \ + xorg-dev libqalculate-dev libxxf86vm-dev libxext-dev libx11-xcb-dev \ + libxcb-composite0-dev libxcb-damage0-dev libxcb-xfixes0-dev libxcb-render0-dev \ + libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-render-util0-dev \ + libxcb-keysyms1-dev libglu1-mesa-dev mesa-common-dev libmtp-dev libusb-1.0-0-dev \ + libssh-dev libdrm-dev libraw1394-dev libsensors4-dev libgphoto2-dev libegl-dev \ libpci-dev libopenexr-dev liblightdm-gobject-1-dev libkmod-dev \ libdbusmenu-katie \ sudo ctags cppcheck lrzsz locate \ diff --git a/config-X11.h.cmake b/config-X11.h.cmake index ef861d8a..ada74bd0 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 DPMS extension */ +#cmakedefine HAVE_DPMS 1 diff --git a/kscreensaver/CMakeLists.txt b/kscreensaver/CMakeLists.txt index 4a96be5e..c430d8d7 100644 --- a/kscreensaver/CMakeLists.txt +++ b/kscreensaver/CMakeLists.txt @@ -26,6 +26,10 @@ target_link_libraries(kded_kscreensaver PRIVATE ${QT_QTDBUS_LIBRARY} ) +if(X11_dpms_FOUND) + target_link_libraries(kded_kscreensaver PRIVATE ${X11_Xext_LIB}) +endif(X11_dpms_FOUND) + install( TARGETS kded_kscreensaver DESTINATION ${KDE4_PLUGIN_INSTALL_DIR} diff --git a/kscreensaver/kscreensaver.cpp b/kscreensaver/kscreensaver.cpp index ee604881..a7921078 100644 --- a/kscreensaver/kscreensaver.cpp +++ b/kscreensaver/kscreensaver.cpp @@ -18,21 +18,29 @@ #include "kscreensaver.h" #include "screensaveradaptor.h" +#include "config-X11.h" -#include -#include +#include +#include #include +#include #include #include -#include +#include + +#ifdef HAVE_DPMS +# include +# include +#endif KScreenSaver::KScreenSaver(QObject *parent) : QObject(parent), m_objectsregistered(false), m_serviceregistered(false), - m_xscreensaver(nullptr), - m_xscreensaverpid(0), + m_havedpms(false), + m_dpmsactive(false), + m_statetimer(this), m_login1("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", QDBusConnection::systemBus()), m_consolekit("org.freedesktop.ConsoleKit", "/org/freedesktop/ConsoleKit/Manager", "org.freedesktop.ConsoleKit.Manager", QDBusConnection::systemBus()) { @@ -64,21 +72,6 @@ KScreenSaver::KScreenSaver(QObject *parent) } m_serviceregistered = true; - QProcess::startDetached( - QString::fromLatin1("xscreensaver"), - QStringList() << QString::fromLatin1("-nosplash"), - QDir::currentPath(), - &m_xscreensaverpid - ); - - m_xscreensaver = new QProcess(this); - connect(m_xscreensaver, SIGNAL(readyReadStandardOutput()), this, SLOT(slotXScreenSaverOutput())); - connect(m_xscreensaver, SIGNAL(readyReadStandardError()), this, SLOT(slotXScreenSaverError())); - m_xscreensaver->start( - QString::fromLatin1("xscreensaver-command"), - QStringList() << QString::fromLatin1("-watch") - ); - if (m_login1.isValid()) { QDBusReply reply = m_login1.call("GetSessionByPID", uint(::getpid())); if (reply.isValid()) { @@ -115,8 +108,26 @@ KScreenSaver::KScreenSaver(QObject *parent) } } - // xscreensaver daemon instantly shows screen saver when started, deactivate it - SetActive(false); +#ifdef HAVE_DPMS + int dpmsevent = 0; + int dpmserror = 0; + int dpmstatus = DPMSQueryExtension(QX11Info::display(), &dpmsevent, &dpmserror); + if (dpmstatus == 0) { + kWarning() << "No DPMS extension"; + return; + } + + dpmstatus = DPMSCapable(QX11Info::display()); + if (dpmstatus == 0) { + kWarning() << "Not DPMS capable"; + return; + } + m_havedpms = true; + + connect(&m_statetimer, SIGNAL(timeout()), this, SLOT(slotCheckState())); + m_statetimer.start(2000); +#endif // HAVE_DPMS + } KScreenSaver::~KScreenSaver() @@ -131,17 +142,6 @@ KScreenSaver::~KScreenSaver() connection.unregisterObject("/ScreenSaver"); connection.unregisterObject("/org/freedesktop/ScreenSaver"); } - - if (m_xscreensaver) { - disconnect(m_xscreensaver, SIGNAL(readyReadStandardOutput()), this, SLOT(slotXScreenSaverOutput())); - disconnect(m_xscreensaver, SIGNAL(readyReadStandardError()), this, SLOT(slotXScreenSaverError())); - m_xscreensaver->terminate(); - m_xscreensaver->deleteLater(); - } - - if (m_xscreensaverpid > 0) { - ::kill(pid_t(m_xscreensaverpid), SIGTERM); - } } bool KScreenSaver::GetActive() @@ -168,34 +168,62 @@ uint KScreenSaver::GetSessionIdleTime() void KScreenSaver::Lock() { // qDebug() << Q_FUNC_INFO; - const int xscreensaverstatus = QProcess::execute( - QString::fromLatin1("xscreensaver-command"), - QStringList() << QString::fromLatin1("-lock") + // NOTE: this is known to work only with LightDM + QDBusInterface dmiface( + QString::fromLatin1("org.freedesktop.DisplayManager"), + QString::fromLatin1("/org/freedesktop/DisplayManager"), + QString::fromLatin1("org.freedesktop.DisplayManager"), + QDBusConnection::systemBus() ); - if (xscreensaverstatus != 0) { - kWarning() << "Could not lock"; + if (!dmiface.isValid()) { + kWarning() << "Display manager interface is not valid"; + return; } + + const QString username = KUser().loginName(); + const QList dmsessions = qvariant_cast>(dmiface.property("Sessions")); + // qDebug() << Q_FUNC_INFO << dmiface.property("Sessions"); + foreach (const QDBusObjectPath &dmsessionobj, dmsessions) { + QDBusInterface dmsessioniface( + QString::fromLatin1("org.freedesktop.DisplayManager"), + dmsessionobj.path(), + QString::fromLatin1("org.freedesktop.DisplayManager.Session"), + QDBusConnection::systemBus() + ); + if (!dmsessioniface.isValid()) { + kWarning() << "Display manager session interface is not valid"; + continue; + } + const QString dmusername = dmsessioniface.property("UserName").toString(); + // qDebug() << Q_FUNC_INFO << dmusername << username; + if (dmusername == username) { + dmsessioniface.asyncCall("Lock"); + return; + } + } + kWarning() << "Could not find session for" << username; } bool KScreenSaver::SetActive(bool active) { // qDebug() << Q_FUNC_INFO << active; - int xscreensaverstatus = 1; + if (!m_havedpms) { + return false; + } + +#ifdef HAVE_DPMS + int dpmstatus = 1; if (active) { - xscreensaverstatus = QProcess::execute( - QString::fromLatin1("xscreensaver-command"), - QStringList() << QString::fromLatin1("-activate") - ); + dpmstatus = DPMSForceLevel(QX11Info::display(), DPMSModeOff); } else { - xscreensaverstatus = QProcess::execute( - QString::fromLatin1("xscreensaver-command"), - QStringList() << QString::fromLatin1("-deactivate") - ); + dpmstatus = DPMSForceLevel(QX11Info::display(), DPMSModeOn); } - if (xscreensaverstatus != 0) { - kWarning() << "Could not set activity"; + if (dpmstatus == 0) { + kWarning() << "Could not set DPMS level"; + return false; } - return xscreensaverstatus; + return true; +#endif } void KScreenSaver::SimulateUserActivity() @@ -207,62 +235,84 @@ void KScreenSaver::SimulateUserActivity() uint KScreenSaver::Inhibit(const QString &application_name, const QString &reason_for_inhibit) { // qDebug() << Q_FUNC_INFO << application_name << reason_for_inhibit; - QDBusInterface poweriface( - "org.freedesktop.PowerManagement", - "/org/freedesktop/PowerManagement/Inhibit", - "org.freedesktop.PowerManagement.Inhibit", - QDBusConnection::sessionBus() - ); - QDBusReply powerreply = poweriface.call("Inhibit", application_name, reason_for_inhibit); - if (powerreply.isValid()) { - const uint inhibitioncookie = powerreply.value(); - m_inhibitions.append(inhibitioncookie); - return inhibitioncookie; + uint cookiecounter = 0; + while (m_cookies.contains(cookiecounter)) { + if (cookiecounter >= INT_MAX) { + kWarning() << "Inhibit limit reached"; + return 0; + } + cookiecounter++; } - kWarning() << "Power manager reply is invalid"; - return 0; + m_cookies.append(cookiecounter); + return cookiecounter; } void KScreenSaver::UnInhibit(uint cookie) { // qDebug() << Q_FUNC_INFO << cookie; - if (m_inhibitions.contains(cookie)) { - QDBusInterface poweriface( - "org.freedesktop.PowerManagement", - "/org/freedesktop/PowerManagement/Inhibit", - "org.freedesktop.PowerManagement.Inhibit", - QDBusConnection::sessionBus() - ); - poweriface.asyncCall("UnInhibit", cookie); - m_inhibitions.removeAll(cookie); + if (!m_cookies.contains(cookie)) { + kWarning() << "Attempt to UnInhibit with invalid cookie"; + return; } + m_cookies.removeAll(cookie); } -void KScreenSaver::slotXScreenSaverOutput() +void KScreenSaver::slotCheckState() { - // qDebug() << Q_FUNC_INFO; - const QByteArray xscreensaverdata = m_xscreensaver->readAllStandardOutput(); - foreach (const QByteArray &xscreensaverline, xscreensaverdata.split('\n')) { - // qDebug() << Q_FUNC_INFO << xscreensaverline; - if (xscreensaverline.isEmpty()) { - continue; - } + // qDebug() << Q_FUNC_INFO << m_cookies; + if (!m_havedpms) { + return; + } - if (xscreensaverline.startsWith("BLANK") || xscreensaverline.startsWith("LOCK")) { +#ifdef HAVE_DPMS + int dpmstatus = 1; + if (!m_cookies.isEmpty()) { + kDebug() << "Disabling DPMS due to inhibitions"; + dpmstatus = DPMSDisable(QX11Info::display()); + } else { + kDebug() << "Enabling DPMS due to no inhibitions"; + dpmstatus = DPMSEnable(QX11Info::display()); + } + if (dpmstatus == 0) { + kWarning() << "Could not set DPMS state"; + } + + CARD16 dpmslevel = 0; + BOOL dpmsstate = false; + dpmstatus = DPMSInfo(QX11Info::display(), &dpmslevel, &dpmsstate); + if (dpmstatus == 0) { + kWarning() << "Could not get DPMS info" << dpmstatus; + return; + } + + const bool olddpmsactive = m_dpmsactive; + switch (dpmslevel) { + case DPMSModeOn: { + m_dpmsactive = false; + break; + } + case DPMSModeOff: + case DPMSModeStandby: + case DPMSModeSuspend: { + m_dpmsactive = true; + break; + } + default: { + kWarning() << "Unknown DPMS level" << dpmslevel; + break; + } + } + + // qDebug() << Q_FUNC_INFO << dpmslevel << dpmsstate << olddpmsactive << m_dpmsactive; + if (olddpmsactive != m_dpmsactive) { + emit ActiveChanged(m_dpmsactive); + if (m_dpmsactive) { m_activetimer.restart(); - emit ActiveChanged(true); - } else if (xscreensaverline.startsWith("UNBLANK")) { + } else { m_activetimer.invalidate(); - emit ActiveChanged(false); } } -} - -void KScreenSaver::slotXScreenSaverError() -{ - // qDebug() << Q_FUNC_INFO; - const QByteArray xscreensaverdata = m_xscreensaver->readAllStandardError(); - kWarning() << xscreensaverdata; +#endif // HAVE_DPMS } void KScreenSaver::slotLock() diff --git a/kscreensaver/kscreensaver.h b/kscreensaver/kscreensaver.h index 525d527b..6d52b3f2 100644 --- a/kscreensaver/kscreensaver.h +++ b/kscreensaver/kscreensaver.h @@ -20,8 +20,8 @@ #define KSCREENSAVER_H #include -#include #include +#include #include class KScreenSaver : public QObject @@ -48,8 +48,7 @@ Q_SIGNALS: void ActiveChanged(bool active); private Q_SLOTS: - void slotXScreenSaverOutput(); - void slotXScreenSaverError(); + void slotCheckState(); void slotLock(); void slotUnlock(); @@ -57,10 +56,11 @@ private Q_SLOTS: private: bool m_objectsregistered; bool m_serviceregistered; - QProcess* m_xscreensaver; - Q_PID m_xscreensaverpid; + bool m_havedpms; + bool m_dpmsactive; QElapsedTimer m_activetimer; - QList m_inhibitions; + QTimer m_statetimer; + QList m_cookies; QDBusInterface m_login1; QDBusInterface m_consolekit; };