From 4900743e0d9b494e26e9c18df1ec4dbcb39b67ac Mon Sep 17 00:00:00 2001 From: Srinivasa Ragavan Date: Fri, 21 Apr 2006 19:38:16 +0000 Subject: Rewrite Alarm Notify with EThread svn path=/trunk/; revision=31858 --- calendar/gui/alarm-notify/alarm-notify.c | 121 ++++-- calendar/gui/alarm-notify/alarm-notify.h | 14 + calendar/gui/alarm-notify/alarm-queue.c | 665 ++++++++++++++++++++++++++----- calendar/gui/alarm-notify/alarm.c | 3 - 4 files changed, 673 insertions(+), 130 deletions(-) (limited to 'calendar/gui/alarm-notify') diff --git a/calendar/gui/alarm-notify/alarm-notify.c b/calendar/gui/alarm-notify/alarm-notify.c index d268c6ffda..a773ab7644 100644 --- a/calendar/gui/alarm-notify/alarm-notify.c +++ b/calendar/gui/alarm-notify/alarm-notify.c @@ -44,6 +44,11 @@ struct _AlarmNotifyPrivate { GMutex *mutex; }; +EThread *alarm_operation_thread; /* for operations that can (or should) be queued */ +EMsgPort *alarm_reply_port; +static GIOChannel *alarm_reply_channel; + +#define d(x) x static void alarm_notify_class_init (AlarmNotifyClass *klass); @@ -82,7 +87,7 @@ process_removal_in_hash (gpointer key, gpointer value, gpointer data) ProcessRemovalsData *prd = data; GSList *groups, *sources, *p, *q; gboolean found = FALSE; - + /* search the list of selected calendars */ groups = e_source_list_peek_groups (prd->source_list); for (p = groups; p != NULL; p = p->next) { @@ -120,8 +125,9 @@ list_changed_cb (ESourceList *source_list, gpointer data) ProcessRemovalsData prd; GList *l; int i; + + g_signal_handlers_block_by_func(source_list, list_changed_cb, data); - printf("LIST CHANGED\n"); priv = an->priv; /* Figure out the source type */ @@ -150,7 +156,7 @@ list_changed_cb (ESourceList *source_list, gpointer data) uri = e_source_get_uri (source); if (!g_hash_table_lookup (priv->uri_client_hash[source_type], uri)) { - g_message ("Adding %s", uri); + d (printf("%s:%d (list_changed_cb) - Adding Calendar %s\n", __FILE__, __LINE__, uri)); alarm_notify_add_calendar (an, source_type, source, FALSE); } g_free (uri); @@ -164,10 +170,12 @@ list_changed_cb (ESourceList *source_list, gpointer data) g_hash_table_foreach (priv->uri_client_hash[source_type], (GHFunc) process_removal_in_hash, &prd); for (l = prd.removals; l; l = l->next) { - g_message ("Removing %s", (char *)l->data); + d (printf("%s:%d (list_changed_cb) - Removing Calendar %s\n", __FILE__, __LINE__, l->data)); alarm_notify_remove_calendar (an, source_type, l->data); } g_list_free (prd.removals); + g_signal_handlers_unblock_by_func(source_list, list_changed_cb, data); + } ESourceList * @@ -175,6 +183,7 @@ alarm_notify_get_selected_calendars (AlarmNotify *an) { return an->priv->selected_calendars; } + static void load_calendars (AlarmNotify *an, ECalSourceType source_type) { @@ -185,7 +194,7 @@ load_calendars (AlarmNotify *an, ECalSourceType source_type) priv = an->priv; if (!e_cal_get_sources (&source_list, source_type, NULL)) { - g_message (G_STRLOC ": Could not get the list of sources to load"); + d (printf("%s:%d (load_calendars) - Cannont get sources\n ", __FILE__, __LINE__)); priv->source_lists[source_type] = NULL; return; @@ -205,7 +214,7 @@ load_calendars (AlarmNotify *an, ECalSourceType source_type) continue; uri = e_source_get_uri (source); - g_message ("Loading %s", uri); + d (printf("%s:%d (load_calendars) - Loading Calendar %s \n", __FILE__, __LINE__, uri)); alarm_notify_add_calendar (an, source_type, source, FALSE); g_free (uri); @@ -216,20 +225,6 @@ load_calendars (AlarmNotify *an, ECalSourceType source_type) priv->source_lists[source_type] = source_list; } -static gboolean -load_calendars_cb (gpointer data) -{ - int i; - AlarmNotify *an = ALARM_NOTIFY (data); - - for (i = 0; i < E_CAL_SOURCE_TYPE_LAST; i++) { - if (an->priv->source_lists[i]) - list_changed_cb (an->priv->source_lists[i], an); - } - - return FALSE; - -} /* Object initialization function for the alarm notify system */ static void alarm_notify_init (AlarmNotify *an, AlarmNotifyClass *klass) @@ -242,7 +237,8 @@ alarm_notify_init (AlarmNotify *an, AlarmNotifyClass *klass) priv->mutex = g_mutex_new (); priv->selected_calendars = config_data_get_calendars ("/apps/evolution/calendar/sources"); - + d (printf("%s:%d (alarm_notify_init) - Initing Alarm Notify\n", __FILE__, __LINE__)); + for (i = 0; i < E_CAL_SOURCE_TYPE_LAST; i++) priv->uri_client_hash[i] = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); @@ -250,7 +246,6 @@ alarm_notify_init (AlarmNotify *an, AlarmNotifyClass *klass) for (i = 0; i < E_CAL_SOURCE_TYPE_LAST; i++) load_calendars (an, i); - g_timeout_add (60000, (GSourceFunc)load_calendars_cb, an); } static void @@ -258,6 +253,7 @@ dequeue_client (gpointer key, gpointer value, gpointer user_data) { ECal *client = value; + d (printf("%s:%d (dequeue_client) - Removing client %d\n ", __FILE__, __LINE__, client)); alarm_queue_remove_client (client); } @@ -271,7 +267,9 @@ alarm_notify_finalize (GObject *object) g_return_if_fail (object != NULL); g_return_if_fail (IS_ALARM_NOTIFY (object)); - + + d (printf("%s:%d (alarm_notify_finalize) - Finalize \n ", __FILE__, __LINE__)); + an = ALARM_NOTIFY (object); priv = an->priv; @@ -285,12 +283,72 @@ alarm_notify_finalize (GObject *object) g_mutex_free (priv->mutex); g_free (priv); + e_thread_destroy(alarm_operation_thread); + g_io_channel_unref(alarm_reply_channel); + e_msgport_destroy(alarm_reply_port); if (G_OBJECT_CLASS (parent_class)->finalize) (* G_OBJECT_CLASS (parent_class)->finalize) (object); } +static guint +alarm_channel_setup(EMsgPort **port, GIOChannel **channel, GIOFunc func) +{ + GSource *source; + guint id; + + d (printf("%s:%d (alarm_channel_setup) - Channel Setup\n ", __FILE__, __LINE__)); + *port = e_msgport_new(); +#ifndef G_OS_WIN32 + *channel = g_io_channel_unix_new(e_msgport_fd(*port)); +#else + *channel = g_io_channel_win32_new_socket(e_msgport_fd(*port)); +#endif + source = g_io_create_watch(*channel, G_IO_IN); + g_source_set_callback(source, (GSourceFunc)func, *port, NULL); + g_source_set_can_recurse(source, FALSE); + id = g_source_attach(source, NULL); + g_source_unref(source); + + return id; +} + +static void +alarm_msg_destroy(EThread *e, EMsg *msg, void *data) +{ + AlarmMsg *m = (AlarmMsg *)msg; + + /* Free the private */ + g_free (m->data); /* Mostly it is a structure allocated as a carrier*/ + g_free (m); +} + +static gboolean +alarm_msgport_replied(GIOChannel *source, GIOCondition cond, void *d) +{ + EMsgPort *port = (EMsgPort *)d; + AlarmMsg *m; + + while (( m = (AlarmMsg *)e_msgport_get(port))) { + d (printf("%s:%d (alarm_msgport_replied) - %p: Replied to GUI thread\n", __FILE__, __LINE__, m)); + alarm_msg_destroy(NULL, m, NULL); + } + + return TRUE; +} + +static void +alarm_msg_received(EThread *e, EMsg *msg, void *data) +{ + AlarmMsg *m = (AlarmMsg *)msg; + + d(printf("%s:%d (alarm_msg_received) - %p: Received at thread %" G_GINT64_MODIFIER "x\n", __FILE__, __LINE__, m, e_util_pthread_id(pthread_self()))); + if (m->receive_msg) { + m->receive_msg (e, m, data); + } +} + /** * alarm_notify_new: * @@ -304,9 +362,20 @@ alarm_notify_new (void) { AlarmNotify *an; + d (printf("%s:%d (alarm_notify_new) - Alarm Notify New \n ", __FILE__, __LINE__)); + + /* Create a thread for alarm queue operation*/ + alarm_channel_setup(&alarm_reply_port, &alarm_reply_channel, alarm_msgport_replied); + + alarm_operation_thread = e_thread_new(E_THREAD_QUEUE); + e_thread_set_msg_destroy(alarm_operation_thread, alarm_msg_destroy, 0); + e_thread_set_msg_received(alarm_operation_thread, alarm_msg_received, 0); + e_thread_set_reply_port(alarm_operation_thread, alarm_reply_port); + an = g_object_new (TYPE_ALARM_NOTIFY, "poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_PER_REQUEST, NULL), NULL); + return an; } @@ -317,7 +386,9 @@ cal_opened_cb (ECal *client, ECalendarStatus status, gpointer user_data) AlarmNotify *an = ALARM_NOTIFY (user_data); priv = an->priv; - + + d (printf("%s:%d (cal_opened_cb) - Calendar Status %d\n", __FILE__, __LINE__, status==E_CALENDAR_STATUS_OK)); + if (status == E_CALENDAR_STATUS_OK) alarm_queue_add_client (client); else { @@ -379,6 +450,7 @@ alarm_notify_add_calendar (AlarmNotify *an, ECalSourceType source_type, ESource client = auth_new_cal_from_source (source, source_type); if (client) { + d (printf("%s:%d (alarm_notify_add_calendar) - Calendar Open Async... %d\n", __FILE__, __LINE__, client)); g_hash_table_insert (priv->uri_client_hash[source_type], g_strdup (str_uri), client); g_signal_connect (G_OBJECT (client), "cal_opened", G_CALLBACK (cal_opened_cb), an); e_cal_open_async (client, FALSE); @@ -398,6 +470,7 @@ alarm_notify_remove_calendar (AlarmNotify *an, ECalSourceType source_type, const client = g_hash_table_lookup (priv->uri_client_hash[source_type], str_uri); if (client) { + d (printf("%s:%d (alarm_notify_remove_calendar) - Removing Client %d\n", __FILE__, __LINE__, client)); alarm_queue_remove_client (client); g_hash_table_remove (priv->uri_client_hash[source_type], str_uri); } diff --git a/calendar/gui/alarm-notify/alarm-notify.h b/calendar/gui/alarm-notify/alarm-notify.h index beb58acc1e..ef8c1fcf81 100644 --- a/calendar/gui/alarm-notify/alarm-notify.h +++ b/calendar/gui/alarm-notify/alarm-notify.h @@ -23,6 +23,7 @@ #define ALARM_NOTIFY_H #include +#include #include "evolution-calendar.h" @@ -38,6 +39,19 @@ typedef struct _AlarmNotifyClass AlarmNotifyClass; typedef struct _AlarmNotifyPrivate AlarmNotifyPrivate; +typedef struct _AlarmMsg AlarmMsg; +typedef struct _AlarmMsgPrivate AlarmMsgPrivate; + +struct _AlarmMsg { + EMsg msg; + + void (*receive_msg)(EThread *e, struct _AlarmMsg *msg, void *data); /* message received */ + void *data; + + /* Private Usage */ + struct _AlarmMsgPrivate *priv; +}; + struct _AlarmNotify { BonoboObject object; diff --git a/calendar/gui/alarm-notify/alarm-queue.c b/calendar/gui/alarm-notify/alarm-queue.c index d97d49af96..9b27990f4b 100644 --- a/calendar/gui/alarm-notify/alarm-queue.c +++ b/calendar/gui/alarm-notify/alarm-queue.c @@ -82,6 +82,9 @@ #include "e-util/e-error.h" + +#define d(x) x + /* The dialog with alarm nofications */ static AlarmNotificationsDialog *alarm_notifications_dialog = NULL; @@ -112,6 +115,9 @@ static int tray_blink_id = -1; static int tray_blink_state = FALSE; static AlarmNotify *an; +/* Main Tasks thread for dealing with the global structures */ +extern EThread *alarm_operation_thread; + /* Structure that stores a client we are monitoring */ typedef struct { /* Monitored client */ @@ -185,6 +191,7 @@ static void query_objects_removed_cb (ECal *client, GList *objects, gpointer dat static void remove_client_alarms (ClientAlarms *ca); static void update_cqa (CompQueuedAlarms *cqa, ECalComponent *comp); static void update_qa (ECalComponentAlarms *alarms, QueuedAlarm *qa); +static void tray_list_remove_cqa (CompQueuedAlarms *cqa); /* Alarm queue engine */ @@ -205,12 +212,13 @@ queue_midnight_refresh (void) } zone = config_data_get_timezone (); - midnight = time_day_end_with_zone (time (NULL), zone); + d(printf("%s:%d (queue_midnight_refresh) - Refresh at %s \n",__FILE__, __LINE__, ctime(&midnight))); + midnight_refresh_id = alarm_add (midnight, midnight_refresh_cb, NULL, NULL); if (!midnight_refresh_id) { - g_message ("queue_midnight_refresh(): Could not set up the midnight refresh alarm!"); + d(printf("%s:%d (queue_midnight_refresh)) - Could not setup the midnight refresh alarm\n",__FILE__, __LINE__)); /* FIXME: what to do? */ } } @@ -220,22 +228,31 @@ static void add_client_alarms_cb (gpointer key, gpointer value, gpointer data) { ClientAlarms *ca; - + + d(printf("%s:%d (add_client_alarms_cb) - Adding %d\n",__FILE__, __LINE__, ca)); + ca = value; load_alarms_for_today (ca); } +struct _midnight_refresh_msg { + gboolean remove; +}; + /* Loads the alarms for the new day every midnight */ static void -midnight_refresh_cb (gpointer alarm_id, time_t trigger, gpointer data) +midnight_refresh_async (EThread *e, AlarmMsg *msg, void *data) { - /* Re-load the alarms for all clients */ + struct _midnight_refresh_msg *list = msg->data; + d(printf("%s:%d (midnight_refresh_async) \n",__FILE__, __LINE__)); + + /* Re-load the alarms for all clients */ g_hash_table_foreach (client_alarms_hash, add_client_alarms_cb, NULL); /* Re-schedule the midnight update */ - - if (midnight_refresh_id != NULL) { + if (list->remove && midnight_refresh_id != NULL) { + d(printf("%s:%d (midnight_refresh_async)) - Reschedule the midnight update \n",__FILE__, __LINE__)); alarm_remove (midnight_refresh_id); midnight_refresh_id = NULL; } @@ -243,6 +260,25 @@ midnight_refresh_cb (gpointer alarm_id, time_t trigger, gpointer data) queue_midnight_refresh (); } +static void +midnight_refresh_cb (gpointer alarm_id, time_t trigger, gpointer data) +{ + AlarmMsg *msg; + struct _midnight_refresh_msg *list; + + /* These two structures will be freed by the msg destroy function*/ + msg = malloc (sizeof (AlarmMsg)); + msg->receive_msg = midnight_refresh_async; + + list = malloc (sizeof (struct _midnight_refresh_msg)); + + list->remove = TRUE; + msg->data = list; + + d(printf("%s:%d (midnight_refresh_cb) - Invoking task for midnight refresh\n",__FILE__, __LINE__)); + e_thread_put(alarm_operation_thread, (EMsg *)msg); +} + /* Looks up a client in the client alarms hash table */ static ClientAlarms * lookup_client (ECal *client) @@ -276,10 +312,10 @@ static void remove_queued_alarm (CompQueuedAlarms *cqa, gpointer alarm_id, gboolean free_object, gboolean remove_alarm) { - QueuedAlarm *qa; + QueuedAlarm *qa=NULL; GSList *l; - qa = NULL; + d(printf("%s:%d (remove_queued_alarm) \n",__FILE__, __LINE__)); for (l = cqa->queued_alarms; l; l = l->next) { qa = l->data; @@ -308,9 +344,8 @@ remove_queued_alarm (CompQueuedAlarms *cqa, gpointer alarm_id, if (cqa->queued_alarms != NULL) return; + d(printf("%s:%d (remove_queued_alarm)) - Last Component. Removing CQA- Free=%d\n",__FILE__, __LINE__, free_object)); if (free_object) { - g_hash_table_remove (cqa->parent_client->uid_alarms_hash, cqa->id); - e_cal_component_free_id (cqa->id); cqa->id = NULL; cqa->parent_client = NULL; e_cal_component_alarms_free (cqa->alarms); @@ -335,6 +370,7 @@ alarm_trigger_cb (gpointer alarm_id, time_t trigger, gpointer data) comp = cqa->alarms->comp; config_data_set_last_notification_time (trigger); + d(printf("%s:%d (alarm_trigger_cb) - Setting Last notification time to %s\n",__FILE__, __LINE__, ctime (&trigger))); saved_notification_time = trigger; qa = lookup_queued_alarm (cqa, alarm_id); @@ -379,6 +415,7 @@ alarm_trigger_cb (gpointer alarm_id, time_t trigger, gpointer data) g_assert_not_reached (); break; } + d(printf("%s:%d (alarm_trigger_cb) - Notification sent:%d\n",__FILE__, __LINE__, action)); } /* Adds the alarms in a ECalComponentAlarms structure to the alarms queued for a @@ -393,7 +430,7 @@ add_component_alarms (ClientAlarms *ca, ECalComponentAlarms *alarms) /* No alarms? */ if (alarms == NULL || alarms->alarms == NULL) { - g_message ("No alarms to add"); + d(printf("%s:%d (add_component_alarms) - No alarms to add\n",__FILE__, __LINE__)); if (alarms) e_cal_component_alarms_free (alarms); return; @@ -405,19 +442,19 @@ add_component_alarms (ClientAlarms *ca, ECalComponentAlarms *alarms) cqa->expecting_update = FALSE; cqa->queued_alarms = NULL; - + d(printf("%s:%d (add_component_alarms)) - Creating CQA %d\n",__FILE__, __LINE__, cqa)); + for (l = alarms->alarms; l; l = l->next) { ECalComponentAlarmInstance *instance; gpointer alarm_id; QueuedAlarm *qa; - + time_t tnow = time(NULL); + instance = l->data; - g_message ("Adding alarm at %lu (%lu)", instance->trigger, time (NULL)); alarm_id = alarm_add (instance->trigger, alarm_trigger_cb, cqa, NULL); if (!alarm_id) { - g_message ("add_component_alarms(): Could not schedule a trigger for " - "%ld, discarding...", (long) instance->trigger); + d(printf("%s:%d (add_component_alarms)) - Could not schedule a trigger for %s. Discarding \n",__FILE__, __LINE__, ctime(&(instance->trigger)))); continue; } @@ -428,6 +465,7 @@ add_component_alarms (ClientAlarms *ca, ECalComponentAlarms *alarms) qa->snooze = FALSE; cqa->queued_alarms = g_slist_prepend (cqa->queued_alarms, qa); + d(printf("%s:%d (add_component_alarms)) - Adding alarm %d(%d)at %s (%s)\n",__FILE__, __LINE__, qa, alarm_id, ctime (&(instance->trigger)), ctime(&tnow))); } id = e_cal_component_get_id (alarms->comp); @@ -436,13 +474,15 @@ add_component_alarms (ClientAlarms *ca, ECalComponentAlarms *alarms) if (cqa->queued_alarms == NULL) { e_cal_component_alarms_free (cqa->alarms); cqa->alarms = NULL; - + d(printf("%s:%d (add_component_alarms)) - Failed to add all : %d\n",__FILE__, __LINE__, cqa)); + g_message ("Failed to add all\n"); g_free (cqa); return; } cqa->queued_alarms = g_slist_reverse (cqa->queued_alarms); cqa->id = id; + d(printf("%s:%d (add_component_alarms)) - Alarm added for %s\n",__FILE__, __LINE__, id->uid)); g_hash_table_insert (ca->uid_alarms_hash, cqa->id, cqa); } @@ -452,6 +492,8 @@ load_alarms (ClientAlarms *ca, time_t start, time_t end) { char *str_query, *iso_start, *iso_end; + d(printf("%s:%d (load_alarms) \n",__FILE__, __LINE__)); + iso_start = isodate_from_time_t (start); if (!iso_start) return; @@ -469,6 +511,7 @@ load_alarms (ClientAlarms *ca, time_t start, time_t end) /* create the live query */ if (ca->query) { + d(printf("%s:%d (load_alarms) - Disconnecting old queries \n",__FILE__, __LINE__)); g_signal_handlers_disconnect_matched (ca->query, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, ca); g_object_unref (ca->query); ca->query = NULL; @@ -478,6 +521,8 @@ load_alarms (ClientAlarms *ca, time_t start, time_t end) if (!e_cal_get_query (ca->client, str_query, &ca->query, NULL)) { g_warning (G_STRLOC ": Could not get query for client"); } else { + d(printf("%s:%d (load_alarms) - Setting Call backs \n",__FILE__, __LINE__)); + g_signal_connect (G_OBJECT (ca->query), "objects_added", G_CALLBACK (query_objects_changed_cb), ca); g_signal_connect (G_OBJECT (ca->query), "objects_modified", @@ -509,8 +554,8 @@ load_alarms_for_today (ClientAlarms *ca) */ from = MAX (config_data_get_last_notification_time () + 1, day_start); - g_message ("Loading alarms for today"); day_end = time_day_end_with_zone (now, zone); + d(printf("%s:%d (load_alarms_for_today) - From %s to %s\n",__FILE__, __LINE__, ctime (&from), ctime(&day_end))); load_alarms (ca, from, day_end); } @@ -522,6 +567,7 @@ cal_opened_cb (ECal *client, ECalendarStatus status, gpointer data) ca = data; + d(printf("%s:%d (cal_opened_cb)) - Opened Calendar %d (Status %d)\n",__FILE__, __LINE__, client, status==E_CALENDAR_STATUS_OK)); if (status != E_CALENDAR_STATUS_OK) return; @@ -540,6 +586,7 @@ remove_alarms (CompQueuedAlarms *cqa, gboolean free_object) { GSList *l; + d(printf("%s:%d (remove_alarms) - Removing for %d\n",__FILE__, __LINE__, cqa)); for (l = cqa->queued_alarms; l;) { QueuedAlarm *qa; @@ -559,10 +606,17 @@ remove_alarms (CompQueuedAlarms *cqa, gboolean free_object) /* Removes a component an its alarms */ static void -remove_comp (ClientAlarms *ca, const ECalComponentId *id) +remove_comp (ClientAlarms *ca, ECalComponentId *id) { CompQueuedAlarms *cqa; + d(printf("%s:%d (remove_comp) - Removing uid %s\n",__FILE__, __LINE__, id->uid)); + + if (id->rid && !(*(id->rid))) { + g_free (id->rid); + id->rid = NULL; + } + cqa = lookup_comp_queued_alarms (ca, id); if (!cqa) return; @@ -571,20 +625,49 @@ remove_comp (ClientAlarms *ca, const ECalComponentId *id) * for it. */ g_assert (cqa->queued_alarms != NULL); - + + d(printf("%s:%d (remove_comp) - Removing CQA %d\n",__FILE__, __LINE__, cqa)); remove_alarms (cqa, TRUE); - - /* The list should be empty now, and thus the queued component alarms - * structure should have been freed and removed from the hash table. - */ - g_assert (lookup_comp_queued_alarms (ca, id) == NULL); } /* Called when a calendar component changes; we must reload its corresponding * alarms. */ +struct _query_msg { + ECal *client; + GList *objects; + gpointer data; +}; + +static GList * +duplicate_ical (GList *in_list) +{ + GList *l, *out_list = NULL; + for (l = in_list; l; l = l->next) { + out_list = g_list_prepend (out_list, icalcomponent_new_clone (l->data)); + } + + return g_list_reverse (out_list); +} + +static GList * +duplicate_ecal (GList *in_list) +{ + GList *l, *out_list = NULL; + for (l = in_list; l; l = l->next) { + ECalComponentId *id, *old; + old = l->data; + id = g_new0 (ECalComponentId, 1); + id->uid = g_strdup (old->uid); + id->rid = g_strdup (old->rid); + out_list = g_list_prepend (out_list, id); + } + + return g_list_reverse (out_list); +} + static void -query_objects_changed_cb (ECal *client, GList *objects, gpointer data) +query_objects_changed_async (EThread *e, AlarmMsg *msg, void *data) { ClientAlarms *ca; time_t from, day_end; @@ -593,9 +676,14 @@ query_objects_changed_cb (ECal *client, GList *objects, gpointer data) icaltimezone *zone; CompQueuedAlarms *cqa; GList *l; - - ca = data; - + struct _query_msg *list = msg->data; + ECal *client; + GList *objects; + + client = list->client; + ca = list->data; + objects = list->objects; + from = config_data_get_last_notification_time (); if (from == -1) from = time (NULL); @@ -605,20 +693,24 @@ query_objects_changed_cb (ECal *client, GList *objects, gpointer data) zone = config_data_get_timezone (); day_end = time_day_end_with_zone (time (NULL), zone); - g_message ("Query response for alarms"); + + d(printf("%s:%d (query_objects_changed_async) - Querying for object between %s to %s\n",__FILE__, __LINE__, ctime(&from), ctime(&day_end))); + for (l = objects; l != NULL; l = l->next) { ECalComponentId *id; GSList *sl; ECalComponent *comp = e_cal_component_new (); - e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (l->data)); + e_cal_component_set_icalcomponent (comp, l->data); id = e_cal_component_get_id (comp); found = e_cal_get_alarms_for_object (ca->client, id, from, day_end, &alarms); if (!found) { - g_message ("No alarms found on object"); + d(printf("%s:%d (query_objects_changed_async) - No Alarm found for client %d\n",__FILE__, __LINE__, ca->client)); + tray_list_remove_cqa (lookup_comp_queued_alarms (ca, l->data)); remove_comp (ca, id); + g_hash_table_remove (ca->uid_alarms_hash, id); e_cal_component_free_id (id); g_object_unref (comp); comp = NULL; @@ -627,15 +719,14 @@ query_objects_changed_cb (ECal *client, GList *objects, gpointer data) cqa = lookup_comp_queued_alarms (ca, id); if (!cqa) { - g_message ("No currently queue alarms"); + d(printf("%s:%d (query_objects_changed_async) - No currently queued alarms for %s\n",__FILE__, __LINE__, id->uid)); add_component_alarms (ca, alarms); g_object_unref (comp); comp = NULL; continue; } - g_message ("Already existing alarms"); - + d(printf("%s:%d (query_objects_changed_async) - Alarm Already Exist for %s\n",__FILE__, __LINE__, id->uid)); /* if the alarms or the alarms list is empty remove it after updating the cqa structure */ if (alarms == NULL || alarms->alarms == NULL) { @@ -662,8 +753,7 @@ query_objects_changed_cb (ECal *client, GList *objects, gpointer data) alarm_id = alarm_add (instance->trigger, alarm_trigger_cb, cqa, NULL); if (!alarm_id) { - g_message (G_STRLOC ": Could not schedule a trigger for " - "%ld, discarding...", (long) instance->trigger); + d(printf("%s:%d (query_objects_changed_async) -Unable to schedule trigger for %s \n",__FILE__, __LINE__, ctime(&(instance->trigger)))); continue; } @@ -673,29 +763,85 @@ query_objects_changed_cb (ECal *client, GList *objects, gpointer data) qa->snooze = FALSE; qa->orig_trigger = instance->trigger; cqa->queued_alarms = g_slist_prepend (cqa->queued_alarms, qa); + d(printf("%s:%d (query_objects_changed_async) - Adding %d to queue \n",__FILE__, __LINE__, qa)); } cqa->queued_alarms = g_slist_reverse (cqa->queued_alarms); g_object_unref (comp); comp = NULL; } + g_list_free (objects); +} + +static void +query_objects_changed_cb (ECal *client, GList *objects, gpointer data) +{ + AlarmMsg *msg; + struct _query_msg *list; + + /* These two structures will be freed by the msg destroy function*/ + msg = malloc (sizeof (AlarmMsg)); + msg->receive_msg = query_objects_changed_async; + list = malloc (sizeof (struct _query_msg)); + list->client = client; + list->objects = duplicate_ical (objects); + list->data = data; + msg->data = list; + + d(printf("%s:%d (query_objects_changed_cb) - Posting a task\n",__FILE__, __LINE__)); + e_thread_put(alarm_operation_thread, (EMsg *)msg); + } /* Called when a calendar component is removed; we must delete its corresponding * alarms. */ static void -query_objects_removed_cb (ECal *client, GList *objects, gpointer data) +query_objects_removed_async (EThread *e, AlarmMsg *msg, void *data) { ClientAlarms *ca; GList *l; - - ca = data; - - for (l = objects; l != NULL; l = l->next) + struct _query_msg *list = msg->data; + ECal *client; + GList *objects; + + client = list->client; + ca = list->data; + objects = list->objects; + + d(printf("%s:%d (query_objects_removed_async) - Removing %d objects\n",__FILE__, __LINE__, g_list_length(objects))); + + for (l = objects; l != NULL; l = l->next) { + /* If the alarm is already triggered remove it. */ + tray_list_remove_cqa (lookup_comp_queued_alarms (ca, l->data)); remove_comp (ca, l->data); + g_hash_table_remove (ca->uid_alarms_hash, l->data); + e_cal_component_free_id (l->data); + } + + g_list_free (objects); } +static void +query_objects_removed_cb (ECal *client, GList *objects, gpointer data) +{ + AlarmMsg *msg; + struct _query_msg *list; + + /* These two structures will be freed by the msg destroy function*/ + msg = malloc (sizeof (AlarmMsg)); + msg->receive_msg = query_objects_removed_async; + + list = malloc (sizeof (struct _query_msg)); + list->client = client; + list->objects = duplicate_ecal (objects); + list->data = data; + msg->data = list; + + d(printf("%s:%d (query_objects_removed_cb) - Posting a task\n",__FILE__, __LINE__)); + e_thread_put(alarm_operation_thread, (EMsg *)msg); + +} /* Notification functions */ @@ -719,14 +865,14 @@ create_snooze (CompQueuedAlarms *cqa, gpointer alarm_id, int snooze_mins) new_id = alarm_add (t, alarm_trigger_cb, cqa, NULL); if (!new_id) { - g_message ("create_snooze(): Could not schedule a trigger for " - "%ld, discarding...", (long) t); + d(printf("%s:%d (create_snooze) -Unable to schedule trigger for %s \n",__FILE__, __LINE__, ctime(&t))); return; } orig_qa->instance->trigger = t; orig_qa->alarm_id = new_id; orig_qa->snooze = TRUE; + d(printf("%s:%d (create_snooze) - Adding a alarm at %s\n",__FILE__, __LINE__, ctime(&t))); } /* Launches a component editor for a component */ @@ -740,6 +886,8 @@ edit_component (ECal *client, ECalComponent *comp) GNOME_Evolution_Calendar_CompEditorFactory factory; GNOME_Evolution_Calendar_CompEditorFactory_CompEditorMode corba_type; + d(printf("%s:%d (edit_component) - Client %d\n",__FILE__, __LINE__, client)); + e_cal_component_get_uid (comp, &uid); uri = e_cal_get_uri (client); @@ -837,12 +985,21 @@ free_tray_icon_data (TrayIconData *tray_data) } static void -on_dialog_objs_removed_cb (ECal *client, GList *objects, gpointer data) +on_dialog_objs_removed_async (EThread *e, AlarmMsg *msg, void *data) { const char *our_uid; GList *l; - TrayIconData *tray_data = data; + TrayIconData *tray_data; + struct _query_msg *list = msg->data; + ECal *client; + GList *objects; + d(printf("%s:%d (on_dialog_objs_removed_async)\n",__FILE__, __LINE__)); + + client = list->client; + tray_data = list->data; + objects = list->objects; + e_cal_component_get_uid (tray_data->comp, &our_uid); g_return_if_fail (our_uid && *our_uid); @@ -861,19 +1018,186 @@ on_dialog_objs_removed_cb (ECal *client, GList *objects, gpointer data) } } +static void +on_dialog_objs_removed_cb (ECal *client, GList *objects, gpointer data) +{ + AlarmMsg *msg; + struct _query_msg *list; + + /* These two structures will be freed by the msg destroy function*/ + msg = malloc (sizeof (AlarmMsg)); + msg->receive_msg = on_dialog_objs_removed_async; + + list = malloc (sizeof (struct _query_msg)); + list->client = client; + list->objects = objects; + list->data = data; + msg->data = list; + + d(printf("%s:%d (on_dialog_objs_removed_cb) - Posting a task \n",__FILE__, __LINE__)); + e_thread_put(alarm_operation_thread, (EMsg *)msg); +} + +struct _tray_cqa_msg { + CompQueuedAlarms *cqa; +}; + +static void +tray_list_remove_cqa_async(EThread *e, AlarmMsg *msg, void *data) +{ + struct _tray_cqa_msg *tmsg = msg->data; + CompQueuedAlarms *cqa = tmsg->cqa; + GList *list = tray_icons_list; + + d(printf("%s:%d (tray_list_remove_cqa_async) - Removing CQA %d from tray list\n",__FILE__, __LINE__, cqa)); + + while (list) { + TrayIconData *tray_data = list->data; + GList *tmp = list; + GtkTreeIter iter; + GtkTreeModel *model; + + list = list->next; + if (tray_data->cqa == cqa) { + d(printf("%s:%d (tray_list_remove_cqa_async) - Found.\n", __FILE__, __LINE__)); + tray_icons_list = g_list_delete_link (tray_icons_list, tmp); + if (alarm_notifications_dialog) { + model = gtk_tree_view_get_model (GTK_TREE_VIEW (alarm_notifications_dialog->treeview)); + gtk_list_store_remove (GTK_LIST_STORE (model), &(tray_data->iter)); + } + free_tray_icon_data (tray_data); + } + } + + d(printf("%s:%d (tray_list_remove_cqa_async) - %d alarms left.\n", __FILE__, __LINE__, g_list_length (tray_icons_list))); + + if (alarm_notifications_dialog) { + if (!g_list_length (tray_icons_list)) { + gtk_widget_destroy (alarm_notifications_dialog->dialog); + g_free (alarm_notifications_dialog); + alarm_notifications_dialog = NULL; + } else { + GtkTreeIter iter; + GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (alarm_notifications_dialog->treeview)); + gboolean valid = gtk_tree_model_get_iter_first (model, &iter); + GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (alarm_notifications_dialog->treeview)); + gtk_tree_selection_select_iter (sel, &iter); + } + } +} + +static void +tray_list_remove_cqa (CompQueuedAlarms *cqa) +{ + AlarmMsg *msg; + struct _tray_cqa_msg *list; + /* These two structures will be freed by the msg destroy function*/ + msg = malloc (sizeof (AlarmMsg)); + msg->receive_msg = tray_list_remove_cqa_async; + + list = malloc (sizeof (struct _tray_cqa_msg)); + list->cqa = cqa; + msg->data = list; + + d(printf("%s:%d (tray_list_remove_cqa) - Posting a task\n",__FILE__, __LINE__)); + e_thread_put(alarm_operation_thread, (EMsg *)msg); +} + /* Callback used from the alarm notify dialog */ +static void +tray_list_remove_async(EThread *e, AlarmMsg *msg, void *data) +{ + GList *list = tray_icons_list; + + d(printf("%s:%d (tray_list_remove_async) - Removing %d alarms\n",__FILE__, __LINE__, g_list_length(list))); + while (list != NULL) { + + TrayIconData *tray_data = list->data; + + if (!tray_data->snooze_set){ + GList *temp = list->next; + tray_icons_list = g_list_remove_link (tray_icons_list, list); + remove_queued_alarm (tray_data->cqa, tray_data->alarm_id, FALSE, TRUE); + g_hash_table_remove (tray_data->cqa->parent_client->uid_alarms_hash, tray_data->cqa->id); + e_cal_component_free_id (tray_data->cqa->id); + g_free (tray_data->cqa); + free_tray_icon_data (tray_data); + tray_data = NULL; + g_list_free_1 (list); + if (tray_icons_list != list) /* List head is modified */ + list = tray_icons_list; + else + list = temp; + } else + list = list->next; + } +} + +static void +tray_list_remove_icons () +{ + AlarmMsg *msg; + + /* These two structures will be freed by the msg destroy function*/ + msg = malloc (sizeof (AlarmMsg)); + msg->receive_msg = tray_list_remove_async; + + msg->data = NULL; + + d(printf("%s:%d (tray_list_remove_icons) - Posting a task\n",__FILE__, __LINE__)); + e_thread_put(alarm_operation_thread, (EMsg *)msg); +} + +struct _tray_msg { + TrayIconData *data; +}; + +static void +tray_list_remove_data_async(EThread *e, AlarmMsg *msg, void *data) +{ + struct _tray_msg *tmsg = msg->data; + TrayIconData *tray_data = tmsg->data; + + d(printf("%s:%d (tray_list_remove_data_async) - Removing %d from tray list\n",__FILE__, __LINE__, tray_data)); + + tray_icons_list = g_list_remove_all (tray_icons_list, tray_data); + free_tray_icon_data (tray_data); + tray_data = NULL; +} + +static void +tray_list_remove_data (TrayIconData *data) +{ + AlarmMsg *msg; + struct _tray_msg *list; + /* These two structures will be freed by the msg destroy function*/ + msg = malloc (sizeof (AlarmMsg)); + msg->receive_msg = tray_list_remove_data_async; + + list = malloc (sizeof (struct _tray_msg)); + list->data = data; + msg->data = list; + + d(printf("%s:%d (tray_list_remove_data) - Posting a task\n",__FILE__, __LINE__)); + e_thread_put(alarm_operation_thread, (EMsg *)msg); +} + static void notify_dialog_cb (AlarmNotifyResult result, int snooze_mins, gpointer data) { TrayIconData *tray_data = data; + + d(printf("%s:%d (notify_dialog_cb) - Received from dialog\n",__FILE__, __LINE__)); g_signal_handlers_disconnect_matched (tray_data->query, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, on_dialog_objs_removed_cb, NULL); switch (result) { case ALARM_NOTIFY_SNOOZE: + d(printf("%s:%d (notify_dialog_cb) - Creating a snooze\n",__FILE__, __LINE__)); create_snooze (tray_data->cqa, tray_data->alarm_id, snooze_mins); tray_data->snooze_set = TRUE; + tray_list_remove_data (tray_data); if (alarm_notifications_dialog) { GtkTreeSelection *selection = gtk_tree_view_get_selection ( @@ -905,7 +1229,7 @@ notify_dialog_cb (AlarmNotifyResult result, int snooze_mins, gpointer data) break; case ALARM_NOTIFY_CLOSE: - + d(printf("%s:%d (notify_dialog_cb) - Dialog close\n",__FILE__, __LINE__)); if (alarm_notifications_dialog) { GList *list; GtkTreeIter iter; @@ -924,27 +1248,8 @@ notify_dialog_cb (AlarmNotifyResult result, int snooze_mins, gpointer data) g_free (alarm_notifications_dialog); alarm_notifications_dialog = NULL; - /* FIXME tray_icons_list is a global data structure - make this thread safe */ - - list = tray_icons_list; - while (list != NULL) { - - tray_data = list->data; - - if (!tray_data->snooze_set){ - GList *temp = list->next; - tray_icons_list = g_list_remove_link (tray_icons_list, list); - remove_queued_alarm (tray_data->cqa, tray_data->alarm_id, TRUE, TRUE); - free_tray_icon_data (tray_data); - tray_data = NULL; - g_list_free_1 (list); - if (tray_icons_list != list) /* List head is modified */ - list = tray_icons_list; - else - list = temp; - } else - list = list->next; - } + /* Task to remove the tray icons */ + tray_list_remove_icons (); } break; @@ -961,7 +1266,8 @@ static gboolean open_alarm_dialog (TrayIconData *tray_data) { QueuedAlarm *qa; - + + d(printf("%s:%d (open_alarm_dialog) \n",__FILE__, __LINE__)); qa = lookup_queued_alarm (tray_data->cqa, tray_data->alarm_id); if (qa) { @@ -1010,6 +1316,7 @@ tray_icon_clicked_cb (GtkWidget *widget, GdkEventButton *event, gpointer user_da TrayIconData *tray_data = user_data; if (event->type == GDK_BUTTON_PRESS) { + d(printf("%s:%d (tray_icon_clicked_cb) - left click and %d alarms\n",__FILE__, __LINE__, g_list_length (tray_icons_list))); if (event->button == 1 && g_list_length (tray_icons_list) > 0) { GList *tmp; for (tmp = tray_icons_list; tmp; tmp = tmp->next) { @@ -1018,11 +1325,11 @@ tray_icon_clicked_cb (GtkWidget *widget, GdkEventButton *event, gpointer user_da return TRUE; } else if (event->button == 3) { - + d(printf("%s:%d (tray_icon_clicked_cb) - right click\n",__FILE__, __LINE__)); if (tray_blink_id > -1) g_source_remove (tray_blink_id); tray_blink_id = -1; - + gtk_widget_destroy (tray_icon); tray_icon = NULL; #ifndef USE_GTK_STATUS_ICON @@ -1073,6 +1380,35 @@ tray_icon_blink_cb (gpointer data) return TRUE; } + +/* Add a new data to tray list */ + +static void +tray_list_add_async (EThread *e, AlarmMsg *msg, void *data) +{ + struct _tray_msg *list = msg->data; + d(printf("%s:%d (tray_list_add_async) - Add %d\n",__FILE__, __LINE__, list->data)); + tray_icons_list = g_list_prepend (tray_icons_list, list->data); +} + +static void +tray_list_add_new (TrayIconData *data) +{ + AlarmMsg *msg; + struct _tray_msg *list; + + /* These two structures will be freed by the msg destroy function*/ + msg = malloc (sizeof (AlarmMsg)); + msg->receive_msg = tray_list_add_async; + + list = malloc (sizeof (struct _tray_msg)); + list->data = data; + msg->data = list; + + d(printf("%s:%d (tray_list_add_new) - Posting a task\n",__FILE__, __LINE__)); + e_thread_put(alarm_operation_thread, (EMsg *)msg); +} + /* Performs notification of a display alarm */ static void display_notification (time_t trigger, CompQueuedAlarms *cqa, @@ -1092,6 +1428,8 @@ display_notification (time_t trigger, CompQueuedAlarms *cqa, icaltimezone *current_zone; ECalComponentOrganizer organiser; + d(printf("%s:%d (display_notification)\n",__FILE__, __LINE__)); + comp = cqa->alarms->comp; qa = lookup_queued_alarm (cqa, alarm_id); if (!qa) @@ -1176,7 +1514,8 @@ display_notification (time_t trigger, CompQueuedAlarms *cqa, g_object_ref (tray_data->client); tray_data->tray_icon = tray_icon; - tray_icons_list = g_list_prepend (tray_icons_list, tray_data); + /* Task to add tray_data to the global tray_icon_list */ + tray_list_add_new (tray_data); if (g_list_length (tray_icons_list) > 1) { char *tip; @@ -1231,6 +1570,8 @@ popup_notification (time_t trigger, CompQueuedAlarms *cqa, icaltimezone *current_zone; ECalComponentOrganizer organiser; char *body; + + d(printf("%s:%d (popup_notification)\n",__FILE__, __LINE__)); comp = cqa->alarms->comp; qa = lookup_queued_alarm (cqa, alarm_id); @@ -1302,6 +1643,8 @@ audio_notification (time_t trigger, CompQueuedAlarms *cqa, icalattach *attach; int flag = 0; + d(printf("%s:%d (audio_notification)\n",__FILE__, __LINE__)); + comp = cqa->alarms->comp; qa = lookup_queued_alarm (cqa, alarm_id); if (!qa) @@ -1341,6 +1684,8 @@ mail_notification (time_t trigger, CompQueuedAlarms *cqa, gpointer alarm_id) /* FIXME */ + d(printf("%s:%d (mail_notification)\n",__FILE__, __LINE__)); + dialog = gtk_dialog_new_with_buttons (_("Warning"), NULL, 0, GTK_STOCK_OK, GTK_RESPONSE_CANCEL, @@ -1361,6 +1706,8 @@ procedure_notification_dialog (const char *cmd, const char *url) GtkWidget *dialog, *label, *checkbox; char *str; int btn; + + d(printf("%s:%d (procedure_notification_dialog)\n",__FILE__, __LINE__)); if (config_data_is_blessed_program (url)) return TRUE; @@ -1411,6 +1758,8 @@ procedure_notification (time_t trigger, CompQueuedAlarms *cqa, gpointer alarm_id char *cmd; int result; + d(printf("%s:%d (procedure_notification)\n",__FILE__, __LINE__)); + comp = cqa->alarms->comp; qa = lookup_queued_alarm (cqa, alarm_id); if (!qa) @@ -1469,14 +1818,27 @@ check_midnight_refresh (gpointer user_data) time_t new_midnight; icaltimezone *zone; + d(printf("%s:%d (check_midnight_refresh)\n",__FILE__, __LINE__)); + zone = config_data_get_timezone (); new_midnight = time_day_end_with_zone (time (NULL), zone); if (new_midnight > midnight) { - /* Re-load the alarms for all clients */ - g_hash_table_foreach (client_alarms_hash, add_client_alarms_cb, NULL); + AlarmMsg *msg; + struct _midnight_refresh_msg *list; + + /* These two structures will be freed by the msg destroy function*/ + msg = malloc (sizeof (AlarmMsg)); + msg->receive_msg = midnight_refresh_async; - queue_midnight_refresh (); + list = malloc (sizeof (struct _midnight_refresh_msg)); + + list->remove = FALSE; + /* We dont need it. So set it to NULL */ + msg->data = list; + + d(printf("%s:%d (check_midnight_refresh) - Posting a task to refresh\n",__FILE__, __LINE__)); + e_thread_put(alarm_operation_thread, (EMsg *)msg); } return TRUE; @@ -1494,12 +1856,15 @@ alarm_queue_init (gpointer data) an = data; g_return_if_fail (alarm_queue_inited == FALSE); + d(printf("%s:%d (alarm_queue_init)\n",__FILE__, __LINE__)); + client_alarms_hash = g_hash_table_new (g_direct_hash, g_direct_equal); queue_midnight_refresh (); saved_notification_time = config_data_get_last_notification_time (); if (saved_notification_time == -1) { saved_notification_time = time (NULL); + d(printf("%s:%d (alarm_queue_init) - Setting last notification time to %s\n",__FILE__, __LINE__, ctime(&saved_notification_time))); config_data_set_last_notification_time (saved_notification_time); } @@ -1518,15 +1883,21 @@ free_client_alarms_cb (gpointer key, gpointer value, gpointer user_data) { ClientAlarms *ca = value; + d(printf("%s:%d (free_client_alarms_cb) - %d \n",__FILE__, __LINE__, ca)); + if (ca) { remove_client_alarms (ca); if (ca->client) { + d(printf("%s:%d (free_client_alarms_cb) - Disconnecting Client \n",__FILE__, __LINE__)); + g_signal_handlers_disconnect_matched (ca->client, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, ca); g_object_unref (ca->client); } if (ca->query) { + d(printf("%s:%d (free_client_alarms_cb) - Disconnecting Query \n",__FILE__, __LINE__)); + g_signal_handlers_disconnect_matched (ca->query, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, ca); g_object_unref (ca->query); @@ -1556,6 +1927,8 @@ alarm_queue_done (void) /* All clients must be unregistered by now */ g_return_if_fail (g_hash_table_size (client_alarms_hash) == 0); + d(printf("%s:%d (alarm_queue_done)\n",__FILE__, __LINE__)); + g_hash_table_foreach_remove (client_alarms_hash, (GHRFunc) free_client_alarms_cb, NULL); g_hash_table_destroy (client_alarms_hash); client_alarms_hash = NULL; @@ -1575,9 +1948,9 @@ compare_ids (gpointer a, gpointer b) id = a; id1 = b; - if (id->uid != NULL && id1->uid != NULL) { if (g_str_equal (id->uid, id1->uid)) { + if (id->rid && id1->rid) return g_str_equal (id->rid, id1->rid); else if (!(id->rid && id1->rid)) @@ -1587,24 +1960,23 @@ compare_ids (gpointer a, gpointer b) return FALSE; } -/** - * alarm_queue_add_client: - * @client: A calendar client. - * - * Adds a calendar client to the alarm queueing system. Alarm trigger - * notifications will be presented at the appropriate times. The client should - * be removed with alarm_queue_remove_client() when receiving notifications - * from it is no longer desired. - * - * A client can be added any number of times to the alarm queueing system, - * but any single alarm trigger will only be presented once for a particular - * client. The client must still be removed the same number of times from the - * queueing system when it is no longer wanted. - **/ -void -alarm_queue_add_client (ECal *client) +static guint +hash_ids (gpointer a) +{ + ECalComponentId *id =a; + + return g_str_hash (id->uid); +} + +struct _alarm_client_msg { + ECal *client; +}; + +static void alarm_queue_add_async (EThread *e, AlarmMsg *msg, void *data) { ClientAlarms *ca; + struct _alarm_client_msg *list = msg->data; + ECal *client = list->client; g_return_if_fail (alarm_queue_inited); g_return_if_fail (client != NULL); @@ -1612,18 +1984,21 @@ alarm_queue_add_client (ECal *client) ca = lookup_client (client); if (ca) { + /* We already have it. Unref the passed one*/ + g_object_unref(client); return; } + d(printf("%s:%d (alarm_queue_add_async) - %d\n",__FILE__, __LINE__, client)); + ca = g_new (ClientAlarms, 1); ca->client = client; ca->query = NULL; - g_object_ref (ca->client); g_hash_table_insert (client_alarms_hash, client, ca); - ca->uid_alarms_hash = g_hash_table_new (g_direct_hash, (GEqualFunc) compare_ids); + ca->uid_alarms_hash = g_hash_table_new ((GHashFunc) hash_ids, (GEqualFunc) compare_ids); if (e_cal_get_load_state (client) == E_CAL_LOAD_LOADED) { load_alarms_for_today (ca); @@ -1631,14 +2006,69 @@ alarm_queue_add_client (ECal *client) g_signal_connect (client, "cal_opened", G_CALLBACK (cal_opened_cb), ca); - } + } +} + +/** + * alarm_queue_add_client: + * @client: A calendar client. + * + * Adds a calendar client to the alarm queueing system. Alarm trigger + * notifications will be presented at the appropriate times. The client should + * be removed with alarm_queue_remove_client() when receiving notifications + * from it is no longer desired. + * + * A client can be added any number of times to the alarm queueing system, + * but any single alarm trigger will only be presented once for a particular + * client. The client must still be removed the same number of times from the + * queueing system when it is no longer wanted. + **/ +void +alarm_queue_add_client (ECal *client) +{ + AlarmMsg *msg; + struct _alarm_client_msg *list; + + /* These two structures will be freed by the msg destroy function*/ + msg = malloc (sizeof (AlarmMsg)); + msg->receive_msg = alarm_queue_add_async; + + list = malloc (sizeof (struct _alarm_client_msg)); + list->client = client; + g_object_ref (client); + msg->data = list; + + d(printf("%s:%d (alarm_queue_add_client) - Posting a task\n",__FILE__, __LINE__)); + e_thread_put(alarm_operation_thread, (EMsg *)msg); } +/* Removes a component an its alarms */ static void +remove_cqa (ClientAlarms *ca, ECalComponentId *id, CompQueuedAlarms *cqa) +{ + + /* If a component is present, then it means we must have alarms queued + * for it. + */ + g_assert (cqa->queued_alarms != NULL); + + d(printf("%s:%d (remove_cqa) - removing %d alarms\n",__FILE__, __LINE__, g_list_length(cqa->queued_alarms))); + remove_alarms (cqa, TRUE); +} + +static gboolean remove_comp_by_id (gpointer key, gpointer value, gpointer userdata) { ClientAlarms *ca = (ClientAlarms *)userdata; - remove_comp (ca, (ECalComponentId *)key); + + d(printf("%s:%d (remove_comp_by_id)\n",__FILE__, __LINE__)); + +/* if (!g_hash_table_size (ca->uid_alarms_hash)) */ +/* return; */ + + remove_cqa (ca, (ECalComponentId *)key, (CompQueuedAlarms *) value); + + return TRUE; } @@ -1646,7 +2076,10 @@ remove_comp_by_id (gpointer key, gpointer value, gpointer userdata) { static void remove_client_alarms (ClientAlarms *ca) { - g_hash_table_foreach (ca->uid_alarms_hash, (GHFunc)remove_comp_by_id, ca); + d(printf("%s:%d (remove_client_alarms) - size %d \n",__FILE__, __LINE__, g_hash_table_size (ca->uid_alarms_hash))); + + g_hash_table_foreach_remove (ca->uid_alarms_hash, (GHFunc)remove_comp_by_id, ca); + /* The hash table should be empty now */ g_assert (g_hash_table_size (ca->uid_alarms_hash) == 0); } @@ -1657,10 +2090,12 @@ remove_client_alarms (ClientAlarms *ca) * * Removes a calendar client from the alarm queueing system. **/ -void -alarm_queue_remove_client (ECal *client) +static void +alarm_queue_remove_async (EThread *e, AlarmMsg *msg, void *data) { ClientAlarms *ca; + struct _alarm_client_msg *list = msg->data; + ECal *client = list->client; g_return_if_fail (alarm_queue_inited); g_return_if_fail (client != NULL); @@ -1669,10 +2104,13 @@ alarm_queue_remove_client (ECal *client) ca = lookup_client (client); g_return_if_fail (ca != NULL); + d(printf("%s:%d (alarm_queue_remove_async) \n",__FILE__, __LINE__)); remove_client_alarms (ca); /* Clean up */ if (ca->client) { + d(printf("%s:%d (alarm_queue_remove_async) - Disconnecting Client \n",__FILE__, __LINE__)); + g_signal_handlers_disconnect_matched (ca->client, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, ca); g_object_unref (ca->client); @@ -1680,6 +2118,8 @@ alarm_queue_remove_client (ECal *client) } if (ca->query) { + d(printf("%s:%d (alarm_queue_remove_async) - Disconnecting Query \n",__FILE__, __LINE__)); + g_signal_handlers_disconnect_matched (ca->query, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, ca); g_object_unref (ca->query); @@ -1694,6 +2134,24 @@ alarm_queue_remove_client (ECal *client) g_hash_table_remove (client_alarms_hash, client); } +void +alarm_queue_remove_client (ECal *client) +{ + AlarmMsg *msg; + struct _alarm_client_msg *list; + + /* These two structures will be freed by the msg destroy function*/ + msg = malloc (sizeof (AlarmMsg)); + msg->receive_msg = alarm_queue_remove_async; + + list = malloc (sizeof (struct _alarm_client_msg)); + list->client = client; + msg->data = list; + + d(printf("%s:%d (alarm_queue_remove_client) - Posting a task\n",__FILE__, __LINE__)); + e_thread_put(alarm_operation_thread, (EMsg *)msg); +} + /* Update non-time related variables for various structures on modification of an existing component to be called only from query_objects_changed_cb */ static void @@ -1712,7 +2170,7 @@ update_cqa (CompQueuedAlarms *cqa, ECalComponent *newcomp) from = time_day_begin_with_zone (time (NULL), zone); to = time_day_end_with_zone (time (NULL), zone); - + d(printf("%s:%d (update_cqa) - Generating alarms between %s and %s\n",__FILE__, __LINE__, ctime(&from), ctime(&to))); alarms = e_cal_util_generate_alarms_for_comp (newcomp, from, to, omit, e_cal_resolve_tzid_cb, cqa->parent_client->client, zone); @@ -1726,7 +2184,7 @@ update_cqa (CompQueuedAlarms *cqa, ECalComponent *newcomp) else { if (e_cal_component_get_alarm (oldcomp, check_auid)) { /* Need to update QueuedAlarms */ if (alarms == NULL) { - g_warning ("No alarms found on the modified component\n"); + d(printf("%s:%d (update_cqa) - No alarms found in the modified component\n",__FILE__, __LINE__)); break; } update_qa (alarms, qa); @@ -1748,7 +2206,8 @@ update_qa (ECalComponentAlarms *alarms, QueuedAlarm *qa) { ECalComponentAlarmInstance *al_inst; GSList *instance_list; - + + d(printf("%s:%d (update_qa)\n",__FILE__, __LINE__)); for (instance_list = alarms->alarms; instance_list; instance_list = instance_list->next) { al_inst = instance_list->data; if (al_inst->trigger == qa->orig_trigger) { /* FIXME if two or more alarm instances (audio, note) for same component have same trigger */ diff --git a/calendar/gui/alarm-notify/alarm.c b/calendar/gui/alarm-notify/alarm.c index 1eb9d899b5..b360075d13 100644 --- a/calendar/gui/alarm-notify/alarm.c +++ b/calendar/gui/alarm-notify/alarm.c @@ -249,9 +249,6 @@ alarm_remove (gpointer alarm) } /* Reset the timeout */ - - g_assert (timeout_id != 0); - if (!alarms) { g_source_remove (timeout_id); timeout_id = 0; -- cgit v1.2.3