diff --git a/colorcorrection/colorcorrectdbusinterface.cpp b/colorcorrection/colorcorrectdbusinterface.cpp
index 5376d9b22f..c1a4d6fc93 100644
--- a/colorcorrection/colorcorrectdbusinterface.cpp
+++ b/colorcorrection/colorcorrectdbusinterface.cpp
@@ -23,18 +23,51 @@ along with this program. If not, see .
#include "manager.h"
+#include
+
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 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);
+ }
+}
+
}
}
diff --git a/colorcorrection/colorcorrectdbusinterface.h b/colorcorrection/colorcorrectdbusinterface.h
index 22570e86f4..481f71fa7b 100644
--- a/colorcorrection/colorcorrectdbusinterface.h
+++ b/colorcorrection/colorcorrectdbusinterface.h
@@ -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 data);
+private Q_SLOTS:
+ void removeInhibitorService(const QString &serviceName);
+
private:
+ void uninhibit(const QString &serviceName, uint cookie);
+
Manager *m_manager;
+ QDBusServiceWatcher *m_inhibitorWatcher;
+ QMultiHash m_inhibitors;
+ uint m_lastInhibitionCookie = 0;
};
}
diff --git a/colorcorrection/manager.cpp b/colorcorrection/manager.cpp
index f3ba2e64f2..5026730190 100644
--- a/colorcorrection/manager.cpp
+++ b/colorcorrection/manager.cpp
@@ -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;
}
diff --git a/colorcorrection/manager.h b/colorcorrection/manager.h
index 0f4e20248e..cad325acd2 100644
--- a/colorcorrection/manager.h
+++ b/colorcorrection/manager.h
@@ -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 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;
diff --git a/org.kde.kwin.ColorCorrect.xml b/org.kde.kwin.ColorCorrect.xml
index 0b83a01295..dd5b298a8f 100644
--- a/org.kde.kwin.ColorCorrect.xml
+++ b/org.kde.kwin.ColorCorrect.xml
@@ -18,5 +18,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+