[nightcolor] Introduce inhibition API
Summary: The new API allows to block Night Color temporarily. This can be useful for applications such as video games and plasma applets. CCBUG: 400418 Test Plan: Called inhibit() and uninhibit() from D-Feet. Reviewers: #kwin, davidedmundson Reviewed By: #kwin, davidedmundson Subscribers: kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D25786
This commit is contained in:
parent
216c005e28
commit
5bec89ac90
5 changed files with 211 additions and 36 deletions
|
@ -23,18 +23,51 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
#include "manager.h"
|
||||
|
||||
#include <QDBusMessage>
|
||||
|
||||
namespace KWin {
|
||||
namespace ColorCorrect {
|
||||
|
||||
ColorCorrectDBusInterface::ColorCorrectDBusInterface(Manager *parent)
|
||||
: QObject(parent)
|
||||
, m_manager(parent)
|
||||
, m_inhibitorWatcher(new QDBusServiceWatcher(this))
|
||||
{
|
||||
m_inhibitorWatcher->setConnection(QDBusConnection::sessionBus());
|
||||
m_inhibitorWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
|
||||
connect(m_inhibitorWatcher, &QDBusServiceWatcher::serviceUnregistered,
|
||||
this, &ColorCorrectDBusInterface::removeInhibitorService);
|
||||
|
||||
// Argh, all this code is just to send one innocent signal...
|
||||
connect(m_manager, &Manager::inhibitedChanged, this, [this] {
|
||||
QVariantMap changedProperties;
|
||||
changedProperties.insert(QStringLiteral("inhibited"), m_manager->isInhibited());
|
||||
|
||||
QDBusMessage message = QDBusMessage::createSignal(
|
||||
QStringLiteral("/ColorCorrect"),
|
||||
QStringLiteral("org.freedesktop.DBus.Properties"),
|
||||
QStringLiteral("PropertiesChanged")
|
||||
);
|
||||
|
||||
message.setArguments({
|
||||
QStringLiteral("org.kde.kwin.ColorCorrect"),
|
||||
changedProperties,
|
||||
QStringList(), // invalidated_properties
|
||||
});
|
||||
|
||||
QDBusConnection::sessionBus().send(message);
|
||||
});
|
||||
|
||||
connect(m_manager, &Manager::configChange, this, &ColorCorrectDBusInterface::nightColorConfigChanged);
|
||||
new ColorCorrectAdaptor(this);
|
||||
QDBusConnection::sessionBus().registerObject(QStringLiteral("/ColorCorrect"), this);
|
||||
}
|
||||
|
||||
bool ColorCorrectDBusInterface::isInhibited() const
|
||||
{
|
||||
return m_manager->isInhibited();
|
||||
}
|
||||
|
||||
QHash<QString, QVariant> ColorCorrectDBusInterface::nightColorInfo()
|
||||
{
|
||||
return m_manager->info();
|
||||
|
@ -50,5 +83,49 @@ void ColorCorrectDBusInterface::nightColorAutoLocationUpdate(double latitude, do
|
|||
m_manager->autoLocationUpdate(latitude, longitude);
|
||||
}
|
||||
|
||||
uint ColorCorrectDBusInterface::inhibit()
|
||||
{
|
||||
const QString serviceName = QDBusContext::message().service();
|
||||
|
||||
if (m_inhibitors.values(serviceName).isEmpty()) {
|
||||
m_inhibitorWatcher->addWatchedService(serviceName);
|
||||
}
|
||||
|
||||
m_inhibitors.insert(serviceName, ++m_lastInhibitionCookie);
|
||||
|
||||
m_manager->inhibit();
|
||||
|
||||
return m_lastInhibitionCookie;
|
||||
}
|
||||
|
||||
void ColorCorrectDBusInterface::uninhibit(uint cookie)
|
||||
{
|
||||
const QString serviceName = QDBusContext::message().service();
|
||||
|
||||
uninhibit(serviceName, cookie);
|
||||
}
|
||||
|
||||
void ColorCorrectDBusInterface::uninhibit(const QString &serviceName, uint cookie)
|
||||
{
|
||||
const int removedCount = m_inhibitors.remove(serviceName, cookie);
|
||||
if (!removedCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_inhibitors.values(serviceName).isEmpty()) {
|
||||
m_inhibitorWatcher->removeWatchedService(serviceName);
|
||||
}
|
||||
|
||||
m_manager->uninhibit();
|
||||
}
|
||||
|
||||
void ColorCorrectDBusInterface::removeInhibitorService(const QString &serviceName)
|
||||
{
|
||||
const auto cookies = m_inhibitors.values(serviceName);
|
||||
for (const uint &cookie : cookies) {
|
||||
uninhibit(serviceName, cookie);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,15 +32,18 @@ namespace ColorCorrect
|
|||
|
||||
class Manager;
|
||||
|
||||
class ColorCorrectDBusInterface : public QObject
|
||||
class ColorCorrectDBusInterface : public QObject, public QDBusContext
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.kde.kwin.ColorCorrect")
|
||||
Q_PROPERTY(bool inhibited READ isInhibited)
|
||||
|
||||
public:
|
||||
explicit ColorCorrectDBusInterface(Manager *parent);
|
||||
~ColorCorrectDBusInterface() override = default;
|
||||
|
||||
bool isInhibited() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* @brief Gives information about the current state of Night Color.
|
||||
|
@ -101,6 +104,16 @@ public Q_SLOTS:
|
|||
* @since 5.12
|
||||
*/
|
||||
void nightColorAutoLocationUpdate(double latitude, double longitude);
|
||||
/**
|
||||
* @brief Temporarily blocks Night Color.
|
||||
* @since 5.18
|
||||
*/
|
||||
uint inhibit();
|
||||
/**
|
||||
* @brief Cancels the previous call to inhibit().
|
||||
* @since 5.18
|
||||
*/
|
||||
void uninhibit(uint cookie);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
|
@ -115,8 +128,16 @@ Q_SIGNALS:
|
|||
*/
|
||||
void nightColorConfigChanged(QHash<QString, QVariant> data);
|
||||
|
||||
private Q_SLOTS:
|
||||
void removeInhibitorService(const QString &serviceName);
|
||||
|
||||
private:
|
||||
void uninhibit(const QString &serviceName, uint cookie);
|
||||
|
||||
Manager *m_manager;
|
||||
QDBusServiceWatcher *m_inhibitorWatcher;
|
||||
QMultiHash<QString, uint> m_inhibitors;
|
||||
uint m_lastInhibitionCookie = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -61,6 +61,27 @@ Manager::Manager(QObject *parent)
|
|||
{
|
||||
m_iface = new ColorCorrectDBusInterface(this);
|
||||
connect(kwinApp(), &Application::workspaceCreated, this, &Manager::init);
|
||||
|
||||
// Display a message when Night Color is (un)inhibited.
|
||||
connect(this, &Manager::inhibitedChanged, this, [this] {
|
||||
// TODO: Maybe use different icons?
|
||||
const QString iconName = isInhibited()
|
||||
? QStringLiteral("preferences-desktop-display-nightcolor-off")
|
||||
: QStringLiteral("preferences-desktop-display-nightcolor-on");
|
||||
|
||||
const QString text = isInhibited()
|
||||
? i18nc("Night Color was disabled", "Night Color Off")
|
||||
: i18nc("Night Color was enabled", "Night Color On");
|
||||
|
||||
QDBusMessage message = QDBusMessage::createMethodCall(
|
||||
QStringLiteral("org.kde.plasmashell"),
|
||||
QStringLiteral("/org/kde/osdService"),
|
||||
QStringLiteral("org.kde.osdService"),
|
||||
QStringLiteral("showText"));
|
||||
message.setArguments({ iconName, text });
|
||||
|
||||
QDBusConnection::sessionBus().asyncCall(message);
|
||||
});
|
||||
}
|
||||
|
||||
void Manager::init()
|
||||
|
@ -145,7 +166,7 @@ void Manager::hardReset()
|
|||
updateSunTimings(true);
|
||||
}
|
||||
|
||||
if (kwinApp()->platform()->supportsGammaControl() && m_active) {
|
||||
if (kwinApp()->platform()->supportsGammaControl() && m_active && !isInhibited()) {
|
||||
m_running = true;
|
||||
commitGammaRamps(currentTargetTemp());
|
||||
}
|
||||
|
@ -159,41 +180,35 @@ void Manager::reparseConfigAndReset()
|
|||
hardReset();
|
||||
}
|
||||
|
||||
// FIXME: The internal OSD service doesn't work on X11 right now. Once the QPA
|
||||
// is ported away from Wayland, drop this function in favor of the internal
|
||||
// OSD service.
|
||||
static void showStatusOsd(bool enabled)
|
||||
{
|
||||
// TODO: Maybe use different icons?
|
||||
const QString iconName = enabled
|
||||
? QStringLiteral("preferences-desktop-display-nightcolor-on")
|
||||
: QStringLiteral("preferences-desktop-display-nightcolor-off");
|
||||
|
||||
const QString text = enabled
|
||||
? i18nc("Night Color was enabled", "Night Color On")
|
||||
: i18nc("Night Color was disabled", "Night Color Off");
|
||||
|
||||
QDBusMessage message = QDBusMessage::createMethodCall(
|
||||
QStringLiteral("org.kde.plasmashell"),
|
||||
QStringLiteral("/org/kde/osdService"),
|
||||
QStringLiteral("org.kde.osdService"),
|
||||
QStringLiteral("showText"));
|
||||
message.setArguments({ iconName, text });
|
||||
|
||||
QDBusConnection::sessionBus().asyncCall(message);
|
||||
}
|
||||
|
||||
void Manager::toggle()
|
||||
{
|
||||
if (!kwinApp()->platform()->supportsGammaControl()) {
|
||||
return;
|
||||
m_isGloballyInhibited = !m_isGloballyInhibited;
|
||||
m_isGloballyInhibited ? inhibit() : uninhibit();
|
||||
}
|
||||
|
||||
bool Manager::isInhibited() const
|
||||
{
|
||||
return m_inhibitReferenceCount;
|
||||
}
|
||||
|
||||
void Manager::inhibit()
|
||||
{
|
||||
m_inhibitReferenceCount++;
|
||||
|
||||
if (m_inhibitReferenceCount == 1) {
|
||||
resetAllTimers();
|
||||
emit inhibitedChanged();
|
||||
}
|
||||
}
|
||||
|
||||
m_active = !m_active;
|
||||
void Manager::uninhibit()
|
||||
{
|
||||
m_inhibitReferenceCount--;
|
||||
|
||||
showStatusOsd(m_active);
|
||||
|
||||
resetAllTimers();
|
||||
if (!m_inhibitReferenceCount) {
|
||||
resetAllTimers();
|
||||
emit inhibitedChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::initShortcuts()
|
||||
|
@ -279,9 +294,7 @@ void Manager::resetAllTimers()
|
|||
{
|
||||
cancelAllTimers();
|
||||
if (kwinApp()->platform()->supportsGammaControl()) {
|
||||
if (m_active) {
|
||||
m_running = true;
|
||||
}
|
||||
m_running = m_active && !isInhibited();
|
||||
// we do this also for active being false in order to reset the temperature back to the day value
|
||||
resetQuickAdjustTimer();
|
||||
} else {
|
||||
|
@ -542,7 +555,7 @@ bool Manager::daylight() const
|
|||
|
||||
int Manager::currentTargetTemp() const
|
||||
{
|
||||
if (!m_active) {
|
||||
if (!m_running) {
|
||||
return NEUTRAL_TEMPERATURE;
|
||||
}
|
||||
|
||||
|
|
|
@ -126,6 +126,24 @@ public:
|
|||
*/
|
||||
void toggle();
|
||||
|
||||
/**
|
||||
* Returns @c true if the night color manager is blocked; otherwise @c false.
|
||||
*/
|
||||
bool isInhibited() const;
|
||||
|
||||
/**
|
||||
* Temporarily blocks the night color manager.
|
||||
*
|
||||
* After calling this method, the screen color temperature will be reverted
|
||||
* back to 6500C. When you're done, call uninhibit() method.
|
||||
*/
|
||||
void inhibit();
|
||||
|
||||
/**
|
||||
* Attempts to unblock the night color manager.
|
||||
*/
|
||||
void uninhibit();
|
||||
|
||||
// for auto tests
|
||||
void reparseConfigAndReset();
|
||||
|
||||
|
@ -136,6 +154,11 @@ public Q_SLOTS:
|
|||
Q_SIGNALS:
|
||||
void configChange(QHash<QString, QVariant> data);
|
||||
|
||||
/**
|
||||
* Emitted whenever the night color manager is blocked or unblocked.
|
||||
*/
|
||||
void inhibitedChanged();
|
||||
|
||||
private:
|
||||
void initShortcuts();
|
||||
void readConfig();
|
||||
|
@ -162,9 +185,15 @@ private:
|
|||
|
||||
ColorCorrectDBusInterface *m_iface;
|
||||
|
||||
// Specifies whether Night Color is enabled.
|
||||
bool m_active;
|
||||
|
||||
// Specifies whether Night Color is currently running.
|
||||
bool m_running = false;
|
||||
|
||||
// Specifies whether Night Color is inhibited globally.
|
||||
bool m_isGloballyInhibited = false;
|
||||
|
||||
NightColorMode m_mode = NightColorMode::Automatic;
|
||||
|
||||
// the previous and next sunrise/sunset intervals - in UTC time
|
||||
|
@ -192,6 +221,7 @@ private:
|
|||
int m_nightTargetTemp = DEFAULT_NIGHT_TEMPERATURE;
|
||||
|
||||
int m_failedCommitAttempts = 0;
|
||||
int m_inhibitReferenceCount = 0;
|
||||
|
||||
// The Workspace class needs to call initShortcuts during initialization.
|
||||
friend class KWin::Workspace;
|
||||
|
|
|
@ -18,5 +18,39 @@
|
|||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QHash<QString,QVariant>"/>
|
||||
<arg type="a{sv}" direction="out"/>
|
||||
</signal>
|
||||
|
||||
<!--
|
||||
Creates an inhibition lock for Night Color.
|
||||
|
||||
You can use this method to temporarily disable Night Color feature.
|
||||
After calling this method, the screen color temperature will be set
|
||||
back to the neutral temperature (6500K).
|
||||
|
||||
This method returns a cookie that uniquely identifies the inhibition
|
||||
request. You must pass the cookie to uninhibit() when you're done.
|
||||
|
||||
Note that the inhibition lock will be released automatically when
|
||||
the service, which requested it, is unregistered.
|
||||
|
||||
A client is allowed to hold more than just one inhibition lock.
|
||||
-->
|
||||
<method name="inhibit">
|
||||
<arg name="cookie" type="u" direction="out"/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
Releases an inhibition lock identified by the given cookie.
|
||||
|
||||
Note that the inhibition lock will be released automatically when
|
||||
the service, which requested it, is unregistered.
|
||||
-->
|
||||
<method name="uninhibit">
|
||||
<arg name="cookie" type="u" direction="in"/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
This property holds a value to indicate whether Night Color is inhibited.
|
||||
-->
|
||||
<property name="inhibited" type="b" access="read"/>
|
||||
</interface>
|
||||
</node>
|
||||
|
|
Loading…
Reference in a new issue