[pim/kalarm] /: Don't execute display alarms while desktop notifications are inhibited
David Jarvie
null at kde.org
Thu Oct 22 00:48:54 BST 2020
Git commit 9e8e3f63c0243e04009414701efb541ab196fc2b by David Jarvie.
Committed on 21/10/2020 at 23:45.
Pushed by djarvie into branch 'master'.
Don't execute display alarms while desktop notifications are inhibited
M +2 -1 Changelog
M +6 -1 doc/index.docbook
M +3 -0 src/CMakeLists.txt
A +28 -0 src/data/org.freedesktop.DBus.Properties.xml
A +60 -0 src/data/org.freedesktop.Notifications.xml
M +1 -1 src/editdlg.cpp
M +94 -21 src/kalarmapp.cpp
M +7 -2 src/kalarmapp.h
M +62 -17 src/resourcescalendar.cpp
M +5 -3 src/resourcescalendar.h
https://invent.kde.org/pim/kalarm/commit/9e8e3f63c0243e04009414701efb541ab196fc2b
diff --git a/Changelog b/Changelog
index cead132b..42d5e2db 100644
--- a/Changelog
+++ b/Changelog
@@ -1,7 +1,8 @@
KAlarm Change Log
-=== Version 3.1.0 (KDE Applications 20.12) --- 24 September 2020 ===
+=== Version 3.1.0 (KDE Applications 20.12) --- 22 October 2020 ===
+ Add option to show alarm message as a notification instead of in a window [KDE Bug 345922]
++ Don't execute display alarms while desktop notifications are inhibited.
=== Version 3.0.3 (KDE Applications 20.08.3) --- 15 October 2020 ===
+ Prevent resources being disabled at logout [KDE Bug 427722]
diff --git a/doc/index.docbook b/doc/index.docbook
index ed86cc44..663e673b 100644
--- a/doc/index.docbook
+++ b/doc/index.docbook
@@ -39,7 +39,7 @@
<!-- Don't change format of date and version of the documentation -->
-<date>2020-09-24</date>
+<date>2020-10-22</date>
<releaseinfo>3.1.0 (Applications 20.12)</releaseinfo>
<abstract>
@@ -1926,6 +1926,11 @@ depending on the option chosen in the
<link linkend="alarm-edit-dlg">Alarm Edit dialog</link>. These two
display options are described below.</para>
+<para>If you inhibit notifications for the desktop, the execution of
+display alarms will be suspended until notifications are re-enabled.
+Note that this applies to all display alarms, regardless of whether
+they are displayed in windows or as notifications.</para>
+
<sect2 id="message-window">
<title>Alarm Message Window</title>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 96e028b5..821b5058 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -145,6 +145,9 @@ qt5_add_dbus_adaptor(kalarm_bin_SRCS data/org.kde.kalarm.kalarm.xml dbushandler.
qt5_add_dbus_interfaces(kalarm_bin_SRCS data/org.kde.kmail.kmail.xml)
+qt5_add_dbus_interface(kalarm_bin_SRCS data/org.freedesktop.Notifications.xml notifications_interface)
+qt5_add_dbus_interface(kalarm_bin_SRCS data/org.freedesktop.DBus.Properties.xml dbusproperties)
+
kcfg_generate_dbus_interface(${CMAKE_CURRENT_SOURCE_DIR}/data/kalarmresource.kcfg org.kde.Akonadi.KAlarm.Settings)
qt5_add_dbus_interface(kalarm_bin_SRCS ${CMAKE_CURRENT_BINARY_DIR}/org.kde.Akonadi.KAlarm.Settings.xml kalarmsettings KAlarmSettings)
diff --git a/src/data/org.freedesktop.DBus.Properties.xml b/src/data/org.freedesktop.DBus.Properties.xml
new file mode 100644
index 00000000..688ed108
--- /dev/null
+++ b/src/data/org.freedesktop.DBus.Properties.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<!-- GDBus 2.32.4 -->
+<node>
+ <interface name="org.freedesktop.DBus.Properties">
+ <method name="Get">
+ <arg type="s" name="interface_name" direction="in"/>
+ <arg type="s" name="property_name" direction="in"/>
+ <arg type="v" name="value" direction="out"/>
+ </method>
+ <method name="GetAll">
+ <arg type="s" name="interface_name" direction="in"/>
+ <arg type="a{sv}" name="properties" direction="out"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap" />
+ </method>
+ <method name="Set">
+ <arg type="s" name="interface_name" direction="in"/>
+ <arg type="s" name="property_name" direction="in"/>
+ <arg type="v" name="value" direction="in"/>
+ </method>
+ <signal name="PropertiesChanged">
+ <arg type="s" name="interface_name"/>
+ <arg type="a{sv}" name="changed_properties"/>
+ <arg type="as" name="invalidated_properties"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap" />
+ </signal>
+ </interface>
+</node>
diff --git a/src/data/org.freedesktop.Notifications.xml b/src/data/org.freedesktop.Notifications.xml
new file mode 100644
index 00000000..fc0825df
--- /dev/null
+++ b/src/data/org.freedesktop.Notifications.xml
@@ -0,0 +1,60 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.freedesktop.Notifications">
+ <signal name="NotificationClosed">
+ <arg name="id" type="u" direction="out"/>
+ <arg name="reason" type="u" direction="out"/>
+ </signal>
+ <signal name="ActionInvoked">
+ <arg name="id" type="u" direction="out"/>
+ <arg name="action_key" type="s" direction="out"/>
+ </signal>
+ <method name="Notify">
+ <annotation name="org.qtproject.QtDBus.QtTypeName.In6" value="QVariantMap"/>
+ <arg type="u" direction="out"/>
+ <arg name="app_name" type="s" direction="in"/>
+ <arg name="replaces_id" type="u" direction="in"/>
+ <arg name="app_icon" type="s" direction="in"/>
+ <arg name="summary" type="s" direction="in"/>
+ <arg name="body" type="s" direction="in"/>
+ <arg name="actions" type="as" direction="in"/>
+ <arg name="hints" type="a{sv}" direction="in"/>
+ <arg name="timeout" type="i" direction="in"/>
+ </method>
+ <method name="CloseNotification">
+ <arg name="id" type="u" direction="in"/>
+ </method>
+ <method name="GetCapabilities">
+ <arg type="as" name="caps" direction="out"/>
+ </method>
+ <method name="GetServerInformation">
+ <arg type="s" name="name" direction="out"/>
+ <arg type="s" name="vendor" direction="out"/>
+ <arg type="s" name="version" direction="out"/>
+ <arg type="s" name="spec_version" direction="out"/>
+ </method>
+
+ <!-- Inhibitions -->
+ <method name="Inhibit">
+ <annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="QVariantMap"/>
+ <arg type="u" direction="out"/>
+ <arg name="desktop_entry" type="s" direction="in"/>
+ <arg name="reason" type="s" direction="in"/>
+ <arg name="hints" type="a{sv}" direction="in"/>
+ </method>
+
+ <method name="UnInhibit">
+ <arg type="u" direction="in"/>
+ </method>
+
+ <property name="Inhibited" type="b" access="read">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
+ </property>
+
+ <!--<method name="ListInhibitors">
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QList<Inhibition>"/>
+ <arg name="inhibitors" type="a(ssa{sv})" direction="out"/>
+ </method>-->
+
+ </interface>
+</node>
diff --git a/src/editdlg.cpp b/src/editdlg.cpp
index cb73bde0..48fdf076 100644
--- a/src/editdlg.cpp
+++ b/src/editdlg.cpp
@@ -1166,7 +1166,7 @@ void EditAlarmDlg::slotTry()
event.setEventId(mEventId);
}
type_aboutToTry();
- void* result = theApp()->execAlarm(event, event.firstAlarm(), KAlarmApp::NoRecordCmdError);
+ void* result = theApp()->execAlarm(event, event.firstAlarm(), KAlarmApp::NoRecordCmdError | KAlarmApp::NoNotifyInhibit);
type_executedTry(text, result);
}
}
diff --git a/src/kalarmapp.cpp b/src/kalarmapp.cpp
index ac03d923..407e6f81 100644
--- a/src/kalarmapp.cpp
+++ b/src/kalarmapp.cpp
@@ -30,6 +30,8 @@
#include "lib/desktop.h"
#include "lib/messagebox.h"
#include "lib/shellprocess.h"
+#include "notifications_interface.h" // DBUS-generated
+#include "dbusproperties.h" // DBUS-generated
#include "kalarm_debug.h"
#include <KAlarmCal/DateTime>
@@ -62,6 +64,9 @@ namespace
{
const int RESOURCES_TIMEOUT = 30; // timeout (seconds) for resources to be populated
+const char FDO_NOTIFICATIONS_SERVICE[] = "org.freedesktop.Notifications";
+const char FDO_NOTIFICATIONS_PATH[] = "/org/freedesktop/Notifications";
+
/******************************************************************************
* Find the maximum number of seconds late which a late-cancel alarm is allowed
* to be. This is calculated as the late cancel interval, plus a few seconds
@@ -194,6 +199,23 @@ void KAlarmApp::initialise()
DateTime::setStartOfDay(Preferences::startOfDay());
mPrefsArchivedColour = Preferences::archivedColour();
}
+
+ // Get notified when the Freedesktop notifications properties have changed.
+ QDBusConnection conn = QDBusConnection::sessionBus();
+ if (conn.interface()->isServiceRegistered(QString::fromLatin1(FDO_NOTIFICATIONS_SERVICE)))
+ {
+ OrgFreedesktopDBusPropertiesInterface* piface = new OrgFreedesktopDBusPropertiesInterface(
+ QString::fromLatin1(FDO_NOTIFICATIONS_SERVICE),
+ QString::fromLatin1(FDO_NOTIFICATIONS_PATH),
+ conn, this);
+ connect(piface, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
+ this, &KAlarmApp::slotFDOPropertiesChanged);
+ OrgFreedesktopNotificationsInterface niface(
+ QString::fromLatin1(FDO_NOTIFICATIONS_SERVICE),
+ QString::fromLatin1(FDO_NOTIFICATIONS_PATH),
+ conn);
+ mNotificationsInhibited = niface.inhibited();
+ }
}
/******************************************************************************
@@ -845,7 +867,7 @@ void KAlarmApp::checkNextDueAlarm()
return;
// Find the first alarm due
KADateTime nextDt;
- const KAEvent nextEvent = ResourcesCalendar::earliestAlarm(nextDt);
+ const KAEvent nextEvent = ResourcesCalendar::earliestAlarm(nextDt, mNotificationsInhibited);
if (!nextEvent.isValid())
return; // there are no alarms pending
const KADateTime now = KADateTime::currentDateTime(Preferences::timeSpec());
@@ -981,13 +1003,15 @@ void KAlarmApp::processQueue()
const QueuedAction action = static_cast<QueuedAction>(int(entry.action) & int(QueuedAction::ActionMask));
bool ok = true;
+ bool inhibit = false;
if (entry.eventId.isEmpty())
{
// It's a new alarm
switch (action)
{
case QueuedAction::Trigger:
- execAlarm(entry.event, entry.event.firstAlarm());
+ if (execAlarm(entry.event, entry.event.firstAlarm()) == (void*)-2)
+ inhibit = true;
break;
case QueuedAction::Handle:
{
@@ -1034,13 +1058,22 @@ void KAlarmApp::processQueue()
}
else
{
- ok = handleEvent(entry.eventId, action, findUniqueId);
- if (!ok && exitAfter)
+ // Trigger the event if it's due.
+ const int result = handleEvent(entry.eventId, action, findUniqueId);
+ if (!result)
+ inhibit = true;
+ else if (result < 0 && exitAfter)
CommandOptions::printError(xi18nc("@info:shell", "%1: Event <resource>%2</resource> not found, or not unique", mCommandOption, entry.eventId.eventId()));
}
}
- if (exitAfter)
+ if (inhibit)
+ {
+ // It's a display event which can't be executed because notifications
+ // are inhibited. Move it to the inhibited queue until the inhibition
+ // is removed.
+ }
+ else if (exitAfter)
{
mActionQueue.clear(); // ensure that quitIf() actually exits the program
quitIf(ok ? 0 : 1);
@@ -1506,6 +1539,29 @@ void KAlarmApp::purge(int daysToKeep)
processQueue();
}
+/******************************************************************************
+* Called when the Freedesktop notifications properties have changed.
+* Check whether the inhibited property has changed.
+*/
+void KAlarmApp::slotFDOPropertiesChanged(const QString& interface,
+ const QVariantMap& changedProperties,
+ const QStringList& invalidatedProperties)
+{
+ Q_UNUSED(interface); // always "org.freedesktop.Notifications"
+ Q_UNUSED(invalidatedProperties);
+ const auto it = changedProperties.find(QStringLiteral("Inhibited"));
+ if (it != changedProperties.end())
+ {
+ const bool inhibited = it.value().toBool();
+ if (inhibited != mNotificationsInhibited)
+ {
+ qCDebug(KALARM_LOG) << "KAlarmApp::slotFDOPropertiesChanged: Notifications inhibited ->" << inhibited;
+ mNotificationsInhibited = inhibited;
+ if (!mNotificationsInhibited)
+ QTimer::singleShot(0, this, &KAlarmApp::processQueue);
+ }
+ }
+}
/******************************************************************************
* Output a list of pending alarms, with their next scheduled occurrence.
@@ -1626,13 +1682,12 @@ bool KAlarmApp::scheduleEvent(KAEvent::SubAction action, const QString& text, co
event.endChanges();
if (alarmTime <= now)
{
- // Alarm is due for display already.
+ // Alarm is due for execution already.
// First execute it once without adding it to the calendar file.
qCDebug(KALARM_LOG) << "KAlarmApp::scheduleEvent: executing" << text;
- if (!mInitialised)
+ if (!mInitialised
+ || execAlarm(event, event.firstAlarm()) == (void*)-2)
mActionQueue.enqueue(ActionQEntry(event, QueuedAction::Trigger));
- else
- execAlarm(event, event.firstAlarm());
// If it's a recurring alarm, reschedule it for its next occurrence
if (!event.recurs()
|| event.setNextOccurrence(now) == KAEvent::NO_OCCURRENCE)
@@ -1673,17 +1728,20 @@ QString KAlarmApp::dbusList()
/******************************************************************************
* Either:
-* a) Display the event and then delete it if it has no outstanding repetitions.
+* a) Execute the event if it's due, and then delete it if it has no outstanding
+* repetitions.
* b) Delete the event.
* c) Reschedule the event for its next repetition. If none remain, delete it.
* If the event is deleted, it is removed from the calendar file and from every
* main window instance.
* If 'findUniqueId' is true and 'id' does not specify a resource, all resources
* will be searched for the event's unique ID.
-* Reply = false if event ID not found, or if more than one event with the same
-* ID is found.
+* Reply = -1 if event ID not found, or if more than one event with the same ID
+* is found.
+* = 0 if can't trigger display event because notifications are inhibited.
+* = 1 if success.
*/
-bool KAlarmApp::handleEvent(const EventId& id, QueuedAction action, bool findUniqueId)
+int KAlarmApp::handleEvent(const EventId& id, QueuedAction action, bool findUniqueId)
{
Q_ASSERT(!(int(action) & ~int(QueuedAction::ActionMask)));
@@ -1700,7 +1758,7 @@ bool KAlarmApp::handleEvent(const EventId& id, QueuedAction action, bool findUni
qCWarning(KALARM_LOG) << "KAlarmApp::handleEvent: Event ID not found, or duplicated:" << eventID;
else
qCCritical(KALARM_LOG) << "KAlarmApp::handleEvent: No resource ID specified for event:" << eventID;
- return false;
+ return -1;
}
switch (action)
{
@@ -1850,7 +1908,7 @@ bool KAlarmApp::handleEvent(const EventId& id, QueuedAction action, bool findUni
// All recurrences are finished, so cancel the event
event.setArchive();
if (cancelAlarm(event, alarm.type(), false))
- return true; // event has been deleted
+ return 1; // event has been deleted
updateCalAndDisplay = true;
continue;
}
@@ -1868,7 +1926,7 @@ bool KAlarmApp::handleEvent(const EventId& id, QueuedAction action, bool findUni
restart = true;
break;
case -1:
- return true; // event has been deleted
+ return 1; // event has been deleted
default:
break;
}
@@ -1888,7 +1946,10 @@ bool KAlarmApp::handleEvent(const EventId& id, QueuedAction action, bool findUni
// If there is an alarm to execute, do this last after rescheduling/cancelling
// any others. This ensures that the updated event is only saved once to the calendar.
if (alarmToExecute.isValid())
- execAlarm(event, alarmToExecute, Reschedule | (alarmToExecute.repeatAtLogin() ? NoExecFlag : AllowDefer));
+ {
+ if (execAlarm(event, alarmToExecute, Reschedule | (alarmToExecute.repeatAtLogin() ? NoExecFlag : AllowDefer)) == (void*)-2)
+ return 0; // display alarm, but notifications are inhibited
+ }
else
{
if (action == QueuedAction::Trigger)
@@ -1898,7 +1959,10 @@ bool KAlarmApp::handleEvent(const EventId& id, QueuedAction action, bool findUni
// identical messages, for example.
const KAAlarm alarm = event.firstAlarm();
if (alarm.isValid())
- execAlarm(event, alarm);
+ {
+ if (execAlarm(event, alarm) == (void*)-2)
+ return 0; // display alarm, but notifications are inhibited
+ }
}
if (updateCalAndDisplay)
KAlarm::updateEvent(event); // update the window lists and calendar file
@@ -1909,7 +1973,7 @@ bool KAlarmApp::handleEvent(const EventId& id, QueuedAction action, bool findUni
default:
break;
}
- return true;
+ return 1;
}
/******************************************************************************
@@ -2098,9 +2162,10 @@ bool KAlarmApp::cancelReminderAndDeferral(KAEvent& event)
* Execute an alarm by displaying its message or file, or executing its command.
* Reply = ShellProcess instance if a command alarm
* = MessageWindow if an audio alarm
-* != 0 if successful
+* != null if successful
* = -1 if execution has not completed
-* = 0 if the alarm is disabled, or if an error message was output.
+* = -2 if can't execute display event because notifications are inhibited.
+* = null if the alarm is disabled, or if an error message was output.
*/
void* KAlarmApp::execAlarm(KAEvent& event, const KAAlarm& alarm, ExecAlarmFlags flags)
{
@@ -2113,6 +2178,14 @@ void* KAlarmApp::execAlarm(KAEvent& event, const KAAlarm& alarm, ExecAlarmFlags
return nullptr;
}
+ if (mNotificationsInhibited && !(flags & NoNotifyInhibit)
+ && (event.actionTypes() & KAEvent::ACT_DISPLAY))
+ {
+ // It's a display event and notifications are inhibited.
+ qCDebug(KALARM_LOG) << "KAlarmApp::execAlarm:" << event.id() << ": notifications inhibited";
+ return (void*)-2;
+ }
+
void* result = (void*)1;
event.setArchive();
diff --git a/src/kalarmapp.h b/src/kalarmapp.h
index c7df5f46..76b32efa 100644
--- a/src/kalarmapp.h
+++ b/src/kalarmapp.h
@@ -43,7 +43,8 @@ public:
Reschedule = 0x01, // reschedule the alarm after executing it
AllowDefer = 0x02, // allow the alarm to be deferred
NoRecordCmdError = 0x04, // don't record command errors
- NoPreAction = 0x08
+ NoPreAction = 0x08, // it isn't a pre-alarm action
+ NoNotifyInhibit = 0x10 // ignore notification inhibit
};
Q_DECLARE_FLAGS(ExecAlarmFlags, ExecAlarmFlag)
@@ -144,6 +145,9 @@ private Q_SLOTS:
void slotResourcePopulated(const Resource&);
void slotPurge() { purge(mArchivedPurgeDays); }
void slotCommandExited(ShellProcess*);
+ void slotFDOPropertiesChanged(const QString& interface,
+ const QVariantMap& changedProperties,
+ const QStringList& invalidatedProperties);
private:
// Actions to execute in processQueue(). May be OR'ed together.
@@ -217,7 +221,7 @@ private:
void checkArchivedCalendar();
void queueAlarmId(const KAEvent&);
bool dbusHandleEvent(const EventId&, QueuedAction);
- bool handleEvent(const EventId&, QueuedAction, bool findUniqueId = false);
+ int handleEvent(const EventId&, QueuedAction, bool findUniqueId = false);
int rescheduleAlarm(KAEvent&, const KAAlarm&, bool updateCalAndDisplay,
const KADateTime& nextDt = KADateTime());
bool cancelAlarm(KAEvent&, KAAlarm::Type, bool updateCalAndDisplay);
@@ -266,6 +270,7 @@ private:
bool mKOrganizerEnabled; // KOrganizer options are enabled (korganizer exists)
bool mWindowFocusBroken; // keyboard focus transfer between windows doesn't work
bool mResourcesTimedOut {false}; // timeout has expired for populating resources
+ bool mNotificationsInhibited {false}; // Freedesktop notifications are inhibited
};
inline KAlarmApp* theApp() { return KAlarmApp::instance(); }
diff --git a/src/resourcescalendar.cpp b/src/resourcescalendar.cpp
index 3c6d5714..a0509818 100644
--- a/src/resourcescalendar.cpp
+++ b/src/resourcescalendar.cpp
@@ -20,6 +20,7 @@ using namespace KAlarmCal;
ResourcesCalendar* ResourcesCalendar::mInstance {nullptr};
ResourcesCalendar::ResourceMap ResourcesCalendar::mResourceMap;
ResourcesCalendar::EarliestMap ResourcesCalendar::mEarliestAlarm;
+ResourcesCalendar::EarliestMap ResourcesCalendar::mEarliestNonDispAlarm;
QSet<QString> ResourcesCalendar::mPendingAlarms;
bool ResourcesCalendar::mIgnoreAtLogin {false};
bool ResourcesCalendar::mHaveDisabledAlarms {false};
@@ -111,6 +112,7 @@ void ResourcesCalendar::removeKAEvents(ResourceId key, bool closing, CalEvent::T
if (removed)
{
mEarliestAlarm.remove(key);
+ mEarliestNonDispAlarm.remove(key);
// Emit signal only if we're not in the process of closing the calendar
if (!closing)
{
@@ -193,17 +195,38 @@ void ResourcesCalendar::slotEventUpdated(Resource& resource, const KAEvent& even
&& event.category() == CalEvent::ACTIVE)
{
// Update the earliest alarm to trigger
- const QString earliestId = mEarliestAlarm.value(key);
- if (earliestId == event.id())
+ const QString earliestId = mEarliestAlarm.value(key);
+ const QString earliestNonDispId = mEarliestNonDispAlarm.value(key);
+ if (earliestId == event.id() || earliestNonDispId == event.id())
findEarliestAlarm(resource);
else
{
const KADateTime dt = event.nextTrigger(KAEvent::ALL_TRIGGER).effectiveKDateTime();
- if (dt.isValid()
- && (earliestId.isEmpty() || dt < resource.event(earliestId).nextTrigger(KAEvent::ALL_TRIGGER)))
+ if (dt.isValid())
{
- mEarliestAlarm[key] = event.id();
- Q_EMIT earliestAlarmChanged();
+ bool changed = false;
+ DateTime next;
+ if (!earliestId.isEmpty())
+ next = resource.event(earliestId).nextTrigger(KAEvent::ALL_TRIGGER);
+ if (earliestId.isEmpty() || dt < next)
+ {
+ mEarliestAlarm[key] = event.id();
+ changed = true;
+ }
+ if (!(event.actionTypes() & KAEvent::ACT_DISPLAY))
+ {
+ // It is not a display event.
+ DateTime nextNonDisp;
+ if (!earliestNonDispId.isEmpty())
+ nextNonDisp = (earliestId == earliestNonDispId) ? next : resource.event(earliestNonDispId).nextTrigger(KAEvent::ALL_TRIGGER);
+ if (earliestNonDispId.isEmpty() || dt < nextNonDisp)
+ {
+ mEarliestNonDispAlarm[key] = event.id();
+ changed = true;
+ }
+ }
+ if (changed)
+ Q_EMIT earliestAlarmChanged();
}
}
}
@@ -435,7 +458,8 @@ CalEvent::Type ResourcesCalendar::deleteEventInternal(const QString& eventID, co
{
const ResourceId key = resource.id();
mResourceMap[key].remove(eventID);
- if (mEarliestAlarm.value(key) == eventID)
+ if (mEarliestAlarm.value(key) == eventID
+ || mEarliestNonDispAlarm.value(key) == eventID)
mInstance->findEarliestAlarm(resource);
CalEvent::Type status = CalEvent::EMPTY;
@@ -609,7 +633,8 @@ void ResourcesCalendar::checkForDisabledAlarms()
}
/******************************************************************************
-* Find and note the active alarm with the earliest trigger time for a calendar.
+* Find and note the active alarm with the earliest trigger time for a calendar,
+* and the non-display active alarm with the earliest trigger time.
*/
void ResourcesCalendar::findEarliestAlarm(const Resource& resource)
{
@@ -618,28 +643,46 @@ void ResourcesCalendar::findEarliestAlarm(const Resource& resource)
return;
if (!(resource.alarmTypes() & CalEvent::ACTIVE))
return;
+
+ // Invalidate any existing earliest alarms for the resource
EarliestMap::Iterator eit = mEarliestAlarm.find(key);
if (eit != mEarliestAlarm.end())
eit.value() = QString();
+ eit = mEarliestNonDispAlarm.find(key);
+ if (eit != mEarliestNonDispAlarm.end())
+ eit.value() = QString();
+
ResourceMap::ConstIterator rit = mResourceMap.constFind(key);
if (rit == mResourceMap.constEnd())
return;
const QVector<KAEvent> events = eventsForResource(resource, rit.value());
- KAEvent earliest;
- KADateTime earliestTime;
+ KAEvent earliest, earliestNonDisp;
+ KADateTime earliestTime, earliestNonDispTime;
for (const KAEvent& event : events)
{
if (event.category() != CalEvent::ACTIVE
|| mPendingAlarms.contains(event.id()))
continue;
const KADateTime dt = event.nextTrigger(KAEvent::ALL_TRIGGER).effectiveKDateTime();
- if (dt.isValid() && (!earliest.isValid() || dt < earliestTime))
+ if (dt.isValid())
{
- earliestTime = dt;
- earliest = event;
+ if (!earliest.isValid() || dt < earliestTime)
+ {
+ earliestTime = dt;
+ earliest = event;
+ }
+ if (!(event.actionTypes() & KAEvent::ACT_DISPLAY))
+ {
+ if (!earliestNonDisp.isValid() || dt < earliestNonDispTime)
+ {
+ earliestNonDispTime = dt;
+ earliestNonDisp = event;
+ }
+ }
}
}
- mEarliestAlarm[key] = earliest.id();
+ mEarliestAlarm[key] = earliest.id();
+ mEarliestNonDispAlarm[key] = earliestNonDisp.id();
Q_EMIT earliestAlarmChanged();
}
@@ -647,11 +690,12 @@ void ResourcesCalendar::findEarliestAlarm(const Resource& resource)
* Return the active alarm with the earliest trigger time.
* Reply = invalid if none.
*/
-KAEvent ResourcesCalendar::earliestAlarm(KADateTime& nextTriggerTime)
+KAEvent ResourcesCalendar::earliestAlarm(KADateTime& nextTriggerTime, bool excludeDisplayAlarms)
{
KAEvent earliest;
KADateTime earliestTime;
- for (EarliestMap::ConstIterator eit = mEarliestAlarm.constBegin(); eit != mEarliestAlarm.constEnd(); ++eit)
+ const EarliestMap& earliestAlarms(excludeDisplayAlarms ? mEarliestNonDispAlarm : mEarliestAlarm);
+ for (EarliestMap::ConstIterator eit = earliestAlarms.constBegin(); eit != earliestAlarms.constEnd(); ++eit)
{
const QString id = eit.value();
if (id.isEmpty())
@@ -663,8 +707,9 @@ KAEvent ResourcesCalendar::earliestAlarm(KADateTime& nextTriggerTime)
// Something went wrong: mEarliestAlarm wasn't updated when it should have been!!
qCCritical(KALARM_LOG) << "ResourcesCalendar::earliestAlarm: resource" << eit.key() << "does not contain" << id;
mInstance->findEarliestAlarm(res);
- return earliestAlarm(nextTriggerTime);
+ return earliestAlarm(nextTriggerTime, excludeDisplayAlarms);
}
+//TODO: use next trigger calculated in findEarliestAlarm() (allowing for it being out of date)?
const KADateTime dt = event.nextTrigger(KAEvent::ALL_TRIGGER).effectiveKDateTime();
if (dt.isValid() && (!earliest.isValid() || dt < earliestTime))
{
diff --git a/src/resourcescalendar.h b/src/resourcescalendar.h
index 04c65282..f679e7f6 100644
--- a/src/resourcescalendar.h
+++ b/src/resourcescalendar.h
@@ -38,10 +38,11 @@ public:
static void terminate();
/** Return the active alarm with the earliest trigger time.
- * @param nextTriggerTime The next trigger time of the earliest alarm.
+ * @param nextTriggerTime The next trigger time of the earliest alarm.
+ * @param excludeDisplayAlarms Ignore display alarms.
* @return The earliest alarm.
*/
- static KAEvent earliestAlarm(KADateTime& nextTriggerTime);
+ static KAEvent earliestAlarm(KADateTime& nextTriggerTime, bool excludeDisplayAlarms = false);
static void setAlarmPending(const KAEvent&, bool pending = true);
static bool haveDisabledAlarms() { return mHaveDisabledAlarms; }
@@ -90,7 +91,8 @@ private:
typedef QHash<ResourceId, QString> EarliestMap; // event ID of earliest alarm, for each resource
static ResourceMap mResourceMap;
- static EarliestMap mEarliestAlarm; // alarm with earliest trigger time, by resource
+ static EarliestMap mEarliestAlarm; // alarm with earliest trigger time, by resource
+ static EarliestMap mEarliestNonDispAlarm; // non-display alarm with earliest trigger time, by resource
static QSet<QString> mPendingAlarms; // IDs of alarms which are currently being processed after triggering
static bool mIgnoreAtLogin; // ignore new/updated repeat-at-login alarms
static bool mHaveDisabledAlarms; // there is at least one individually disabled alarm
More information about the kde-doc-english
mailing list