[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 "manager.h"
|
||||||
|
|
||||||
|
#include <QDBusMessage>
|
||||||
|
|
||||||
namespace KWin {
|
namespace KWin {
|
||||||
namespace ColorCorrect {
|
namespace ColorCorrect {
|
||||||
|
|
||||||
ColorCorrectDBusInterface::ColorCorrectDBusInterface(Manager *parent)
|
ColorCorrectDBusInterface::ColorCorrectDBusInterface(Manager *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_manager(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);
|
connect(m_manager, &Manager::configChange, this, &ColorCorrectDBusInterface::nightColorConfigChanged);
|
||||||
new ColorCorrectAdaptor(this);
|
new ColorCorrectAdaptor(this);
|
||||||
QDBusConnection::sessionBus().registerObject(QStringLiteral("/ColorCorrect"), this);
|
QDBusConnection::sessionBus().registerObject(QStringLiteral("/ColorCorrect"), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ColorCorrectDBusInterface::isInhibited() const
|
||||||
|
{
|
||||||
|
return m_manager->isInhibited();
|
||||||
|
}
|
||||||
|
|
||||||
QHash<QString, QVariant> ColorCorrectDBusInterface::nightColorInfo()
|
QHash<QString, QVariant> ColorCorrectDBusInterface::nightColorInfo()
|
||||||
{
|
{
|
||||||
return m_manager->info();
|
return m_manager->info();
|
||||||
|
@ -50,5 +83,49 @@ void ColorCorrectDBusInterface::nightColorAutoLocationUpdate(double latitude, do
|
||||||
m_manager->autoLocationUpdate(latitude, longitude);
|
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 Manager;
|
||||||
|
|
||||||
class ColorCorrectDBusInterface : public QObject
|
class ColorCorrectDBusInterface : public QObject, public QDBusContext
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_CLASSINFO("D-Bus Interface", "org.kde.kwin.ColorCorrect")
|
Q_CLASSINFO("D-Bus Interface", "org.kde.kwin.ColorCorrect")
|
||||||
|
Q_PROPERTY(bool inhibited READ isInhibited)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ColorCorrectDBusInterface(Manager *parent);
|
explicit ColorCorrectDBusInterface(Manager *parent);
|
||||||
~ColorCorrectDBusInterface() override = default;
|
~ColorCorrectDBusInterface() override = default;
|
||||||
|
|
||||||
|
bool isInhibited() const;
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
/**
|
/**
|
||||||
* @brief Gives information about the current state of Night Color.
|
* @brief Gives information about the current state of Night Color.
|
||||||
|
@ -101,6 +104,16 @@ public Q_SLOTS:
|
||||||
* @since 5.12
|
* @since 5.12
|
||||||
*/
|
*/
|
||||||
void nightColorAutoLocationUpdate(double latitude, double longitude);
|
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:
|
Q_SIGNALS:
|
||||||
/**
|
/**
|
||||||
|
@ -115,8 +128,16 @@ Q_SIGNALS:
|
||||||
*/
|
*/
|
||||||
void nightColorConfigChanged(QHash<QString, QVariant> data);
|
void nightColorConfigChanged(QHash<QString, QVariant> data);
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void removeInhibitorService(const QString &serviceName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void uninhibit(const QString &serviceName, uint cookie);
|
||||||
|
|
||||||
Manager *m_manager;
|
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);
|
m_iface = new ColorCorrectDBusInterface(this);
|
||||||
connect(kwinApp(), &Application::workspaceCreated, this, &Manager::init);
|
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()
|
void Manager::init()
|
||||||
|
@ -145,7 +166,7 @@ void Manager::hardReset()
|
||||||
updateSunTimings(true);
|
updateSunTimings(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kwinApp()->platform()->supportsGammaControl() && m_active) {
|
if (kwinApp()->platform()->supportsGammaControl() && m_active && !isInhibited()) {
|
||||||
m_running = true;
|
m_running = true;
|
||||||
commitGammaRamps(currentTargetTemp());
|
commitGammaRamps(currentTargetTemp());
|
||||||
}
|
}
|
||||||
|
@ -159,41 +180,35 @@ void Manager::reparseConfigAndReset()
|
||||||
hardReset();
|
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()
|
void Manager::toggle()
|
||||||
{
|
{
|
||||||
if (!kwinApp()->platform()->supportsGammaControl()) {
|
m_isGloballyInhibited = !m_isGloballyInhibited;
|
||||||
return;
|
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);
|
if (!m_inhibitReferenceCount) {
|
||||||
|
resetAllTimers();
|
||||||
resetAllTimers();
|
emit inhibitedChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::initShortcuts()
|
void Manager::initShortcuts()
|
||||||
|
@ -279,9 +294,7 @@ void Manager::resetAllTimers()
|
||||||
{
|
{
|
||||||
cancelAllTimers();
|
cancelAllTimers();
|
||||||
if (kwinApp()->platform()->supportsGammaControl()) {
|
if (kwinApp()->platform()->supportsGammaControl()) {
|
||||||
if (m_active) {
|
m_running = m_active && !isInhibited();
|
||||||
m_running = true;
|
|
||||||
}
|
|
||||||
// we do this also for active being false in order to reset the temperature back to the day value
|
// we do this also for active being false in order to reset the temperature back to the day value
|
||||||
resetQuickAdjustTimer();
|
resetQuickAdjustTimer();
|
||||||
} else {
|
} else {
|
||||||
|
@ -542,7 +555,7 @@ bool Manager::daylight() const
|
||||||
|
|
||||||
int Manager::currentTargetTemp() const
|
int Manager::currentTargetTemp() const
|
||||||
{
|
{
|
||||||
if (!m_active) {
|
if (!m_running) {
|
||||||
return NEUTRAL_TEMPERATURE;
|
return NEUTRAL_TEMPERATURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,6 +126,24 @@ public:
|
||||||
*/
|
*/
|
||||||
void toggle();
|
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
|
// for auto tests
|
||||||
void reparseConfigAndReset();
|
void reparseConfigAndReset();
|
||||||
|
|
||||||
|
@ -136,6 +154,11 @@ public Q_SLOTS:
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void configChange(QHash<QString, QVariant> data);
|
void configChange(QHash<QString, QVariant> data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted whenever the night color manager is blocked or unblocked.
|
||||||
|
*/
|
||||||
|
void inhibitedChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initShortcuts();
|
void initShortcuts();
|
||||||
void readConfig();
|
void readConfig();
|
||||||
|
@ -162,9 +185,15 @@ private:
|
||||||
|
|
||||||
ColorCorrectDBusInterface *m_iface;
|
ColorCorrectDBusInterface *m_iface;
|
||||||
|
|
||||||
|
// Specifies whether Night Color is enabled.
|
||||||
bool m_active;
|
bool m_active;
|
||||||
|
|
||||||
|
// Specifies whether Night Color is currently running.
|
||||||
bool m_running = false;
|
bool m_running = false;
|
||||||
|
|
||||||
|
// Specifies whether Night Color is inhibited globally.
|
||||||
|
bool m_isGloballyInhibited = false;
|
||||||
|
|
||||||
NightColorMode m_mode = NightColorMode::Automatic;
|
NightColorMode m_mode = NightColorMode::Automatic;
|
||||||
|
|
||||||
// the previous and next sunrise/sunset intervals - in UTC time
|
// the previous and next sunrise/sunset intervals - in UTC time
|
||||||
|
@ -192,6 +221,7 @@ private:
|
||||||
int m_nightTargetTemp = DEFAULT_NIGHT_TEMPERATURE;
|
int m_nightTargetTemp = DEFAULT_NIGHT_TEMPERATURE;
|
||||||
|
|
||||||
int m_failedCommitAttempts = 0;
|
int m_failedCommitAttempts = 0;
|
||||||
|
int m_inhibitReferenceCount = 0;
|
||||||
|
|
||||||
// The Workspace class needs to call initShortcuts during initialization.
|
// The Workspace class needs to call initShortcuts during initialization.
|
||||||
friend class KWin::Workspace;
|
friend class KWin::Workspace;
|
||||||
|
|
|
@ -18,5 +18,39 @@
|
||||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QHash<QString,QVariant>"/>
|
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QHash<QString,QVariant>"/>
|
||||||
<arg type="a{sv}" direction="out"/>
|
<arg type="a{sv}" direction="out"/>
|
||||||
</signal>
|
</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>
|
</interface>
|
||||||
</node>
|
</node>
|
||||||
|
|
Loading…
Reference in a new issue