diff options
author | Ted Gould <ted@gould.cx> | 2013-09-06 12:51:45 -0500 |
---|---|---|
committer | Ted Gould <ted@gould.cx> | 2013-09-06 12:51:45 -0500 |
commit | f5746cfe118abf74fd2ef75ed4fb03d9a92cfa14 (patch) | |
tree | dc406c0e6d7cf106288c1048beedea1ae1fe69b0 | |
parent | 55ed2b1b22607f3b9618640294d233eee15db767 (diff) | |
parent | ddebe3c47040869cb8fe94729c43f10f2b763550 (diff) | |
download | ayatana-indicator-datetime-f5746cfe118abf74fd2ef75ed4fb03d9a92cfa14.tar.gz ayatana-indicator-datetime-f5746cfe118abf74fd2ef75ed4fb03d9a92cfa14.tar.bz2 ayatana-indicator-datetime-f5746cfe118abf74fd2ef75ed4fb03d9a92cfa14.zip |
Merge trunk
-rw-r--r-- | src/planner-eds.c | 341 | ||||
-rw-r--r-- | src/planner.c | 31 | ||||
-rw-r--r-- | src/planner.h | 38 | ||||
-rw-r--r-- | src/service.c | 241 | ||||
-rw-r--r-- | src/timezone-geoclue.c | 16 |
5 files changed, 490 insertions, 177 deletions
diff --git a/src/planner-eds.c b/src/planner-eds.c index 276058d..f121a32 100644 --- a/src/planner-eds.c +++ b/src/planner-eds.c @@ -19,8 +19,6 @@ #include "config.h" -#include <gio/gio.h> /* GFile, GFileMonitor */ - #include <libical/ical.h> #include <libical/icaltime.h> #include <libecal/libecal.h> @@ -30,6 +28,8 @@ struct _IndicatorDatetimePlannerEdsPriv { + GSList * sources; + GCancellable * cancellable; ESourceRegistry * source_registry; }; @@ -39,6 +39,8 @@ G_DEFINE_TYPE (IndicatorDatetimePlannerEds, indicator_datetime_planner_eds, INDICATOR_TYPE_DATETIME_PLANNER) +G_DEFINE_QUARK ("source-client", source_client) + /*** **** ***/ @@ -52,7 +54,7 @@ indicator_datetime_appt_free (struct IndicatorDatetimeAppt * appt) g_date_time_unref (appt->begin); g_free (appt->color); g_free (appt->summary); - g_free (appt); + g_slice_free (struct IndicatorDatetimeAppt, appt); } } @@ -60,23 +62,70 @@ indicator_datetime_appt_free (struct IndicatorDatetimeAppt * appt) **** my_get_appointments() helpers ***/ -struct my_get_appointments_data +struct get_appointments_task_data { - ESource * source; + /* how many subtasks are still running on */ + int subtask_count; + + /* the list of appointments to be returned */ GSList * appointments; /* ensure that recurring events don't get multiple IndicatorDatetimeAppts */ GHashTable * added; }; +static void +get_appointments_task_data_free (gpointer gdata) +{ + struct get_appointments_task_data * data = gdata; + g_hash_table_unref (data->added); + g_slice_free (struct get_appointments_task_data, data); +} + +static void +on_all_subtasks_done (GTask * task) +{ + struct get_appointments_task_data * data = g_task_get_task_data (task); + g_task_return_pointer (task, data->appointments, NULL); + g_object_unref (task); +} + +struct get_appointments_subtask_data +{ + GTask * task; + + gchar * color; +}; + +static void +on_subtask_done (gpointer gsubdata) +{ + struct get_appointments_subtask_data * subdata; + GTask * task; + struct get_appointments_task_data * data; + + subdata = gsubdata; + task = subdata->task; + + /* free the subtask data */ + g_free (subdata->color); + g_slice_free (struct get_appointments_subtask_data, subdata); + + /* poke the task */ + data = g_task_get_task_data (task); + if (g_atomic_int_dec_and_test (&data->subtask_count)) + on_all_subtasks_done (task); +} + static gboolean my_get_appointments_foreach (ECalComponent * component, time_t begin, time_t end, - gpointer gdata) + gpointer gsubdata) { const ECalComponentVType vtype = e_cal_component_get_vtype (component); - struct my_get_appointments_data * data = gdata; + struct get_appointments_subtask_data * subdata = gsubdata; + struct get_appointments_task_data * data = g_task_get_task_data (subdata->task); if ((vtype == E_CAL_COMPONENT_EVENT) || (vtype == E_CAL_COMPONENT_TODO)) { @@ -97,7 +146,7 @@ my_get_appointments_foreach (ECalComponent * component, ECalComponentText text; struct IndicatorDatetimeAppt * appt; - appt = g_new0 (struct IndicatorDatetimeAppt, 1); + appt = g_slice_new0 (struct IndicatorDatetimeAppt); /* Determine whether this is a recurring event. NB: icalrecurrencetype supports complex recurrence patterns; @@ -117,7 +166,7 @@ my_get_appointments_foreach (ECalComponent * component, appt->begin = g_date_time_new_from_unix_local (begin); appt->end = g_date_time_new_from_unix_local (end); - appt->color = e_source_selectable_dup_color (e_source_get_extension (data->source, E_SOURCE_EXTENSION_CALENDAR)); + appt->color = g_strdup (subdata->color); appt->is_event = vtype == E_CAL_COMPONENT_EVENT; appt->summary = g_strdup (text.value); @@ -133,24 +182,26 @@ my_get_appointments_foreach (ECalComponent * component, return G_SOURCE_CONTINUE; } - /*** **** IndicatorDatetimePlanner virtual funcs ***/ -static GSList * +static void my_get_appointments (IndicatorDatetimePlanner * planner, GDateTime * begin_datetime, - GDateTime * end_datetime) + GDateTime * end_datetime, + GAsyncReadyCallback callback, + gpointer user_data) { - GList * l; - GList * sources; + GSList * l; priv_t * p; const char * str; icaltimezone * default_timezone; - struct my_get_appointments_data data; + struct get_appointments_task_data * data; const int64_t begin = g_date_time_to_unix (begin_datetime); const int64_t end = g_date_time_to_unix (end_datetime); + GTask * task; + gboolean subtasks_added; p = INDICATOR_DATETIME_PLANNER_EDS (planner)->priv; @@ -172,60 +223,56 @@ my_get_appointments (IndicatorDatetimePlanner * planner, *** walk through the sources to build the appointment list **/ - data.source = NULL; - data.appointments = NULL; - data.added = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + data = g_slice_new0 (struct get_appointments_task_data); + data->added = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + task = g_task_new (planner, p->cancellable, callback, user_data); + g_task_set_task_data (task, data, get_appointments_task_data_free); - sources = e_source_registry_list_sources (p->source_registry, E_SOURCE_EXTENSION_CALENDAR); - for (l=sources; l!=NULL; l=l->next) + subtasks_added = FALSE; + for (l=p->sources; l!=NULL; l=l->next) { - GError * err; ESource * source; - ECalClient * ecc; - - source = E_SOURCE (l->data); - if (e_source_get_enabled (source)) - { - err = NULL; - ecc = e_cal_client_new (source, E_CAL_CLIENT_SOURCE_TYPE_EVENTS, &err); - if (err != NULL) - { - g_warning ("Can't create ecal client: %s", err->message); - g_error_free (err); - } - else - { - if (!e_client_open_sync (E_CLIENT (ecc), TRUE, NULL, &err)) - { - g_debug ("Failed to open ecal client: %s", err->message); - g_error_free (err); - } - else - { - if (default_timezone != NULL) - e_cal_client_set_default_timezone (ecc, default_timezone); - - data.source = source; - e_cal_client_generate_instances_sync (ecc, begin, end, my_get_appointments_foreach, &data); - } - - g_object_unref (ecc); - } - } + ECalClient * client; + struct get_appointments_subtask_data * subdata; + + source = l->data; + client = g_object_get_qdata (l->data, source_client_quark()); + if (client == NULL) + continue; + + if (default_timezone != NULL) + e_cal_client_set_default_timezone (client, default_timezone); + + subdata = g_slice_new (struct get_appointments_subtask_data); + subdata->task = task; + subdata->color = e_source_selectable_dup_color (e_source_get_extension (source, E_SOURCE_EXTENSION_CALENDAR)); + + g_atomic_int_inc (&data->subtask_count); + subtasks_added = TRUE; + e_cal_client_generate_instances (client, + begin, + end, + p->cancellable, + my_get_appointments_foreach, + subdata, + on_subtask_done); } - g_list_free_full (sources, g_object_unref); + if (!subtasks_added) + on_all_subtasks_done (task); +} - g_debug ("%s EDS get_appointments returning %d appointments", G_STRLOC, g_slist_length (data.appointments)); - g_hash_table_destroy (data.added); - return data.appointments; +static GSList * +my_get_appointments_finish (IndicatorDatetimePlanner * self G_GNUC_UNUSED, + GAsyncResult * res, + GError ** error) +{ + return g_task_propagate_pointer (G_TASK(res), error); } gboolean my_is_configured (IndicatorDatetimePlanner * planner) { - GList * sources; - gboolean have_sources; IndicatorDatetimePlannerEds * self; /* confirm that it's installed... */ @@ -238,10 +285,7 @@ my_is_configured (IndicatorDatetimePlanner * planner) /* see if there are any calendar sources */ self = INDICATOR_DATETIME_PLANNER_EDS (planner); - sources = e_source_registry_list_sources (self->priv->source_registry, E_SOURCE_EXTENSION_CALENDAR); - have_sources = sources != NULL; - g_list_free_full (sources, g_object_unref); - return have_sources; + return self->priv->sources != NULL; } static void @@ -279,6 +323,148 @@ my_activate_time (IndicatorDatetimePlanner * self G_GNUC_UNUSED, } /*** +**** Source / Client Wrangling +***/ + +static void +on_client_connected (GObject * unused G_GNUC_UNUSED, + GAsyncResult * res, + gpointer gself) +{ + GError * error; + EClient * client; + + error = NULL; + client = e_cal_client_connect_finish (res, &error); + if (error != NULL) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("indicator-datetime cannot connect to EDS source: %s", error->message); + + g_error_free (error); + } + else + { + /* we've got a new connected ECalClient, so store it & notify clients */ + + g_object_set_qdata_full (G_OBJECT(e_client_get_source(client)), + source_client_quark(), + client, + g_object_unref); + + indicator_datetime_planner_emit_appointments_changed (gself); + } +} + +static void +on_source_enabled (ESourceRegistry * registry G_GNUC_UNUSED, + ESource * source, + gpointer gself) +{ + IndicatorDatetimePlannerEds * self = INDICATOR_DATETIME_PLANNER_EDS (gself); + priv_t * p = self->priv; + + e_cal_client_connect (source, + E_CAL_CLIENT_SOURCE_TYPE_EVENTS, + p->cancellable, + on_client_connected, + self); +} + +static void +on_source_added (ESourceRegistry * registry, + ESource * source, + gpointer gself) +{ + IndicatorDatetimePlannerEds * self = INDICATOR_DATETIME_PLANNER_EDS (gself); + priv_t * p = self->priv; + + p->sources = g_slist_prepend (p->sources, g_object_ref(source)); + + if (e_source_get_enabled (source)) + on_source_enabled (registry, source, gself); +} + +static void +on_source_disabled (ESourceRegistry * registry G_GNUC_UNUSED, + ESource * source, + gpointer gself) +{ + ECalClient * client; + + /* If this source has a connected ECalClient, remove it & notify clients */ + if ((client = g_object_steal_qdata (G_OBJECT(source), source_client_quark()))) + { + g_object_unref (client); + indicator_datetime_planner_emit_appointments_changed (gself); + } +} + +static void +on_source_removed (ESourceRegistry * registry, + ESource * source, + gpointer gself) +{ + IndicatorDatetimePlannerEds * self = INDICATOR_DATETIME_PLANNER_EDS (gself); + priv_t * p = self->priv; + + on_source_disabled (registry, source, gself); + + p->sources = g_slist_remove (p->sources, source); + g_object_unref (source); +} + +static void +on_source_changed (ESourceRegistry * registry G_GNUC_UNUSED, + ESource * source G_GNUC_UNUSED, + gpointer gself) +{ + indicator_datetime_planner_emit_appointments_changed (gself); +} + +static void +on_source_registry_ready (GObject * source_object G_GNUC_UNUSED, + GAsyncResult * res, + gpointer gself) +{ + GError * error; + ESourceRegistry * r; + + error = NULL; + r = e_source_registry_new_finish (res, &error); + if (error != NULL) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("indicator-datetime cannot show EDS appointments: %s", error->message); + + g_error_free (error); + } + else + { + IndicatorDatetimePlannerEds * self; + priv_t * p; + GList * l; + GList * sources; + + self = INDICATOR_DATETIME_PLANNER_EDS (gself); + p = self->priv; + + g_signal_connect (r, "source-added", G_CALLBACK(on_source_added), self); + g_signal_connect (r, "source-removed", G_CALLBACK(on_source_removed), self); + g_signal_connect (r, "source-changed", G_CALLBACK(on_source_changed), self); + g_signal_connect (r, "source-disabled", G_CALLBACK(on_source_disabled), self); + g_signal_connect (r, "source-enabled", G_CALLBACK(on_source_enabled), self); + + p->source_registry = r; + + sources = e_source_registry_list_sources (r, E_SOURCE_EXTENSION_CALENDAR); + for (l=sources; l!=NULL; l=l->next) + on_source_added (r, l->data, self); + g_list_free_full (sources, g_object_unref); + } +} + +/*** **** GObject virtual funcs ***/ @@ -288,6 +474,12 @@ my_dispose (GObject * o) IndicatorDatetimePlannerEds * self = INDICATOR_DATETIME_PLANNER_EDS (o); priv_t * p = self->priv; + if (p->cancellable != NULL) + { + g_cancellable_cancel (p->cancellable); + g_clear_object (&p->cancellable); + } + if (p->source_registry != NULL) { g_signal_handlers_disconnect_by_func (p->source_registry, @@ -301,7 +493,7 @@ my_dispose (GObject * o) } /*** -**** Insantiation +**** Instantiation ***/ static void @@ -318,6 +510,7 @@ indicator_datetime_planner_eds_class_init (IndicatorDatetimePlannerEdsClass * kl planner_class->activate = my_activate; planner_class->activate_time = my_activate_time; planner_class->get_appointments = my_get_appointments; + planner_class->get_appointments_finish = my_get_appointments_finish; g_type_class_add_private (klass, sizeof (IndicatorDatetimePlannerEdsPriv)); } @@ -326,7 +519,6 @@ static void indicator_datetime_planner_eds_init (IndicatorDatetimePlannerEds * self) { priv_t * p; - GError * err; p = G_TYPE_INSTANCE_GET_PRIVATE (self, INDICATOR_TYPE_DATETIME_PLANNER_EDS, @@ -334,22 +526,11 @@ indicator_datetime_planner_eds_init (IndicatorDatetimePlannerEds * self) self->priv = p; - err = 0; - p->source_registry = e_source_registry_new_sync (NULL, &err); - if (err != NULL) - { - g_warning ("indicator-datetime cannot show EDS appointments: %s", err->message); - g_error_free (err); - } - else - { - gpointer o = p->source_registry; - g_signal_connect_swapped (o, "source-added", G_CALLBACK(indicator_datetime_planner_emit_appointments_changed), self); - g_signal_connect_swapped (o, "source-removed", G_CALLBACK(indicator_datetime_planner_emit_appointments_changed), self); - g_signal_connect_swapped (o, "source-changed", G_CALLBACK(indicator_datetime_planner_emit_appointments_changed), self); - g_signal_connect_swapped (o, "source-disabled", G_CALLBACK(indicator_datetime_planner_emit_appointments_changed), self); - g_signal_connect_swapped (o, "source-enabled", G_CALLBACK(indicator_datetime_planner_emit_appointments_changed), self); - } + p->cancellable = g_cancellable_new (); + + e_source_registry_new (p->cancellable, + on_source_registry_ready, + self); } /*** diff --git a/src/planner.c b/src/planner.c index 6cbf80c..17cc55b 100644 --- a/src/planner.c +++ b/src/planner.c @@ -178,19 +178,46 @@ compare_appointments_by_start_time (gconstpointer ga, gconstpointer gb) return g_date_time_compare (a->begin, b->begin); } +void +indicator_datetime_planner_get_appointments (IndicatorDatetimePlanner * self, + GDateTime * begin, + GDateTime * end, + GAsyncReadyCallback callback, + gpointer user_data) +{ + IndicatorDatetimePlannerClass * klass; + + g_return_if_fail (INDICATOR_IS_DATETIME_PLANNER (self)); + + klass = INDICATOR_DATETIME_PLANNER_GET_CLASS (self); + g_return_if_fail (klass->get_appointments != NULL); + klass->get_appointments (self, begin, end, callback, user_data); +} + GSList * -indicator_datetime_planner_get_appointments (IndicatorDatetimePlanner * self, GDateTime * begin, GDateTime * end) +indicator_datetime_planner_get_appointments_finish (IndicatorDatetimePlanner * self, + GAsyncResult * res, + GError ** error) { + IndicatorDatetimePlannerClass * klass; GSList * appointments; g_return_val_if_fail (INDICATOR_IS_DATETIME_PLANNER (self), NULL); g_return_val_if_fail (begin != NULL, NULL); g_return_val_if_fail (end != NULL, NULL); - appointments = INDICATOR_DATETIME_PLANNER_GET_CLASS (self)->get_appointments (self, begin, end); + klass = INDICATOR_DATETIME_PLANNER_GET_CLASS (self); + g_return_val_if_fail (klass->get_appointments_finish != NULL, NULL); + appointments = klass->get_appointments_finish (self, res, error); return g_slist_sort (appointments, compare_appointments_by_start_time); } +void +indicator_datetime_planner_free_appointments (GSList * l) +{ + g_slist_free_full (l, (GDestroyNotify)indicator_datetime_appt_free); +} + gboolean indicator_datetime_planner_is_configured (IndicatorDatetimePlanner * self) { diff --git a/src/planner.h b/src/planner.h index f6148c6..206bfe5 100644 --- a/src/planner.h +++ b/src/planner.h @@ -22,6 +22,7 @@ #include <glib.h> #include <glib-object.h> /* parent class */ +#include <gio/gio.h> G_BEGIN_DECLS @@ -70,7 +71,16 @@ struct _IndicatorDatetimePlannerClass /* virtual functions */ - GSList* (*get_appointments) (IndicatorDatetimePlanner * self, GDateTime * begin, GDateTime * end); + void (*get_appointments) (IndicatorDatetimePlanner * self, + GDateTime * begin, + GDateTime * end, + GAsyncReadyCallback callback, + gpointer user_data); + + GSList* (*get_appointments_finish) (IndicatorDatetimePlanner * self, + GAsyncResult * res, + GError ** error); + gboolean (*is_configured) (IndicatorDatetimePlanner * self); void (*activate) (IndicatorDatetimePlanner * self); @@ -85,17 +95,33 @@ void indicator_datetime_appt_free (struct IndicatorDatetimeAppt * appt); /** * Get a list of appointments, sorted by start time. + */ +void indicator_datetime_planner_get_appointments (IndicatorDatetimePlanner * self, + GDateTime * begin, + GDateTime * end, + GAsyncReadyCallback callback, + gpointer user_data); + +/** + * Finishes the async call begun with indicator_datetime_planner_get_appointments() * - * An easy way to free the list properly in one step is as follows: - * - * g_slist_free_full (list, (GDestroyNotify)indicator_datetime_appt_free); - * + * To free the list properly, use indicator_datetime_planner_free_appointments() * * Return value: (element-type IndicatorDatetimeAppt) * (transfer full): * list of appointments */ -GSList * indicator_datetime_planner_get_appointments (IndicatorDatetimePlanner * self, GDateTime * begin, GDateTime * end); +GSList * indicator_datetime_planner_get_appointments_finish (IndicatorDatetimePlanner * self, + GAsyncResult * res, + GError ** error); + +/** + * Convenience function for freeing a GSList of IndicatorDatetimeAppt. + * + * Equivalent to g_slist_free_full (list, (GDestroyNotify)indicator_datetime_appt_free); + */ +void indicator_datetime_planner_free_appointments (GSList *); + /** * Returns false if the planner's backend is not configured. diff --git a/src/service.c b/src/service.c index c1f8752..c46beeb 100644 --- a/src/service.c +++ b/src/service.c @@ -118,6 +118,15 @@ struct _IndicatorDatetimeServicePrivate GSimpleAction * calendar_action; GDBusProxy * login1_manager; + + /* all the appointments in the selected calendar_date's month. + Used when populating the 'appointment-days' entry in + create_calendar_state() */ + GSList * calendar_appointments; + + /* appointments over the next few weeks. + Used when building SECTION_APPOINTMENTS */ + GSList * upcoming_appointments; }; typedef IndicatorDatetimeServicePrivate priv_t; @@ -569,38 +578,6 @@ get_calendar_date (IndicatorDatetimeService * self) return date; } -static GSList * -get_all_appointments_this_month (IndicatorDatetimeService * self) -{ - GSList * appointments = NULL; - priv_t * p = self->priv; - - if (p->planner != NULL) - { - GDateTime * calendar_date = NULL; - GDateTime * begin = NULL; - GDateTime * end = NULL; - int y, m, d; - - calendar_date = get_calendar_date (self); - g_date_time_get_ymd (calendar_date, &y, &m, &d); - begin = g_date_time_new_local (y, m, 1, - 0, 0, 0.1); - end = g_date_time_new_local (y, m, g_date_get_days_in_month(m,y), - 23, 59, 59.9); - - appointments = indicator_datetime_planner_get_appointments (p->planner, - begin, - end); - - g_date_time_unref (end); - g_date_time_unref (begin); - g_date_time_unref (calendar_date); - } - - return appointments; -} - static GVariant * create_calendar_state (IndicatorDatetimeService * self) { @@ -611,15 +588,13 @@ create_calendar_state (IndicatorDatetimeService * self) GVariantBuilder day_builder; GDateTime * date; GSList * l; - GSList * appts; gboolean b; priv_t * p = self->priv; g_variant_builder_init (&dict_builder, G_VARIANT_TYPE_DICTIONARY); key = "appointment-days"; - appts = get_all_appointments_this_month (self); - for (l=appts; l!=NULL; l=l->next) + for (l=p->calendar_appointments; l!=NULL; l=l->next) { const struct IndicatorDatetimeAppt * appt = l->data; days[g_date_time_get_day_of_month (appt->begin)] = TRUE; @@ -630,7 +605,6 @@ create_calendar_state (IndicatorDatetimeService * self) g_variant_builder_add (&day_builder, "i", i); g_variant_builder_add (&dict_builder, "{sv}", key, g_variant_builder_end (&day_builder)); - g_slist_free_full (appts, (GDestroyNotify)indicator_datetime_appt_free); key = "calendar-day"; date = get_calendar_date (self); @@ -726,38 +700,6 @@ create_phone_calendar_section (IndicatorDatetimeService * self) **** ***/ -/* gets the next MAX_APPTS appointments */ -static GSList * -get_upcoming_appointments (IndicatorDatetimeService * self) -{ - const int MAX_APPTS = 5; - GSList * l; - GSList * appts = NULL; - priv_t * p = self->priv; - - if (p->planner != NULL) - { - GDateTime * begin = get_calendar_date (self); - GDateTime * end = g_date_time_add_months (begin, 1); - - appts = indicator_datetime_planner_get_appointments (p->planner, - begin, - end); - - g_date_time_unref (end); - g_date_time_unref (begin); - } - - /* truncate at MAX_APPTS */ - if ((l = g_slist_nth (appts, MAX_APPTS-1))) - { - g_slist_free_full (l->next, (GDestroyNotify)indicator_datetime_appt_free); - l->next = NULL; - } - - return appts; -} - static gboolean service_has_alarms (IndicatorDatetimeService * self) { @@ -765,7 +707,7 @@ service_has_alarms (IndicatorDatetimeService * self) GSList * appts; GSList * l; - appts = get_upcoming_appointments (self); + appts = self->priv->upcoming_appointments; for (l=appts; l!=NULL; l=l->next) { struct IndicatorDatetimeAppt * appt = l->data; @@ -773,7 +715,6 @@ service_has_alarms (IndicatorDatetimeService * self) break; } - g_slist_free_full (appts, (GDestroyNotify)indicator_datetime_appt_free); return has_alarms; } @@ -809,13 +750,15 @@ get_appointment_time_format (struct IndicatorDatetimeAppt * appt, static void add_appointments (IndicatorDatetimeService * self, GMenu * menu, gboolean terse) { + const int MAX_APPTS = 5; GDateTime * now = indicator_datetime_service_get_localtime (self); GSList * appts; GSList * l; + int i; /* build appointment menuitems */ - appts = get_upcoming_appointments (self); - for (l=appts; l!=NULL; l=l->next) + appts = self->priv->upcoming_appointments; + for (l=appts, i=0; l!=NULL && i<MAX_APPTS; l=l->next, i++) { struct IndicatorDatetimeAppt * appt = l->data; char * fmt = get_appointment_time_format (appt, now, terse); @@ -824,7 +767,7 @@ add_appointments (IndicatorDatetimeService * self, GMenu * menu, gboolean terse) menu_item = g_menu_item_new (appt->summary, NULL); - if (!appt->has_alarms) + if (appt->color && !appt->has_alarms) g_menu_item_set_attribute (menu_item, "x-canonical-color", "s", appt->color); @@ -845,7 +788,6 @@ add_appointments (IndicatorDatetimeService * self, GMenu * menu, gboolean terse) /* cleanup */ g_date_time_unref (now); - g_slist_free_full (appts, (GDestroyNotify)indicator_datetime_appt_free); } static GMenuModel * @@ -966,7 +908,7 @@ time_location_free (struct TimeLocation * loc) g_date_time_unref (loc->local_time); g_free (loc->name); g_free (loc->zone); - g_free (loc); + g_slice_free (struct TimeLocation, loc); } static struct TimeLocation* @@ -974,7 +916,7 @@ time_location_new (const char * zone, const char * name, gboolean visible) { - struct TimeLocation * loc = g_new (struct TimeLocation, 1); + struct TimeLocation * loc = g_slice_new (struct TimeLocation); GTimeZone * tz = g_time_zone_new (zone); loc->zone = g_strdup (zone); loc->name = g_strdup (name); @@ -1140,7 +1082,7 @@ setlocation_data_free (struct setlocation_data * data) { g_free (data->timezone_id); g_free (data->name); - g_free (data); + g_slice_free (struct setlocation_data, data); } static void @@ -1224,7 +1166,7 @@ indicator_datetime_service_set_location (IndicatorDatetimeService * self, g_return_if_fail (name && *name); g_return_if_fail (timezone_id && *timezone_id); - data = g_new0 (struct setlocation_data, 1); + data = g_slice_new0 (struct setlocation_data); data->timezone_id = g_strdup (timezone_id); data->name = g_strdup (name); data->service = self; @@ -1604,6 +1546,133 @@ on_login1_manager_proxy_ready (GObject * object G_GNUC_UNUSED, } /*** +**** Appointments +***/ + +static void +set_calendar_appointments (IndicatorDatetimeService * self, + GSList * appointments) +{ + priv_t * p = self->priv; + + /* repopulate the list */ + indicator_datetime_planner_free_appointments (p->calendar_appointments); + p->calendar_appointments = appointments; + + /* sync the menus/actions */ + update_calendar_action_state (self); + rebuild_calendar_section_soon (self); +} + +static void +on_calendar_appointments_ready (GObject * source, + GAsyncResult * res, + gpointer self) +{ + IndicatorDatetimePlanner * planner; + GError * error; + GSList * appointments; + + planner = INDICATOR_DATETIME_PLANNER (source); + error = NULL; + appointments = indicator_datetime_planner_get_appointments_finish (planner, + res, + &error); + + if (error != NULL) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("can't get this month's appointments: %s", error->message); + + g_error_free (error); + } + else + { + set_calendar_appointments (INDICATOR_DATETIME_SERVICE (self), + appointments); + } +} + +static void +set_upcoming_appointments (IndicatorDatetimeService * self, + GSList * appointments) +{ + priv_t * p = self->priv; + + /* repopulate the list */ + indicator_datetime_planner_free_appointments (p->upcoming_appointments); + p->upcoming_appointments = appointments; + + /* sync the menus/actions */ + rebuild_appointments_section_soon (self); +} + +static void +on_upcoming_appointments_ready (GObject * source, + GAsyncResult * res, + gpointer self) +{ + IndicatorDatetimePlanner * planner; + GError * error; + GSList * appointments; + + planner = INDICATOR_DATETIME_PLANNER (source); + error = NULL; + appointments = indicator_datetime_planner_get_appointments_finish (planner, + res, + &error); + + if (error != NULL) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("can't get upcoming appointments: %s", error->message); + + g_error_free (error); + } + else + { + set_upcoming_appointments (INDICATOR_DATETIME_SERVICE (self), + appointments); + } +} + +static void +update_appointment_lists (IndicatorDatetimeService * self) +{ + IndicatorDatetimePlanner * planner; + GDateTime * calendar_date; + GDateTime * begin; + GDateTime * end; + int y, m, d; + + planner = self->priv->planner; + calendar_date = get_calendar_date (self); + + /* get all the appointments in the calendar month */ + g_date_time_get_ymd (calendar_date, &y, &m, &d); + begin = g_date_time_new_local (y, m, 1, 0, 0, 0); + end = g_date_time_new_local (y, m, g_date_get_days_in_month(m,y), 23, 59, 0); + if (begin && end) + indicator_datetime_planner_get_appointments (planner, begin, end, + on_calendar_appointments_ready, + self); + g_clear_pointer (&begin, g_date_time_unref); + g_clear_pointer (&end, g_date_time_unref); + + /* get the upcoming appointments */ + begin = g_date_time_ref (calendar_date); + end = g_date_time_add_months (begin, 1); + if (begin && end) + indicator_datetime_planner_get_appointments (planner, begin, end, + on_upcoming_appointments_ready, + self); + g_clear_pointer (&begin, g_date_time_unref); + g_clear_pointer (&end, g_date_time_unref); + g_clear_pointer (&calendar_date, g_date_time_unref); +} + + +/*** **** GDBus ***/ @@ -1642,9 +1711,6 @@ on_bus_acquired (GDBusConnection * connection, char * path = g_strdup_printf ("%s/%s", BUS_PATH, menu_names[i]); struct ProfileMenuInfo * menu = &p->menus[i]; - if (menu->menu == NULL) - create_menu (self, i); - if ((id = g_dbus_connection_export_menu_model (connection, path, G_MENU_MODEL (menu->menu), @@ -1735,6 +1801,8 @@ my_dispose (GObject * o) g_signal_handlers_disconnect_by_data (p->planner, self); g_clear_object (&p->planner); } + g_clear_pointer (&p->upcoming_appointments, indicator_datetime_planner_free_appointments); + g_clear_pointer (&p->calendar_appointments, indicator_datetime_planner_free_appointments); if (p->login1_manager != NULL) { @@ -1758,7 +1826,6 @@ my_dispose (GObject * o) for (i=0; i<N_PROFILES; ++i) g_clear_object (&p->menus[i].menu); - g_clear_object (&p->planner); g_clear_object (&p->calendar_action); g_clear_object (&p->desktop_header_action); g_clear_object (&p->phone_header_action); @@ -1841,7 +1908,7 @@ indicator_datetime_service_init (IndicatorDatetimeService * self) p->planner = indicator_datetime_planner_eds_new (); g_signal_connect_swapped (p->planner, "appointments-changed", - G_CALLBACK(rebuild_calendar_section_soon), self); + G_CALLBACK(update_appointment_lists), self); /*** @@ -1913,6 +1980,9 @@ indicator_datetime_service_init (IndicatorDatetimeService * self) on_local_time_jumped (self); + for (i=0; i<N_PROFILES; ++i) + create_menu (self, i); + g_string_free (gstr, TRUE); } @@ -1972,8 +2042,5 @@ indicator_datetime_service_set_calendar_date (IndicatorDatetimeService * self, /* sync the menuitems and action states */ if (dirty) - { - update_calendar_action_state (self); - rebuild_appointments_section_soon (self); - } + update_appointment_lists (self); } diff --git a/src/timezone-geoclue.c b/src/timezone-geoclue.c index 239ac50..f7dcf5c 100644 --- a/src/timezone-geoclue.c +++ b/src/timezone-geoclue.c @@ -77,6 +77,18 @@ on_address_changed (GeoclueAddress * address G_GNUC_UNUSED, } } +/* The signal doesn't have the parameter for an error, so it ends up needing + a NULL inserted. */ +static void +on_address_changed_sig (GeoclueAddress * address G_GNUC_UNUSED, + int timestamp G_GNUC_UNUSED, + GHashTable * addy_data, + GeoclueAccuracy * accuracy G_GNUC_UNUSED, + gpointer gself) +{ + return on_address_changed(address, timestamp, addy_data, accuracy, NULL, gself); +} + static void on_address_created (GeoclueMasterClient * master G_GNUC_UNUSED, GeoclueAddress * address, @@ -95,7 +107,7 @@ on_address_created (GeoclueMasterClient * master G_GNUC_UNUSED, p->address = g_object_ref (address); geoclue_address_get_address_async (address, on_address_changed, gself); - g_signal_connect (address, "address-changed", G_CALLBACK(on_address_changed), gself); + g_signal_connect (address, "address-changed", G_CALLBACK(on_address_changed_sig), gself); } } @@ -161,7 +173,7 @@ geo_stop (IndicatorDatetimeTimezoneGeoclue * self) if (p->address != NULL) { - g_signal_handlers_disconnect_by_func (p->address, on_address_changed, self); + g_signal_handlers_disconnect_by_func (p->address, on_address_changed_sig, self); g_clear_object (&p->address); } |