diff --git a/CMakeLists.txt b/CMakeLists.txt index c9e90474..3e84a6b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,58 +1,58 @@ project(PowerDevil) set(PROJECT_VERSION "5.2.90") set(PROJECT_VERSION_MAJOR 5) cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) set(QT_MIN_VERSION "5.2.0") find_package(ECM 1.2.0 REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) include(FeatureSummary) include(WriteBasicConfigVersionFile) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings) # require at least gcc 4.8 if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") if ("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.8") message(SEND_ERROR "Version ${CMAKE_CXX_COMPILER_VERSION} of the ${CMAKE_CXX_COMPILER_ID} C++ compiler is not supported. Please use version 4.8 or later.") endif() endif() find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Widgets DBus X11Extras) find_package(KF5 REQUIRED COMPONENTS Activities Auth IdleTime Config Solid I18n GlobalAccel KIO NotifyConfig Screen KDELibs4Support) find_package(LibKWorkspace CONFIG REQUIRED) find_package(UDev) #upower/udev backend find_package(X11) set_package_properties(X11 PROPERTIES DESCRIPTION "X11 libraries" URL "http://www.x.org" TYPE OPTIONAL PURPOSE "Required for building the X11 based workspace" ) if(X11_FOUND) - find_package(XCB REQUIRED COMPONENTS XCB RANDR) + find_package(XCB REQUIRED COMPONENTS XCB RANDR DPMS) set_package_properties(XCB PROPERTIES TYPE REQUIRED) endif() include_directories ( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/daemon ) set(HAVE_DPMS ${X11_dpms_FOUND}) configure_file(config-workspace.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-workspace.h) add_subdirectory(daemon) add_subdirectory(kcmodule) add_subdirectory(doc) install( FILES powerdevil.notifyrc DESTINATION ${KNOTIFYRC_INSTALL_DIR} ) if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) endif() diff --git a/daemon/actions/CMakeLists.txt b/daemon/actions/CMakeLists.txt index a1b70ca7..767f083b 100644 --- a/daemon/actions/CMakeLists.txt +++ b/daemon/actions/CMakeLists.txt @@ -1,6 +1,7 @@ install(FILES powerdevilaction.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR}) add_subdirectory(bundled) -if(HAVE_DPMS) - add_subdirectory(dpms) -endif() + +if (X11_FOUND) + add_subdirectory(dpms) +endif () diff --git a/daemon/actions/dpms/CMakeLists.txt b/daemon/actions/dpms/CMakeLists.txt index 79c40621..61d7b568 100644 --- a/daemon/actions/dpms/CMakeLists.txt +++ b/daemon/actions/dpms/CMakeLists.txt @@ -1,29 +1,29 @@ include_directories(${PowerDevil_SOURCE_DIR}/daemon ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ${X11_dpms_INCLUDE_PATH}) + ${CMAKE_CURRENT_BINARY_DIR}) set(powerdevildpmsaction_SRCS ${PowerDevil_SOURCE_DIR}/daemon/powerdevil_debug.cpp powerdevildpmsaction.cpp ${PowerDevil_SOURCE_DIR}/daemon/kwinkscreenhelpereffect.cpp) add_library(powerdevildpmsaction MODULE ${powerdevildpmsaction_SRCS}) target_link_libraries(powerdevildpmsaction - ${X11_LIBRARIES} Qt5::X11Extras + XCB::XCB + XCB::DPMS KF5::CoreAddons KF5::ConfigGui Qt5::Widgets powerdevilcore) install(TARGETS powerdevildpmsaction DESTINATION ${PLUGIN_INSTALL_DIR}) install(FILES powerdevildpmsaction.desktop DESTINATION ${SERVICES_INSTALL_DIR}) # Action config set(dpmsconfig_SRCS powerdevildpmsactionconfig.cpp) add_library(powerdevildpmsaction_config MODULE ${dpmsconfig_SRCS}) target_link_libraries(powerdevildpmsaction_config KF5::CoreAddons KF5::ConfigGui KF5::I18n Qt5::Widgets powerdevilui) install(TARGETS powerdevildpmsaction_config DESTINATION ${PLUGIN_INSTALL_DIR}) diff --git a/daemon/actions/dpms/powerdevildpmsaction.cpp b/daemon/actions/dpms/powerdevildpmsaction.cpp index 8586f94c..42ff8f13 100644 --- a/daemon/actions/dpms/powerdevildpmsaction.cpp +++ b/daemon/actions/dpms/powerdevildpmsaction.cpp @@ -1,273 +1,219 @@ /*************************************************************************** * Copyright (C) 2010 by Dario Freddi * + * Copyright (C) 2015 by Kai Uwe Broulik * * * * 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 "powerdevildpmsaction.h" #include #include #include #include #include #include #include #include #include #include -#include -#include -#include -#include -#include -#include -extern "C" { -#include - int __kde_do_not_unload = 1; - -#ifndef HAVE_DPMSCAPABLE_PROTO - Bool DPMSCapable(Display *); -#endif - -#ifndef HAVE_DPMSINFO_PROTO - Status DPMSInfo(Display *, CARD16 *, BOOL *); -#endif - -int dropError(Display *, XErrorEvent *); -typedef int (*XErrFunc)(Display *, XErrorEvent *); -} - -int dropError(Display *, XErrorEvent *) -{ - return 0; -} - -class PowerDevilDPMSAction::Private -{ -public: - XErrorHandler defaultHandler; -}; +#include K_PLUGIN_FACTORY(PowerDevilDPMSActionFactory, registerPlugin(); ) PowerDevilDPMSAction::PowerDevilDPMSAction(QObject* parent, const QVariantList &args) : Action(parent) - , m_idleTime(0) - , m_inhibitScreen(0) // can't use PowerDevil::PolicyAgent enum because X11/X.h defines None as 0L - , m_oldKeyboardBrightnessValue(0) , m_fadeEffect(new PowerDevil::KWinKScreenHelperEffect()) - , d(new Private) { - setRequiredPolicies(PowerDevil::PolicyAgent::ChangeScreenSettings); - // We want to query for DPMS in the constructor, before anything else happens - d->defaultHandler = XSetErrorHandler(dropError); + ScopedCPointer capableReply(xcb_dpms_capable_reply(QX11Info::connection(), + xcb_dpms_capable(QX11Info::connection()), + nullptr)); - // Since we are in the constructor, we should check for support manually - if (!isSupported()) { - XSetErrorHandler(d->defaultHandler); - return; + if (capableReply && capableReply->capable) { + m_supported = true; } // Is the action being loaded outside the core? if (args.size() > 0) { if (args.first().toBool()) { qCDebug(POWERDEVIL) << "Action loaded from outside the core, skipping early init"; return; } } // Pretend we're unloading profiles here, as if the action is not enabled, DPMS should be switched off. onProfileUnload(); // Listen to the policy agent - connect(PowerDevil::PolicyAgent::instance(), - SIGNAL(unavailablePoliciesChanged(PowerDevil::PolicyAgent::RequiredPolicies)), - this, - SLOT(onUnavailablePoliciesChanged(PowerDevil::PolicyAgent::RequiredPolicies))); + connect(PowerDevil::PolicyAgent::instance(), &PowerDevil::PolicyAgent::unavailablePoliciesChanged, + this, &PowerDevilDPMSAction::onUnavailablePoliciesChanged); + // inhibitions persist over kded module unload/load m_inhibitScreen = PowerDevil::PolicyAgent::instance()->unavailablePolicies() & PowerDevil::PolicyAgent::ChangeScreenSettings; } -PowerDevilDPMSAction::~PowerDevilDPMSAction() -{ - delete d; -} - bool PowerDevilDPMSAction::isSupported() { - Display *dpy = QX11Info::display(); - int dummy; - - return DPMSQueryExtension(dpy, &dummy, &dummy) && DPMSCapable(dpy); + return m_supported; } void PowerDevilDPMSAction::onProfileUnload() { using namespace PowerDevil; - Display *dpy = QX11Info::display(); + if (!(PolicyAgent::instance()->unavailablePolicies() & PolicyAgent::ChangeScreenSettings)) { - DPMSDisable(dpy); + xcb_dpms_disable(QX11Info::connection()); } else { qCDebug(POWERDEVIL) << "Not performing DPMS action due to inhibition"; } - DPMSSetTimeouts(dpy, 0, 0, 0); + + xcb_dpms_set_timeouts(QX11Info::connection(), 0, 0, 0); } void PowerDevilDPMSAction::onWakeupFromIdle() { m_fadeEffect->stop(); if (m_oldKeyboardBrightnessValue > 0) { setKeyboardBrightnessHelper(m_oldKeyboardBrightnessValue); m_oldKeyboardBrightnessValue = 0; } } void PowerDevilDPMSAction::onIdleTimeout(int msec) { - Q_UNUSED(msec); - - //Do not inhibit anything even if idleTimeout reaches because we are inhibit + // Do not inhibit anything even if idleTimeout reaches because we are inhibit if (m_inhibitScreen) { return; } if (msec == m_idleTime * 1000 - 5000) { // fade out screen m_fadeEffect->start(); } else if (msec == m_idleTime * 1000) { const int brightness = backend()->brightnessValue(PowerDevil::BackendInterface::Keyboard); if (brightness > 0) { m_oldKeyboardBrightnessValue = brightness; setKeyboardBrightnessHelper(0); } } } void PowerDevilDPMSAction::setKeyboardBrightnessHelper(int brightness) { trigger(QVariantMap{ {"KeyboardBrightness", QVariant::fromValue(brightness)} }); } void PowerDevilDPMSAction::onProfileLoad() { using namespace PowerDevil; - Display *dpy = QX11Info::display(); + if (!(PolicyAgent::instance()->unavailablePolicies() & PolicyAgent::ChangeScreenSettings)) { - DPMSEnable(dpy); + xcb_dpms_enable(QX11Info::connection()); } else { qCDebug(POWERDEVIL) << "Not performing DPMS action due to inhibition"; return; } - XFlush(dpy); - XSetErrorHandler(d->defaultHandler); - // An unloaded action will have m_idleTime = 0: // DPMS enabled with zeroed timeouts is effectively disabled. // So onProfileLoad is always safe - DPMSSetTimeouts(dpy, (CARD16)m_idleTime, (CARD16)(m_idleTime * 1.5), (CARD16)(m_idleTime * 2)); - - XFlush(dpy); - XSetErrorHandler(d->defaultHandler); + xcb_dpms_set_timeouts(QX11Info::connection(), m_idleTime, m_idleTime * 1.5, m_idleTime * 2); } void PowerDevilDPMSAction::triggerImpl(const QVariantMap& args) { if (args.contains("KeyboardBrightness")) { backend()->setBrightnessValue(args["KeyboardBrightness"].toInt(), PowerDevil::BackendInterface::Keyboard); return; } - CARD16 dummy; - BOOL enabled; - Display *dpy = QX11Info::display(); - DPMSInfo(dpy, &dummy, &enabled); - - if (args["Type"].toString() == "TurnOff") { - if (enabled) { - DPMSForceLevel(dpy, DPMSModeOff); - } else { - DPMSEnable(dpy); - DPMSForceLevel(dpy, DPMSModeOff); - } - } else if (args["Type"].toString() == "Standby") { - if (enabled) { - DPMSForceLevel(dpy, DPMSModeStandby); - } else { - DPMSEnable(dpy); - DPMSForceLevel(dpy, DPMSModeStandby); - } - } else if (args["Type"].toString() == "Suspend") { - if (enabled) { - DPMSForceLevel(dpy, DPMSModeSuspend); - } else { - DPMSEnable(dpy); - DPMSForceLevel(dpy, DPMSModeSuspend); - } + const QString type = args.value(QStringLiteral("Type")).toString(); + int level = 0; + + if (type == QLatin1String("TurnOff")) { + level = XCB_DPMS_DPMS_MODE_OFF; + } else if (type == QLatin1String("Standby")) { + level = XCB_DPMS_DPMS_MODE_STANDBY; + } else if (type == QLatin1String("Suspend")) { + level = XCB_DPMS_DPMS_MODE_SUSPEND; + } else { + // this leaves DPMS enabled but if it's meant to be disabled + // then the timeouts will be zero and so effectively disabled + return; + } + + ScopedCPointer infoReply(xcb_dpms_info_reply(QX11Info::connection(), + xcb_dpms_info(QX11Info::connection()), + nullptr)); + + if (!infoReply) { + qCWarning(POWERDEVIL) << "Failed to query DPMS state, cannot trigger" << level; + return; + } + + if (!infoReply->state) { + xcb_dpms_enable(QX11Info::connection()); } - // this leaves DPMS enabled but if it's meant to be disabled - // then the timeouts will be zero and so effectively disabled + xcb_dpms_force_level(QX11Info::connection(), level); } bool PowerDevilDPMSAction::loadAction(const KConfigGroup& config) { m_idleTime = config.readEntry("idleTime", -1); if (m_idleTime > 0) { registerIdleTimeout(m_idleTime * 1000); registerIdleTimeout(m_idleTime * 1000 - 5000); // start screen fade a bit earlier to alert user } return true; } bool PowerDevilDPMSAction::onUnloadAction() { m_idleTime = 0; return Action::onUnloadAction(); } void PowerDevilDPMSAction::onUnavailablePoliciesChanged(PowerDevil::PolicyAgent::RequiredPolicies policies) { // only take action if screen inhibit changed PowerDevil::PolicyAgent::RequiredPolicies oldPolicy = m_inhibitScreen; m_inhibitScreen = policies & PowerDevil::PolicyAgent::ChangeScreenSettings; if (oldPolicy == m_inhibitScreen) { return; } if (m_inhibitScreen) { // Inhibition triggered: disable DPMS qCDebug(POWERDEVIL) << "Disabling DPMS due to inhibition"; - Display *dpy = QX11Info::display(); - DPMSSetTimeouts(dpy, 0, 0, 0); - DPMSDisable(dpy); // wakes the screen - do we want this? + xcb_dpms_set_timeouts(QX11Info::connection(), 0, 0, 0); + xcb_dpms_disable(QX11Info::connection()); // wakes the screen - do we want this? } else { // Inhibition removed: let's start again onProfileLoad(); qCDebug(POWERDEVIL) << "Restoring DPMS features after inhibition release"; } } #include "powerdevildpmsaction.moc" diff --git a/daemon/actions/dpms/powerdevildpmsaction.h b/daemon/actions/dpms/powerdevildpmsaction.h index 31e11c61..c74b45ba 100644 --- a/daemon/actions/dpms/powerdevildpmsaction.h +++ b/daemon/actions/dpms/powerdevildpmsaction.h @@ -1,69 +1,72 @@ /*************************************************************************** * Copyright (C) 2010 by Dario Freddi * + * Copyright (C) 2015 by Kai Uwe Broulik * * * * 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 POWERDEVILDPMSACTION_H #define POWERDEVILDPMSACTION_H #include #include +template using ScopedCPointer = QScopedPointer; + namespace PowerDevil { class KWinKScreenHelperEffect; } class PowerDevilDPMSAction : public PowerDevil::Action { Q_OBJECT Q_DISABLE_COPY(PowerDevilDPMSAction) public: - explicit PowerDevilDPMSAction(QObject* parent, const QVariantList&); - virtual ~PowerDevilDPMSAction(); + explicit PowerDevilDPMSAction(QObject *parent, const QVariantList &); + virtual ~PowerDevilDPMSAction() = default; protected: virtual void onProfileUnload(); virtual bool onUnloadAction(); virtual void onWakeupFromIdle(); virtual void onIdleTimeout(int msec); virtual void onProfileLoad(); - virtual void triggerImpl(const QVariantMap& args); + virtual void triggerImpl(const QVariantMap &args); bool isSupported(); public: - virtual bool loadAction(const KConfigGroup& config); + virtual bool loadAction(const KConfigGroup &config); private Q_SLOTS: void onUnavailablePoliciesChanged(PowerDevil::PolicyAgent::RequiredPolicies policies); private: void setKeyboardBrightnessHelper(int brightness); - int m_idleTime; - PowerDevil::PolicyAgent::RequiredPolicies m_inhibitScreen; + bool m_supported = false; + + int m_idleTime = 0; + PowerDevil::PolicyAgent::RequiredPolicies m_inhibitScreen = PowerDevil::PolicyAgent::None; - int m_oldKeyboardBrightnessValue; + int m_oldKeyboardBrightnessValue = 0; QScopedPointer m_fadeEffect; - class Private; - Private * const d; }; #endif // POWERDEVILDPMSACTION_H