/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 2 -*- */ /* * gcal-manager.c * Copyright (C) 2012 Erick Pérez Castellanos * * gnome-calendar is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * gnome-calendar is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "gcal-manager.h" #include "gcal-utils.h" #include #include #include #include #include enum { COLUMN_UID = 0, //corresponding source uid COLUMN_NAME, COLUMN_ACTIVE, COLUMN_COLOR, N_COLUMNS }; struct _RetryOpenData { EClient *client; GcalManager *manager; GCancellable *cancellable; }; typedef struct _RetryOpenData RetryOpenData; struct _GcalManagerUnit { ESource *source; ECalClient *client; ECalClientView *view; /** * The hash containing events retrieved. * Keys are the uid of the component * Values are the component itself */ GHashTable *events; gboolean enabled; }; typedef struct _GcalManagerUnit GcalManagerUnit; struct _GcalManagerPrivate { /** * The list of clients we are managing. * Each value is of type GCalStoreUnit * And each key is the source uid */ GHashTable *clients; /** * System sources read from gconf */ ESourceList *system_sources; /* The store for keeping easily retrieved data about sources */ GtkListStore *sources_model; /* The range of dates defining the query */ icaltimetype *initial_date; icaltimetype *final_date; /* The active query */ gchar *query; GCancellable *loading_clients; }; /* Signal IDs */ enum { EVENTS_ADDED, EVENTS_MODIFIED, EVENTS_REMOVED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL]; static void gcal_manager_constructed (GObject *object); static void gcal_manager_finalize (GObject *object); void gcal_manager_free_unit_data (gpointer data); static void gcal_manager_on_client_opened (GObject *source_object, GAsyncResult *result, gpointer user_data); static gboolean gcal_manager_retry_open_on_timeout (gpointer user_data); static void gcal_manager_free_retry_open_data (gpointer user_data); void gcal_manager_remove_client (GcalManager *manager, ECalClient *client); static void gcal_manager_load_source (GcalManager *manager, ESource *source); static void gcal_manager_reload_events (GcalManager *manager); static void gcal_manager_reload_view (GcalManager *manager, GcalManagerUnit *unit); static void gcal_manager_on_view_objects_added (ECalClientView *view, gpointer objects, gpointer user_data); static void gcal_manager_on_view_objects_removed (ECalClientView *view, gpointer objects, gpointer user_data); static void gcal_manager_on_view_objects_modified (ECalClientView *view, gpointer objects, gpointer user_data); static void gcal_manager_on_sources_row_changed (GtkTreeModel *store, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data); G_DEFINE_TYPE(GcalManager, gcal_manager, G_TYPE_OBJECT) static void gcal_manager_class_init (GcalManagerClass *klass) { G_OBJECT_CLASS (klass)->constructed = gcal_manager_constructed; G_OBJECT_CLASS (klass)->finalize = gcal_manager_finalize; signals[EVENTS_ADDED] = g_signal_new ("events-added", GCAL_TYPE_MANAGER, G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GcalManagerClass, events_added), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[EVENTS_MODIFIED] = g_signal_new ("events-modified", GCAL_TYPE_MANAGER, G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GcalManagerClass, events_modified), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[EVENTS_REMOVED] = g_signal_new ("evens-removed", GCAL_TYPE_MANAGER, G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GcalManagerClass, events_removed), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); g_type_class_add_private ((gpointer) klass, sizeof(GcalManagerPrivate)); } static void gcal_manager_init (GcalManager *self) { GcalManagerPrivate *priv; self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCAL_TYPE_MANAGER, GcalManagerPrivate); priv = self->priv; priv->sources_model = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, GDK_TYPE_COLOR); g_object_ref_sink (priv->sources_model); g_signal_connect (priv->sources_model, "row-changed", G_CALLBACK (gcal_manager_on_sources_row_changed), self); priv->initial_date = g_new(icaltimetype, 1); *(priv->initial_date) = icaltime_from_timet (time (NULL), 0); priv->final_date = g_new(icaltimetype, 1); *(priv->final_date) = icaltime_from_timet (time (NULL), 0); priv->clients = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, gcal_manager_free_unit_data); } static void gcal_manager_constructed (GObject *object) { GcalManagerPrivate *priv; GError *error; GSList *l_groups; GSList *l; if (G_OBJECT_CLASS (gcal_manager_parent_class)->constructed != NULL) G_OBJECT_CLASS (gcal_manager_parent_class)->constructed (object); priv = GCAL_MANAGER (object)->priv; if (!e_cal_client_get_sources (&(priv->system_sources), E_CAL_CLIENT_SOURCE_TYPE_EVENTS, &error)) { //FIXME maybe give more information of what happened g_warning ("%s", error->message); } for (l_groups = e_source_list_peek_groups (priv->system_sources); l_groups != NULL; l_groups = l_groups->next) { for (l = e_source_group_peek_sources (E_SOURCE_GROUP (l_groups->data)); l != NULL; l = l->next) { gcal_manager_load_source (GCAL_MANAGER (object), l->data); } } } static void gcal_manager_finalize (GObject *object) { GcalManagerPrivate *priv; priv = GCAL_MANAGER (object)->priv; g_hash_table_destroy (priv->clients); g_clear_object (&(priv->sources_model)); } void gcal_manager_free_unit_data (gpointer data) { GcalManagerUnit *unit; unit = (GcalManagerUnit*) data; g_clear_object (&(unit->source)); g_clear_object (&(unit->client)); g_clear_object (&(unit->view)); g_hash_table_destroy (unit->events); g_free (unit); } static void gcal_manager_on_client_opened (GObject *source_object, GAsyncResult *result, gpointer user_data) { ECalClient *client; GcalManagerPrivate *priv; GError *error; ESource *source; const gchar *uid; GcalManagerUnit *unit; client = E_CAL_CLIENT (source_object); priv = ((GcalManager*) user_data)->priv; error = NULL; if (e_client_open_finish (E_CLIENT (client), result, &error)) { /* get_object_list */ if (priv->query != NULL) { uid = e_source_peek_uid (e_client_get_source (E_CLIENT (client))); unit = (GcalManagerUnit*) g_hash_table_lookup (priv->clients, uid); /* setting view */ gcal_manager_reload_view (GCAL_MANAGER (user_data), unit); } } else { if (error != NULL) { /* handling error */ g_warning ("%s", error->message); if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { g_error_free (error); return; } if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY)) { RetryOpenData *rod; rod = g_new0 (RetryOpenData, 1); rod->client = g_object_ref (client); rod->manager = user_data; rod->cancellable = g_object_ref (priv->loading_clients); /* postpone for 1/2 of a second, backend is busy now */ g_timeout_add_full (G_PRIORITY_DEFAULT, 500, gcal_manager_retry_open_on_timeout, rod, gcal_manager_free_retry_open_data); g_error_free (error); return; } /* in any other case, remove it*/ source = e_client_get_source (E_CLIENT (client)); gcal_manager_remove_client (GCAL_MANAGER (user_data), client); g_warning ("%s: Failed to open '%s': %s", G_STRFUNC, e_source_peek_name (source), error->message); g_error_free (error); return; } } // /* to have them ready for later use */ // e_client_retrieve_capabilities ( // E_CLIENT (client), manager->priv->loading_clients, // cal_model_retrieve_capabilies_cb, model); } static gboolean gcal_manager_retry_open_on_timeout (gpointer user_data) { RetryOpenData *rod = user_data; g_return_val_if_fail (rod != NULL, FALSE); g_return_val_if_fail (rod->client != NULL, FALSE); g_return_val_if_fail (rod->manager != NULL, FALSE); e_client_open (rod->client, TRUE, rod->cancellable, gcal_manager_on_client_opened, rod->manager); return FALSE; } static void gcal_manager_free_retry_open_data (gpointer user_data) { RetryOpenData *rod = user_data; if (rod == NULL) return; g_object_unref (rod->client); g_object_unref (rod->cancellable); g_free (rod); } void gcal_manager_remove_client (GcalManager *manager, ECalClient *client) { GcalManagerPrivate *priv; g_return_if_fail (GCAL_IS_MANAGER (manager)); g_return_if_fail (E_IS_CAL_CLIENT (client)); priv = manager->priv; g_hash_table_remove ( priv->clients, e_source_peek_uid (e_client_get_source (E_CLIENT (client)))); } static void gcal_manager_load_source (GcalManager *manager, ESource *source) { GcalManagerPrivate *priv; ECalClient *new_client; GcalManagerUnit *unit; GError *error; GtkTreeIter iter; GdkColor gdk_color; priv = manager->priv; error = NULL; new_client = e_cal_client_new (source, E_CAL_CLIENT_SOURCE_TYPE_EVENTS, &error); if (error != NULL) { g_warning ("Couldn't create ECalClient. Error: %s", error->message); g_error_free (error); return; } unit = g_new0 (GcalManagerUnit, 1); unit->client = g_object_ref (new_client); unit->source = source; unit->events = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); g_hash_table_insert (priv->clients, g_strdup (e_source_peek_uid (source)), unit); /* filling store */ gdk_color_parse (e_source_peek_color_spec (source), &gdk_color); gtk_list_store_append (priv->sources_model, &iter); gtk_list_store_set (priv->sources_model, &iter, COLUMN_UID, e_source_peek_uid (source), COLUMN_NAME, e_source_peek_name (source), COLUMN_ACTIVE, TRUE, COLUMN_COLOR, &gdk_color, -1); e_client_open (E_CLIENT (unit->client), TRUE, priv->loading_clients, gcal_manager_on_client_opened, manager); } /** * gcal_manager_reload_events: * * @manager: Self * * This executes every time a new query has been set. * So, there are a bunch of stuff to be done here: * * * Retrieving Object list with the new query. * * * Releasing the old view, desconnecting the callbacks * * * Creating a new view, connecting callbacks * * */ static void gcal_manager_reload_events (GcalManager *manager) { GcalManagerPrivate *priv; GHashTableIter iter; gpointer key; gpointer value; priv = manager->priv; g_hash_table_iter_init (&iter, priv->clients); while (g_hash_table_iter_next (&iter, &key, &value)) { gcal_manager_reload_view (manager, (GcalManagerUnit*) value); } } static void gcal_manager_reload_view (GcalManager *manager, GcalManagerUnit *unit) { GcalManagerPrivate *priv; GError *error; priv = manager->priv; g_return_if_fail (priv->query != NULL); /* stopping */ if (unit->view != NULL) g_clear_object (&(unit->view)); error = NULL; if (e_cal_client_get_view_sync (unit->client, priv->query, &(unit->view), priv->loading_clients, &error)) { /*hooking signals */ g_signal_connect (unit->view, "objects-added", G_CALLBACK (gcal_manager_on_view_objects_added), manager); g_signal_connect (unit->view, "objects-removed", G_CALLBACK (gcal_manager_on_view_objects_removed), manager); g_signal_connect (unit->view, "objects-modified", G_CALLBACK (gcal_manager_on_view_objects_modified), manager); error = NULL; e_cal_client_view_set_fields_of_interest (unit->view, NULL, &error); error = NULL; e_cal_client_view_start (unit->view, &error); if (error != NULL) { g_clear_object (&(unit->view)); g_warning ("%s", error->message); } } else { g_warning ("%s", error->message); } } /** * gcal_manager_on_view_objects_added * @view: the view emitting the signal * @objects: a GSList of icalcomponent* * @user_data: The data passed when connecting the signal, here GcalManager */ static void gcal_manager_on_view_objects_added (ECalClientView *view, gpointer objects, gpointer user_data) { GcalManagerPrivate *priv; GcalManagerUnit *unit; GSList *l; GSList *events_data; ECalClient *client; const gchar *source_uid; gchar *event_uuid; priv = GCAL_MANAGER (user_data)->priv; events_data = NULL; client = e_cal_client_view_get_client (view); source_uid = e_source_peek_uid (e_client_get_source (E_CLIENT (client))); unit = (GcalManagerUnit*) g_hash_table_lookup (priv->clients, source_uid); for (l = objects; l != NULL; l = l->next) { if (l->data != NULL) { ECalComponent *component; if (! g_hash_table_lookup_extended (unit->events, icalcomponent_get_uid (l->data), NULL, NULL)) { component = e_cal_component_new_from_icalcomponent ( icalcomponent_new_clone (l->data)); g_hash_table_insert (unit->events, g_strdup (icalcomponent_get_uid (l->data)), component); event_uuid = g_strdup_printf ("%s:%s", source_uid, icalcomponent_get_uid (l->data)); events_data = g_slist_append (events_data, event_uuid); } } } if (events_data != NULL) { g_signal_emit (GCAL_MANAGER (user_data), signals[EVENTS_ADDED], 0, events_data); g_slist_free_full (events_data, g_free); } } /** * gcal_manager_on_view_objects_removed * @view: the view emitting the signal * @objects: a GSList of ECalComponentId* * @user_data: The data passed when connecting the signal, here GcalManager */ static void gcal_manager_on_view_objects_removed (ECalClientView *view, gpointer objects, gpointer user_data) { } /** * gcal_manager_on_view_objects_modified * @view: the view emitting the signal * @objects: a GSList of icalcomponent* * @user_data: The data passed when connecting the signal, here GcalManager */ static void gcal_manager_on_view_objects_modified (ECalClientView *view, gpointer objects, gpointer user_data) { } static void gcal_manager_on_sources_row_changed (GtkTreeModel *store, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { GcalManagerPrivate *priv; GcalManagerUnit *unit; gchar *source_uid; gboolean active; priv = GCAL_MANAGER (user_data)->priv; gtk_tree_model_get (store, iter, COLUMN_UID, &source_uid, COLUMN_ACTIVE, &active, -1); unit = g_hash_table_lookup (priv->clients, source_uid); unit->enabled = active; g_free (source_uid); } /** * gcal_manager_new: * * Since: 0.0.1 * Return value: the new #GcalManager * Returns: (transfer full): **/ GcalManager* gcal_manager_new (void) { return GCAL_MANAGER (g_object_new (GCAL_TYPE_MANAGER, NULL)); } GtkListStore* gcal_manager_get_sources_model (GcalManager *manager) { g_return_val_if_fail (GCAL_IS_MANAGER (manager), NULL); return manager->priv->sources_model; } /** * gcal_manager_add_source: * @manager: a #GcalManager * @base_uri: URI defining the ESourceGroup the client will belongs * @relative_uri: URI, relative to the base URI * @color: a string representing a color parseable for gdk_color_parse * * Add a new calendar by its URI. * The calendar is enabled by default * * Return value: The UID of calendar's source, NULL in other case * Returns: (transfer full): * * Since: 0.0.1 */ gchar* gcal_manager_add_source (GcalManager *manager, const gchar *name, const gchar *base_uri, const gchar *relative_uri, const gchar *color) { GcalManagerPrivate *priv; GSList *groups; ESourceGroup *selected_group; GHashTableIter iter; gpointer key; gpointer value; ESource *source; g_return_val_if_fail (GCAL_IS_MANAGER (manager), NULL); priv = manager->priv; g_return_val_if_fail (GCAL_IS_MANAGER (manager), FALSE); selected_group = NULL; for (groups = e_source_list_peek_groups (priv->system_sources); groups != NULL; groups = groups->next) { if (g_strcmp0 ( base_uri, e_source_group_peek_base_uri (E_SOURCE_GROUP (groups->data))) == 0) { selected_group = (ESourceGroup*) groups->data; g_hash_table_iter_init (&iter, priv->clients); while (g_hash_table_iter_next (&iter, &key, &value)) { GcalManagerUnit *unit = (GcalManagerUnit*) value; if (g_strcmp0 ( e_source_peek_relative_uri (unit->source), relative_uri) == 0) { return NULL; } } break; } } if (selected_group == NULL) { selected_group = e_source_group_new (gcal_get_group_name (base_uri), base_uri); e_source_list_add_group (priv->system_sources, selected_group, -1); } source = e_source_new (name, relative_uri); e_source_group_add_source (selected_group, source, -1); gcal_manager_load_source (manager, source); return g_strdup (e_source_peek_uid (source)); } const gchar* gcal_manager_get_source_name (GcalManager *manager, const gchar *source_uid) { GcalManagerPrivate *priv; GcalManagerUnit *unit; g_return_val_if_fail (GCAL_IS_MANAGER (manager), NULL); priv = manager->priv; unit = g_hash_table_lookup (priv->clients, source_uid); return e_source_peek_name (unit->source); } /** * gcal_manager_set_new_range: * @manager: a #GcalManager * @initial_date: starting date of the new range * @final_date: final date of the new range * * Sets a new range of date to look for events. * This method compares the dates to find out * the larger range, between the new one and the old. * It signals once the range it's been set and the * events retrieved for it. This methods triggers * an update of the internal list of events for every * opened calendar; a signal would be emitted * when the updated it's done. * * Return value: void * * Since: 0.0.1 */ void gcal_manager_set_new_range (GcalManager *manager, const icaltimetype *initial_date, const icaltimetype *final_date) { GcalManagerPrivate *priv; gboolean refresh_events; g_return_if_fail (GCAL_IS_MANAGER (manager)); priv = manager->priv; refresh_events = FALSE; /* updating query range */ if ((icaltime_compare (*(priv->initial_date), *initial_date)) == 1) { /* switch dates */ *(priv->initial_date) = *initial_date; refresh_events = TRUE; } if (icaltime_compare (*(priv->final_date), *final_date) == -1) { /* switch dates */ *(priv->final_date) = *final_date; refresh_events = TRUE; } if (refresh_events) { /* rebuild query */ gchar* since_iso8601 = isodate_from_time_t (icaltime_as_timet (*(priv->initial_date))); gchar* until_iso8601 = isodate_from_time_t (icaltime_as_timet (*(priv->final_date))); if (priv->query != NULL) g_free (priv->query); priv->query = g_strdup_printf ( "occur-in-time-range? (make-time \"%s\") " "(make-time \"%s\")", since_iso8601, until_iso8601); g_debug ("Query %s", priv->query); /* redoing query */ gcal_manager_reload_events (manager); } } gboolean gcal_manager_exists_event (GcalManager *manager, const gchar *source_uid, const gchar *event_uid) { GcalManagerPrivate *priv; GcalManagerUnit *unit; g_return_val_if_fail (GCAL_IS_MANAGER (manager), FALSE); priv = manager->priv; if ((unit = g_hash_table_lookup (priv->clients, source_uid)) != NULL) return g_hash_table_lookup (unit->events, event_uid) != NULL; return FALSE; } icaltimetype* gcal_manager_get_event_start_date (GcalManager *manager, const gchar *source_uid, const gchar *event_uid) { GcalManagerPrivate *priv; GcalManagerUnit *unit; ECalComponent *event; ECalComponentDateTime dt; icaltimetype *dtstart; g_return_val_if_fail (GCAL_IS_MANAGER (manager), NULL); priv = manager->priv; unit = g_hash_table_lookup (priv->clients, source_uid); event = g_hash_table_lookup (unit->events, event_uid); e_cal_component_get_dtstart (event, &dt); dtstart = gcal_dup_icaltime (dt.value); e_cal_component_free_datetime (&dt); return dtstart; } gchar* gcal_manager_get_event_summary (GcalManager *manager, const gchar *source_uid, const gchar *event_uid) { GcalManagerPrivate *priv; GcalManagerUnit *unit; ECalComponent *event; ECalComponentText e_summary; gchar *summary; g_return_val_if_fail (GCAL_IS_MANAGER (manager), NULL); priv = manager->priv; unit = g_hash_table_lookup (priv->clients, source_uid); event = g_hash_table_lookup (unit->events, event_uid); e_cal_component_get_summary (event, &e_summary); summary = g_strdup (e_summary.value); return summary; } gchar** gcal_manager_get_event_organizer (GcalManager *manager, const gchar *source_uid, const gchar *event_uid) { GcalManagerPrivate *priv; GcalManagerUnit *unit; ECalComponent *event; ECalComponentOrganizer e_organizer; gchar** values; g_return_val_if_fail (GCAL_IS_MANAGER (manager), NULL); priv = manager->priv; unit = g_hash_table_lookup (priv->clients, source_uid); event = g_hash_table_lookup (unit->events, event_uid); e_cal_component_get_organizer (event, &e_organizer); if (e_organizer.cn == NULL) return NULL; values = g_new (gchar*, 3); values[2] = NULL; values[0] = g_strdup (e_organizer.cn); values[1] = g_strdup (e_organizer.value); return values; } gchar* gcal_manager_get_event_date (GcalManager *manager, const gchar *source_uid, const gchar *event_uid) { GcalManagerPrivate *priv; GcalManagerUnit *unit; ECalComponent *event; ECalComponentDateTime dt; icaltimetype *dtstart; icaltimetype *dtend; struct tm tm_date; gchar *date; gchar since [128]; gchar until [128]; gchar *all_day; g_return_val_if_fail (GCAL_IS_MANAGER (manager), NULL); priv = manager->priv; unit = g_hash_table_lookup (priv->clients, source_uid); event = g_hash_table_lookup (unit->events, event_uid); e_cal_component_get_dtstart (event, &dt); dtstart = gcal_dup_icaltime (dt.value); e_cal_component_free_datetime (&dt); e_cal_component_get_dtend (event, &dt); dtend = gcal_dup_icaltime (dt.value); e_cal_component_free_datetime (&dt); if (dtstart->is_date == 1 && dtend->is_date == 1) { all_day = g_strdup (_(" (All day)")); tm_date = icaltimetype_to_tm (dtstart); e_utf8_strftime_fix_am_pm (since, 128, "%b, %d", &tm_date); tm_date = icaltimetype_to_tm (dtstart); e_utf8_strftime_fix_am_pm (until, 128, "%b, %d", &tm_date); } else { all_day = NULL; tm_date = icaltimetype_to_tm (dtstart); e_utf8_strftime_fix_am_pm (since, 128, "%b, %d, %l:%M %p", &tm_date); tm_date = icaltimetype_to_tm (dtstart); e_utf8_strftime_fix_am_pm (until, 128, "%b, %d, %l:%M %p", &tm_date); } date = g_strdup_printf ("%s - %s%s", since, until, all_day == NULL ? "": all_day); g_free (all_day); g_free (dtstart); g_free (dtend); return date; } const gchar* gcal_manager_get_event_location (GcalManager *manager, const gchar *source_uid, const gchar *event_uid) { GcalManagerPrivate *priv; GcalManagerUnit *unit; ECalComponent *event; const gchar* location; g_return_val_if_fail (GCAL_IS_MANAGER (manager), NULL); priv = manager->priv; unit = g_hash_table_lookup (priv->clients, source_uid); event = g_hash_table_lookup (unit->events, event_uid); e_cal_component_get_location (event, &location); return location; } gchar* gcal_manager_get_event_description (GcalManager *manager, const gchar *source_uid, const gchar *event_uid) { GcalManagerPrivate *priv; GcalManagerUnit *unit; ECalComponent *event; GSList *text_list; GSList *l; gchar *desc; g_return_val_if_fail (GCAL_IS_MANAGER (manager), NULL); priv = manager->priv; desc = NULL; unit = g_hash_table_lookup (priv->clients, source_uid); event = g_hash_table_lookup (unit->events, event_uid); e_cal_component_get_description_list (event, &text_list); for (l = text_list; l != NULL; l = l->next) { if (l->data != NULL) { ECalComponentText *text; gchar *carrier; text = l->data; if (desc != NULL) { carrier = g_strconcat (desc, text->value, NULL); g_free (desc); desc = carrier; } else { desc = g_strdup (text->value); } } } e_cal_component_free_text_list (text_list); return desc; } GdkRGBA* gcal_manager_get_event_color (GcalManager *manager, const gchar *source_uid, const gchar *event_uid) { GcalManagerPrivate *priv; GcalManagerUnit *unit; GdkRGBA *color; GdkColor gdk_color; g_return_val_if_fail (GCAL_IS_MANAGER (manager), NULL); priv = manager->priv; color = g_new0 (GdkRGBA, 1); unit = g_hash_table_lookup (priv->clients, source_uid); gdk_color_parse (e_source_peek_color_spec (unit->source), &gdk_color); color->red = (gdouble) gdk_color.red / 65535; color->green = (gdouble) gdk_color.green / 65535; color->blue = (gdouble) gdk_color.blue / 65535; color->alpha = 1; return color; }