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-queue.c | 665 +++++++++++++++++++++++++++----- 1 file changed, 562 insertions(+), 103 deletions(-) (limited to 'calendar/gui/alarm-notify/alarm-queue.c') 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 */ -- cgit v1.2.3