diff --git a/applets/notifications/package/contents/ui/FullRepresentation.qml b/applets/notifications/package/contents/ui/FullRepresentation.qml
--- a/applets/notifications/package/contents/ui/FullRepresentation.qml
+++ b/applets/notifications/package/contents/ui/FullRepresentation.qml
@@ -98,6 +98,8 @@
if (Globals.inhibited) {
notificationSettings.notificationsInhibitedUntil = undefined;
notificationSettings.revokeApplicationInhibitions();
+ // overrules current mirrored screen setup, updates again when screen configuration changes
+ notificationSettings.screensMirrored = false;
notificationSettings.save();
}
@@ -222,6 +224,8 @@
var inhibitedUntil = notificationSettings.notificationsInhibitedUntil;
var inhibitedByApp = notificationSettings.notificationsInhibitedByApplication;
+ var inhibitedByMirroredScreens = notificationSettings.inhibitNotificationsWhenScreensMirrored
+ && notificationSettings.screensMirrored;
var sections = [];
@@ -247,6 +251,10 @@
}
}
+ if (inhibitedByMirroredScreens) {
+ sections.push(i18nc("Do not disturb because external mirrored screens connected", "Screens are mirrored"))
+ }
+
return sections.join(" ยท ");
}
visible: text !== ""
diff --git a/applets/notifications/package/contents/ui/global/Globals.qml b/applets/notifications/package/contents/ui/global/Globals.qml
--- a/applets/notifications/package/contents/ui/global/Globals.qml
+++ b/applets/notifications/package/contents/ui/global/Globals.qml
@@ -204,6 +204,10 @@
inhibited |= true;
}
+ if (notificationSettings.inhibitNotificationsWhenScreensMirrored) {
+ inhibited |= notificationSettings.screensMirrored;
+ }
+
return inhibited;
});
}
diff --git a/libnotificationmanager/CMakeLists.txt b/libnotificationmanager/CMakeLists.txt
--- a/libnotificationmanager/CMakeLists.txt
+++ b/libnotificationmanager/CMakeLists.txt
@@ -9,6 +9,7 @@
server.cpp
server_p.cpp
settings.cpp
+ mirroredscreenstracker.cpp
notifications.cpp
notification.cpp
@@ -79,6 +80,7 @@
KF5::KIOFileWidgets
KF5::Plasma
KF5::ProcessCore
+ KF5::Screen
KF5::Service
)
diff --git a/libnotificationmanager/kcfg/donotdisturbsettings.kcfg b/libnotificationmanager/kcfg/donotdisturbsettings.kcfg
--- a/libnotificationmanager/kcfg/donotdisturbsettings.kcfg
+++ b/libnotificationmanager/kcfg/donotdisturbsettings.kcfg
@@ -10,6 +10,10 @@
+
+ true
+
+
false
diff --git a/libnotificationmanager/mirroredscreenstracker.cpp b/libnotificationmanager/mirroredscreenstracker.cpp
new file mode 100644
--- /dev/null
+++ b/libnotificationmanager/mirroredscreenstracker.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2019 Kai Uwe Broulik
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) version 3, or any
+ * later version accepted by the membership of KDE e.V. (or its
+ * successor approved by the membership of KDE e.V.), which shall
+ * act as a proxy defined in Section 6 of version 3 of the license.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ */
+
+#include "mirroredscreenstracker_p.h"
+
+#include
+
+#include
+#include
+#include
+
+#include "debug.h"
+
+using namespace NotificationManager;
+
+MirroredScreensTracker::MirroredScreensTracker()
+ : QObject(nullptr)
+{
+ connect(new KScreen::GetConfigOperation(KScreen::GetConfigOperation::NoEDID), &KScreen::ConfigOperation::finished, this,
+ [this](KScreen::ConfigOperation *op) {
+ m_screenConfiguration = qobject_cast(op)->config();
+ checkScreensMirrored();
+
+ KScreen::ConfigMonitor::instance()->addConfig(m_screenConfiguration);
+ connect(KScreen::ConfigMonitor::instance(), &KScreen::ConfigMonitor::configurationChanged,
+ this, &MirroredScreensTracker::checkScreensMirrored);
+ });
+}
+
+MirroredScreensTracker::~MirroredScreensTracker() = default;
+
+MirroredScreensTracker::Ptr MirroredScreensTracker::createTracker()
+{
+ static QWeakPointer s_instance;
+ if (!s_instance) {
+ QSharedPointer ptr(new MirroredScreensTracker());
+ s_instance = ptr.toWeakRef();
+ return ptr;
+ }
+ return s_instance.toStrongRef();
+}
+
+bool MirroredScreensTracker::screensMirrored() const
+{
+ return m_screensMirrored;
+}
+
+void MirroredScreensTracker::setScreensMirrored(bool mirrored)
+{
+ if (m_screensMirrored != mirrored) {
+ m_screensMirrored = mirrored;
+ emit screensMirroredChanged(mirrored);
+ }
+}
+
+void MirroredScreensTracker::checkScreensMirrored()
+{
+ if (!m_screenConfiguration) {
+ setScreensMirrored(false);
+ return;
+ }
+
+ const auto outputs = m_screenConfiguration->outputs();
+ for (const KScreen::OutputPtr &output : outputs) {
+ if (!output->isConnected() || !output->isEnabled()) {
+ continue;
+ }
+
+ for (const KScreen::OutputPtr &checkOutput : outputs) {
+ if (checkOutput == output) {
+ continue;
+ }
+
+ if (output->geometry().intersects(checkOutput->geometry())) {
+ qCDebug(NOTIFICATIONMANAGER) << "Screen geometry" << checkOutput->geometry() << "intersects" << output->geometry() << "- considering them to be mirrored";
+ setScreensMirrored(true);
+ return;
+ }
+ }
+ }
+
+ setScreensMirrored(false);
+}
diff --git a/libnotificationmanager/mirroredscreenstracker_p.h b/libnotificationmanager/mirroredscreenstracker_p.h
new file mode 100644
--- /dev/null
+++ b/libnotificationmanager/mirroredscreenstracker_p.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2019 Kai Uwe Broulik
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) version 3, or any
+ * later version accepted by the membership of KDE e.V. (or its
+ * successor approved by the membership of KDE e.V.), which shall
+ * act as a proxy defined in Section 6 of version 3 of the license.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ */
+
+#pragma once
+
+#include
+#include
+
+#include
+
+namespace NotificationManager
+{
+
+/**
+ * @short Tracks whether there are any mirrored screens
+ *
+ * @author Kai Uwe Broulik
+ **/
+class MirroredScreensTracker : public QObject
+{
+ Q_OBJECT
+
+public:
+ ~MirroredScreensTracker();
+
+ using Ptr = QSharedPointer;
+ static Ptr createTracker();
+
+ bool screensMirrored() const;
+ /**
+ * Set whether screens are mirrored
+ *
+ * This is public so that automatic do not disturb mode when screens are mirrored
+ * can be disabled temporarily until screen configuration changes again.
+ */
+ void setScreensMirrored(bool mirrored);
+ Q_SIGNAL void screensMirroredChanged(bool mirrored);
+
+private:
+ MirroredScreensTracker();
+ Q_DISABLE_COPY(MirroredScreensTracker)
+
+ void checkScreensMirrored();
+
+ KScreen::ConfigPtr m_screenConfiguration;
+ bool m_screensMirrored = false;
+
+};
+
+} // namespace NotificationManager
diff --git a/libnotificationmanager/settings.h b/libnotificationmanager/settings.h
--- a/libnotificationmanager/settings.h
+++ b/libnotificationmanager/settings.h
@@ -169,6 +169,28 @@
READ notificationInhibitionReasons
NOTIFY notificationInhibitionApplicationsChanged)
+ /**
+ * Whether to enable do not disturb mode when screens are mirrored/overlapping
+ *
+ * @since 5.17
+ */
+ Q_PROPERTY(bool inhibitNotificationsWhenScreensMirrored
+ READ inhibitNotificationsWhenScreensMirrored
+ WRITE setInhibitNotificationsWhenScreensMirrored
+ NOTIFY settingsChanged)
+
+ /**
+ * Whether there currently are mirrored/overlapping screens
+ *
+ * This property is only updated when @c inhibitNotificationsWhenScreensMirrored
+ * is set to true, otherwise it is always false.
+ * You can assign false to this property if you want to temporarily revoke automatic do not disturb
+ * mode when screens are mirrored until the screen configuration changes.
+ *
+ * @since 5.17
+ */
+ Q_PROPERTY(bool screensMirrored READ screensMirrored WRITE setScreensMirrored NOTIFY screensMirroredChanged)
+
/**
* Whether notification sounds should be disabled
*
@@ -299,6 +321,12 @@
QStringList notificationInhibitionApplications() const;
QStringList notificationInhibitionReasons() const;
+ bool inhibitNotificationsWhenScreensMirrored() const;
+ void setInhibitNotificationsWhenScreensMirrored(bool mirrored);
+
+ bool screensMirrored() const;
+ void setScreensMirrored(bool enable);
+
bool notificationSoundsInhibited() const;
void setNotificationSoundsInhibited(bool inhibited);
@@ -321,6 +349,8 @@
void notificationsInhibitedByApplicationChanged(bool notificationsInhibitedByApplication);
void notificationInhibitionApplicationsChanged();
+ void screensMirroredChanged();
+
private:
class Private;
QScopedPointer d;
diff --git a/libnotificationmanager/settings.cpp b/libnotificationmanager/settings.cpp
--- a/libnotificationmanager/settings.cpp
+++ b/libnotificationmanager/settings.cpp
@@ -26,6 +26,7 @@
#include
#include "server.h"
+#include "mirroredscreenstracker_p.h"
#include "debug.h"
// Settings
@@ -59,6 +60,8 @@
KConfigWatcher::Ptr watcher;
QMetaObject::Connection watcherConnection;
+ MirroredScreensTracker::Ptr mirroredScreensTracker;
+
bool live = false; // set to true initially in constructor
bool dirty = false;
@@ -180,6 +183,11 @@
this, &Settings::notificationsInhibitedByApplicationChanged);
connect(&Server::self(), &Server::inhibitionApplicationsChanged,
this, &Settings::notificationInhibitionApplicationsChanged);
+
+ if (DoNotDisturbSettings::whenScreensMirrored()) {
+ d->mirroredScreensTracker = MirroredScreensTracker::createTracker();
+ connect(d->mirroredScreensTracker.data(), &MirroredScreensTracker::screensMirroredChanged, this, &Settings::screensMirroredChanged);
+ }
}
Settings::~Settings()
@@ -300,6 +308,22 @@
if (group.name() == QLatin1String("DoNotDisturb")) {
DoNotDisturbSettings::self()->load();
+
+ bool emitScreensMirroredChanged = false;
+ if (DoNotDisturbSettings::whenScreensMirrored()) {
+ if (!d->mirroredScreensTracker) {
+ d->mirroredScreensTracker = MirroredScreensTracker::createTracker();
+ emitScreensMirroredChanged = d->mirroredScreensTracker->screensMirrored();
+ connect(d->mirroredScreensTracker.data(), &MirroredScreensTracker::screensMirroredChanged, this, &Settings::screensMirroredChanged);
+ }
+ } else if (d->mirroredScreensTracker) {
+ emitScreensMirroredChanged = d->mirroredScreensTracker->screensMirrored();
+ d->mirroredScreensTracker.reset();
+ }
+
+ if (emitScreensMirroredChanged) {
+ emit screensMirroredChanged();
+ }
} else if (group.name() == QLatin1String("Notifications")) {
NotificationSettings::self()->load();
} else if (group.name() == QLatin1String("Jobs")) {
@@ -541,6 +565,38 @@
return Server::self().inhibitionReasons();
}
+bool Settings::inhibitNotificationsWhenScreensMirrored() const
+{
+ return DoNotDisturbSettings::whenScreensMirrored();
+}
+
+void Settings::setInhibitNotificationsWhenScreensMirrored(bool inhibit)
+{
+ if (inhibit == inhibitNotificationsWhenScreensMirrored()) {
+ return;
+ }
+
+ DoNotDisturbSettings::setWhenScreensMirrored(inhibit);
+ d->setDirty(true);
+}
+
+bool Settings::screensMirrored() const
+{
+ return d->mirroredScreensTracker && d->mirroredScreensTracker->screensMirrored();
+}
+
+void Settings::setScreensMirrored(bool mirrored)
+{
+ if (mirrored) {
+ qCWarning(NOTIFICATIONMANAGER) << "Cannot forcefully set screens mirrored";
+ return;
+ }
+
+ if (d->mirroredScreensTracker) {
+ d->mirroredScreensTracker->setScreensMirrored(mirrored);
+ }
+}
+
void Settings::revokeApplicationInhibitions()
{
Server::self().clearInhibitions();