diff --git a/js/ui/calendar.js b/js/ui/calendar.js index 90ef9cc95..84bdaeea8 100644 --- a/js/ui/calendar.js +++ b/js/ui/calendar.js @@ -273,6 +273,15 @@ class DBusEventSource extends EventSourceBase { this._lastRequestEnd = null; } + _removeMatching(uidPrefix) { + let changed = false; + for (const id of this._events.keys()) { + if (id.startsWith(uidPrefix)) + changed = this._events.delete(id) || changed; + } + return changed; + } + _onNameAppeared() { this._initialized = true; this._resetCache(); @@ -287,12 +296,21 @@ class DBusEventSource extends EventSourceBase { _onEventsAddedOrUpdated(dbusProxy, nameOwner, argArray) { const [appointments = []] = argArray; let changed = false; + const handledRemovals = new Set(); for (let n = 0; n < appointments.length; n++) { const [id, summary, startTime, endTime] = appointments[n]; const date = new Date(startTime * 1000); const end = new Date(endTime * 1000); let event = new CalendarEvent(id, date, end, summary); + /* It's a recurring event */ + if (!id.endsWith('\n')) { + const parentId = id.substr(0, id.lastIndexOf('\n') + 1); + if (!handledRemovals.has(parentId)) { + handledRemovals.add(parentId); + this._removeMatching(parentId); + } + } this._events.set(event.id, event); changed = true; @@ -307,7 +325,7 @@ class DBusEventSource extends EventSourceBase { let changed = false; for (const id of ids) - changed ||= this._events.delete(id); + changed = this._removeMatching(id) || changed; if (changed) this.emit('changed'); @@ -317,13 +335,7 @@ class DBusEventSource extends EventSourceBase { let [sourceUid = ''] = argArray; sourceUid += '\n'; - let changed = false; - for (const id of this._events.keys()) { - if (id.startsWith(sourceUid)) - changed ||= this._events.delete(id); - } - - if (changed) + if (this._removeMatching(sourceUid)) this.emit('changed'); } diff --git a/src/calendar-server/gnome-shell-calendar-server.c b/src/calendar-server/gnome-shell-calendar-server.c index f1980c633..4cd28d1c2 100644 --- a/src/calendar-server/gnome-shell-calendar-server.c +++ b/src/calendar-server/gnome-shell-calendar-server.c @@ -438,20 +438,30 @@ app_process_added_modified_objects (App *app, GSList *objects) /* ICalComponent * */ { ECalClient *cal_client; + g_autoptr(GHashTable) covered_uids = NULL; GSList *link; gboolean expand_recurrences; cal_client = e_cal_client_view_ref_client (view); + covered_uids = g_hash_table_new (g_str_hash, g_str_equal); expand_recurrences = e_cal_client_get_source_type (cal_client) == E_CAL_CLIENT_SOURCE_TYPE_EVENTS; for (link = objects; link; link = g_slist_next (link)) { ECalComponent *comp; ICalComponent *icomp = link->data; + const gchar *uid; + gboolean fallback = FALSE; - if (!icomp || !i_cal_component_get_uid (icomp)) + if (!icomp) continue; + uid = i_cal_component_get_uid (icomp); + if (!uid || g_hash_table_contains (covered_uids, uid)) + continue; + + g_hash_table_add (covered_uids, (gpointer) uid); + if (expand_recurrences && !e_cal_util_component_is_instance (icomp) && e_cal_util_component_has_recurrences (icomp)) @@ -464,7 +474,36 @@ app_process_added_modified_objects (App *app, e_cal_client_generate_instances_for_object_sync (cal_client, icomp, app->since, app->until, NULL, generate_instances_cb, &data); } + else if (expand_recurrences && + e_cal_util_component_is_instance (icomp)) + { + ICalComponent *main_comp = NULL; + + /* Always pass whole series of the recurring events, because + * the calendar removes events with the same UID first. */ + if (e_cal_client_get_object_sync (cal_client, uid, NULL, &main_comp, NULL, NULL)) + { + CollectAppointmentsData data; + + data.client = cal_client; + data.pappointments = &app->notify_appointments; + + e_cal_client_generate_instances_for_object_sync (cal_client, main_comp, app->since, app->until, NULL, + generate_instances_cb, &data); + + g_clear_object (&main_comp); + } + else + { + fallback = TRUE; + } + } else + { + fallback = TRUE; + } + + if (fallback) { comp = e_cal_component_new_from_icalcomponent (i_cal_component_clone (icomp)); if (!comp)