From 5485aef44178391f822edbdee1560bdc36f11501 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 8 Oct 2013 20:42:16 -0500 Subject: add a timer to test periodically to see if we've reached an EDS alarm --- src/planner.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/planner.h b/src/planner.h index 206bfe5..adc820e 100644 --- a/src/planner.h +++ b/src/planner.h @@ -42,6 +42,7 @@ struct IndicatorDatetimeAppt { char * color; char * summary; + char * url; GDateTime * begin; GDateTime * end; gboolean is_event; -- cgit v1.2.3 From 414c9ee4a5d04c7d8b1aa893ba68936c3107430b Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 8 Oct 2013 20:53:10 -0500 Subject: add a timer to periodically check to see if EDS alarms have been reached. --- src/service.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) (limited to 'src') diff --git a/src/service.c b/src/service.c index e8d4764..1123c51 100644 --- a/src/service.c +++ b/src/service.c @@ -107,6 +107,7 @@ struct _IndicatorDatetimeServicePrivate guint header_timer; guint timezone_timer; + guint alarm_timer; /* Which year/month to show in the calendar, and which day should get the cursor. @@ -376,6 +377,96 @@ start_header_timer (IndicatorDatetimeService * self) g_date_time_unref (now); } +/*** +**** +***/ + +static void start_alarm_timer (IndicatorDatetimeService * self); + +static gboolean +datetimes_have_the_same_minute (GDateTime * a, GDateTime * b) +{ + int ay, am, ad; + int by, bm, bd; + + g_date_time_get_ymd (a, &ay, &am, &ad); + g_date_time_get_ymd (b, &by, &bm, &bd); + + return (ay == by) && + (am == bm) && + (ad == ad) && + (g_date_time_get_hour (a) == g_date_time_get_hour (b)) && + (g_date_time_get_minute (a) == g_date_time_get_minute (b)); +} + +/* This is called on the minute, every minute. + We check for alarms that start at the current time. + If we find any, we dispatch the URL associated with them. */ +static void +dispatch_alarm_urls (IndicatorDatetimeService * self) +{ + GDateTime * now = indicator_datetime_service_get_localtime (self); + GSList * l; + + for (l=self->priv->upcoming_appointments; l!=NULL; l=l->next) + { + const struct IndicatorDatetimeAppt * appt = l->data; + + if ((appt->has_alarms) && + (appt->url != NULL) && + (g_str_has_prefix (appt->url, "alarm:///")) && + (datetimes_have_the_same_minute (now, appt->begin))) + { + gchar * str = g_date_time_format (appt->begin, "%F %H:%M"); + g_debug ("at %s, dispatching url \"%s\" for appointment \"%s\"", str, appt->url, appt->summary); + url_dispatch_send (appt->url, NULL, NULL); + g_free (str); + } + } + + g_date_time_unref (now); +} + +static gboolean +on_alarm_timer (gpointer self) +{ + dispatch_alarm_urls (self); + + /* Restarting the timer to recalculate the interval. This helps us to hit + our marks despite clock skew, suspend+resume, leap seconds, etc */ + start_alarm_timer (self); + return G_SOURCE_REMOVE; +} + +static void +start_alarm_timer (IndicatorDatetimeService * self) +{ + priv_t * p; + GDateTime * now; + guint interval_msec; + + p = self->priv; + + indicator_clear_timer (&p->alarm_timer); + + now = indicator_datetime_service_get_localtime (self); + interval_msec = calculate_milliseconds_until_next_minute (now); + interval_msec += 50; /* add a small margin to ensure the callback + fires /after/ next is reached */ + + p->alarm_timer = g_timeout_add_full (G_PRIORITY_HIGH, + interval_msec, + on_alarm_timer, + self, + NULL); + + g_date_time_unref (now); +} + +/*** +**** +***/ + /** * General purpose handler for rebuilding sections and restarting their timers * when time jumps for whatever reason: @@ -1782,6 +1873,7 @@ my_dispose (GObject * o) indicator_clear_timer (&p->rebuild_id); indicator_clear_timer (&p->timezone_timer); indicator_clear_timer (&p->header_timer); + indicator_clear_timer (&p->alarm_timer); if (p->settings != NULL) { @@ -1948,6 +2040,8 @@ indicator_datetime_service_init (IndicatorDatetimeService * self) on_local_time_jumped (self); + start_alarm_timer (self); + for (i=0; i Date: Tue, 8 Oct 2013 20:53:41 -0500 Subject: add a uri-searching subtask whenever we find an appointment --- src/planner-eds.c | 198 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 165 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/planner-eds.c b/src/planner-eds.c index f121a32..dd41428 100644 --- a/src/planner-eds.c +++ b/src/planner-eds.c @@ -54,16 +54,23 @@ indicator_datetime_appt_free (struct IndicatorDatetimeAppt * appt) g_date_time_unref (appt->begin); g_free (appt->color); g_free (appt->summary); + g_free (appt->url); g_slice_free (struct IndicatorDatetimeAppt, appt); } } /*** -**** my_get_appointments() helpers +**** +**** my_get_appointments() helpers +**** ***/ -struct get_appointments_task_data +/* whole-task data that all the subtasks can see */ +struct appointment_task_data { + /* a ref to the planner's cancellable */ + GCancellable * cancellable; + /* how many subtasks are still running on */ int subtask_count; @@ -74,47 +81,164 @@ struct get_appointments_task_data GHashTable * added; }; +static struct appointment_task_data * +appointment_task_data_new (GCancellable * cancellable) +{ + struct appointment_task_data * data; + + data = g_slice_new0 (struct appointment_task_data); + data->added = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + data->cancellable = g_object_ref (cancellable); + return data; +} + static void -get_appointments_task_data_free (gpointer gdata) +appointment_task_data_free (gpointer gdata) { - struct get_appointments_task_data * data = gdata; + struct appointment_task_data * data = gdata; + + g_object_unref (data->cancellable); g_hash_table_unref (data->added); - g_slice_free (struct get_appointments_task_data, data); + g_slice_free (struct appointment_task_data, data); } static void -on_all_subtasks_done (GTask * task) +appointment_task_done (GTask * task) { - struct get_appointments_task_data * data = g_task_get_task_data (task); + struct appointment_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 +static void +appointment_task_decrement_subtasks (GTask * task) +{ + struct appointment_task_data * data = g_task_get_task_data (task); + + if (g_atomic_int_dec_and_test (&data->subtask_count)) + appointment_task_done (task); +} + +static void +appointment_task_increment_subtasks (GTask * task) { + struct appointment_task_data * data = g_task_get_task_data (task); + + g_atomic_int_inc (&data->subtask_count); +} + +/** +*** get-the-appointment's-uri subtasks +**/ + +struct appointment_uri_subtask_data +{ + /* The parent task */ GTask * task; - gchar * color; + /* The appointment whose uri we're looking for. + This pointer is owned by the Task and isn't reffed/unreffed by the subtask */ + struct IndicatorDatetimeAppt * appt; }; static void -on_subtask_done (gpointer gsubdata) +appointment_uri_subtask_done (struct appointment_uri_subtask_data * subdata) +{ + GTask * task = subdata->task; + + /* free the subtask data */ + g_slice_free (struct appointment_uri_subtask_data, subdata); + + appointment_task_decrement_subtasks (task); +} + +static struct appointment_uri_subtask_data * +appointment_uri_subtask_data_new (GTask * task, struct IndicatorDatetimeAppt * appt) +{ + struct appointment_uri_subtask_data * subdata; + + appointment_task_increment_subtasks (task); + + subdata = g_slice_new0 (struct appointment_uri_subtask_data); + subdata->task = task; + subdata->appt = appt; + return subdata; +} + +static void +on_appointment_uris_ready (GObject * client, + GAsyncResult * res, + gpointer gsubdata) +{ + GSList * uris; + GError * error; + struct appointment_uri_subtask_data * subdata = gsubdata; + + uris = NULL; + error = NULL; + e_cal_client_get_attachment_uris_finish (E_CAL_CLIENT(client), res, &uris, &error); + if (error != NULL) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Error getting appointment uris: %s", error->message); + + g_error_free (error); + } + else if (uris != NULL) + { + struct IndicatorDatetimeAppt * appt = subdata->appt; + appt->url = g_strdup (uris->data); /* copy the first URL */ + g_debug ("found url '%s' for appointment '%s'", appt->url, appt->summary); + e_client_util_free_string_slist (uris); + } + + appointment_uri_subtask_done (subdata); +} + +/** +*** enumerate-the-components subtasks +**/ + +/* data struct for the enumerate-components subtask */ +struct appointment_component_subtask_data { - struct get_appointments_subtask_data * subdata; + /* The parent task */ GTask * task; - struct get_appointments_task_data * data; - subdata = gsubdata; - task = subdata->task; + /* The client we're walking through. The subtask owns a ref to this */ + ECalClient * client; + + /* The appointment's color coding. The subtask owns this string */ + gchar * color; +}; + +static void +on_appointment_component_subtask_done (gpointer gsubdata) +{ + struct appointment_component_subtask_data * subdata = gsubdata; + GTask * task = subdata->task; /* free the subtask data */ g_free (subdata->color); - g_slice_free (struct get_appointments_subtask_data, subdata); + g_object_unref (subdata->client); + g_slice_free (struct appointment_component_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); + appointment_task_decrement_subtasks (task); +} + +static struct appointment_component_subtask_data * +appointment_component_subtask_data_new (GTask * task, ECalClient * client, const gchar * color) +{ + struct appointment_component_subtask_data * subdata; + + appointment_task_increment_subtasks (task); + + subdata = g_slice_new0 (struct appointment_component_subtask_data); + subdata->task = task; + subdata->client = g_object_ref (client); + subdata->color = g_strdup (color); + return subdata; } static gboolean @@ -124,8 +248,8 @@ my_get_appointments_foreach (ECalComponent * component, gpointer gsubdata) { const ECalComponentVType vtype = e_cal_component_get_vtype (component); - struct get_appointments_subtask_data * subdata = gsubdata; - struct get_appointments_task_data * data = g_task_get_task_data (subdata->task); + struct appointment_component_subtask_data * subdata = gsubdata; + struct appointment_task_data * data = g_task_get_task_data (subdata->task); if ((vtype == E_CAL_COMPONENT_EVENT) || (vtype == E_CAL_COMPONENT_TODO)) { @@ -145,6 +269,7 @@ my_get_appointments_foreach (ECalComponent * component, GSList * recur_list; ECalComponentText text; struct IndicatorDatetimeAppt * appt; + struct appointment_uri_subtask_data * uri_subdata; appt = g_slice_new0 (struct IndicatorDatetimeAppt); @@ -176,6 +301,15 @@ my_get_appointments_foreach (ECalComponent * component, data->appointments = g_slist_prepend (data->appointments, appt); g_hash_table_add (data->added, g_strdup(uid)); + + /* start a new subtask to get the associated URIs */ + uri_subdata = appointment_uri_subtask_data_new (subdata->task, appt); + e_cal_client_get_attachment_uris (subdata->client, + uid, + NULL, + data->cancellable, + on_appointment_uris_ready, + uri_subdata); } } @@ -197,7 +331,6 @@ my_get_appointments (IndicatorDatetimePlanner * planner, priv_t * p; const char * str; icaltimezone * default_timezone; - 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; @@ -223,17 +356,18 @@ my_get_appointments (IndicatorDatetimePlanner * planner, *** walk through the sources to build the appointment list **/ - 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); + g_task_set_task_data (task, + appointment_task_data_new (p->cancellable), + appointment_task_data_free); subtasks_added = FALSE; for (l=p->sources; l!=NULL; l=l->next) { ESource * source; ECalClient * client; - struct get_appointments_subtask_data * subdata; + const char * color; + struct appointment_component_subtask_data * subdata; source = l->data; client = g_object_get_qdata (l->data, source_client_quark()); @@ -243,11 +377,9 @@ my_get_appointments (IndicatorDatetimePlanner * planner, 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); + /* start a new subtask to enumerate all the components in this client. */ + color = e_source_selectable_get_color (e_source_get_extension (source, E_SOURCE_EXTENSION_CALENDAR)); + subdata = appointment_component_subtask_data_new (task, client, color); subtasks_added = TRUE; e_cal_client_generate_instances (client, begin, @@ -255,11 +387,11 @@ my_get_appointments (IndicatorDatetimePlanner * planner, p->cancellable, my_get_appointments_foreach, subdata, - on_subtask_done); + on_appointment_component_subtask_done); } if (!subtasks_added) - on_all_subtasks_done (task); + appointment_task_done (task); } static GSList * -- cgit v1.2.3 From c1a349811e64c1e8597ad4ec391d150eda163512 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 9 Oct 2013 08:21:16 -0500 Subject: in the case of recurring appointments, allow multiple entries with the same uid to be returned by get_appointments(). This is so the client can always find the timestamp of the instance that occurs next. --- src/planner-eds.c | 10 +++------- src/planner.h | 7 ++++--- 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/planner-eds.c b/src/planner-eds.c index dd41428..e5f0b43 100644 --- a/src/planner-eds.c +++ b/src/planner-eds.c @@ -55,6 +55,7 @@ indicator_datetime_appt_free (struct IndicatorDatetimeAppt * appt) g_free (appt->color); g_free (appt->summary); g_free (appt->url); + g_free (appt->uid); g_slice_free (struct IndicatorDatetimeAppt, appt); } } @@ -76,9 +77,6 @@ struct appointment_task_data /* the list of appointments to be returned */ GSList * appointments; - - /* ensure that recurring events don't get multiple IndicatorDatetimeAppts */ - GHashTable * added; }; static struct appointment_task_data * @@ -87,7 +85,6 @@ appointment_task_data_new (GCancellable * cancellable) struct appointment_task_data * data; data = g_slice_new0 (struct appointment_task_data); - data->added = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); data->cancellable = g_object_ref (cancellable); return data; } @@ -98,7 +95,7 @@ appointment_task_data_free (gpointer gdata) struct appointment_task_data * data = gdata; g_object_unref (data->cancellable); - g_hash_table_unref (data->added); + g_slice_free (struct appointment_task_data, data); } @@ -260,7 +257,6 @@ my_get_appointments_foreach (ECalComponent * component, e_cal_component_get_status (component, &status); if ((uid != NULL) && - (!g_hash_table_contains (data->added, uid)) && (status != ICAL_STATUS_COMPLETED) && (status != ICAL_STATUS_CANCELLED)) { @@ -294,13 +290,13 @@ my_get_appointments_foreach (ECalComponent * component, appt->color = g_strdup (subdata->color); appt->is_event = vtype == E_CAL_COMPONENT_EVENT; appt->summary = g_strdup (text.value); + appt->uid = g_strdup (uid); alarm_uids = e_cal_component_get_alarm_uids (component); appt->has_alarms = alarm_uids != NULL; cal_obj_uid_list_free (alarm_uids); data->appointments = g_slist_prepend (data->appointments, appt); - g_hash_table_add (data->added, g_strdup(uid)); /* start a new subtask to get the associated URIs */ uri_subdata = appointment_uri_subtask_data_new (subdata->task, appt); diff --git a/src/planner.h b/src/planner.h index adc820e..ffe8937 100644 --- a/src/planner.h +++ b/src/planner.h @@ -40,9 +40,10 @@ GType indicator_datetime_planner_get_type (void); struct IndicatorDatetimeAppt { - char * color; - char * summary; - char * url; + gchar * color; + gchar * summary; + gchar * url; + gchar * uid; GDateTime * begin; GDateTime * end; gboolean is_event; -- cgit v1.2.3 From de4e79a613c01baf566658ffb593c665f15a2e78 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 9 Oct 2013 08:22:09 -0500 Subject: instead of testing for alarms once per minute, set a timer for the next alarm occurence. --- src/service.c | 119 +++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 89 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/service.c b/src/service.c index 1123c51..07f6a51 100644 --- a/src/service.c +++ b/src/service.c @@ -381,7 +381,15 @@ start_header_timer (IndicatorDatetimeService * self) **** ***/ -static void start_alarm_timer (IndicatorDatetimeService * self); +static void set_alarm_timer (IndicatorDatetimeService * self); + +static gboolean +appointment_has_alarm_url (const struct IndicatorDatetimeAppt * appt) +{ + return (appt->has_alarms) && + (appt->url != NULL);// && + //(g_str_has_prefix (appt->url, "alarm:///")); +} static gboolean datetimes_have_the_same_minute (GDateTime * a, GDateTime * b) @@ -394,13 +402,12 @@ datetimes_have_the_same_minute (GDateTime * a, GDateTime * b) return (ay == by) && (am == bm) && - (ad == ad) && + (ad == bd) && (g_date_time_get_hour (a) == g_date_time_get_hour (b)) && (g_date_time_get_minute (a) == g_date_time_get_minute (b)); } -/* This is called on the minute, every minute. - We check for alarms that start at the current time. +/* Check for alarms that start at the current time. If we find any, we dispatch the URL associated with them. */ static void dispatch_alarm_urls (IndicatorDatetimeService * self) @@ -412,13 +419,12 @@ dispatch_alarm_urls (IndicatorDatetimeService * self) { const struct IndicatorDatetimeAppt * appt = l->data; - if ((appt->has_alarms) && - (appt->url != NULL) && - (g_str_has_prefix (appt->url, "alarm:///")) && - (datetimes_have_the_same_minute (now, appt->begin))) + if (appointment_has_alarm_url (appt) && + datetimes_have_the_same_minute (now, appt->begin)) { - gchar * str = g_date_time_format (appt->begin, "%F %H:%M"); - g_debug ("at %s, dispatching url \"%s\" for appointment \"%s\"", str, appt->url, appt->summary); + gchar * str = g_date_time_format (appt->begin, "%F %T"); + g_debug ("at %s, dispatching url \"%s\" for appointment \"%s\"", + str, appt->url, appt->summary); url_dispatch_send (appt->url, NULL, NULL); g_free (str); } @@ -427,38 +433,73 @@ dispatch_alarm_urls (IndicatorDatetimeService * self) g_date_time_unref (now); } +static void update_appointment_lists (IndicatorDatetimeService * self); + static gboolean on_alarm_timer (gpointer self) { dispatch_alarm_urls (self); - - /* Restarting the timer to recalculate the interval. This helps us to hit - our marks despite clock skew, suspend+resume, leap seconds, etc */ - start_alarm_timer (self); + + /* rebuild the alarm list asynchronously. + when it's done, set_upcoming_appointments() will update the alarm timer */ + update_appointment_lists (self); + return G_SOURCE_REMOVE; } +/* if there are upcoming alarms, set the alarm timer to the nearest one. + otherwise, unset the alarm timer. */ static void -start_alarm_timer (IndicatorDatetimeService * self) +set_alarm_timer (IndicatorDatetimeService * self) { priv_t * p; GDateTime * now; - guint interval_msec; - - p = self->priv; + GDateTime * alarm_time; + GSList * l; + p = self->priv; indicator_clear_timer (&p->alarm_timer); now = indicator_datetime_service_get_localtime (self); - interval_msec = calculate_milliseconds_until_next_minute (now); - interval_msec += 50; /* add a small margin to ensure the callback - fires /after/ next is reached */ - p->alarm_timer = g_timeout_add_full (G_PRIORITY_HIGH, - interval_msec, - on_alarm_timer, - self, - NULL); + /* find the time of the next alarm on our calendar */ + alarm_time = NULL; + for (l=p->upcoming_appointments; l!=NULL; l=l->next) + { + const struct IndicatorDatetimeAppt * appt = l->data; + + if (appointment_has_alarm_url (appt)) + if (g_date_time_compare (appt->begin, now) > 0) + if (!alarm_time || g_date_time_compare (alarm_time, appt->begin) > 0) + alarm_time = appt->begin; + } + + /* if there's an upcoming alarm, set a timer to wake up at that time */ + if (alarm_time != NULL) + { + GTimeSpan interval_msec; + gchar * str; + GDateTime * then; + + interval_msec = g_date_time_difference (alarm_time, now); + interval_msec += G_USEC_PER_SEC; /* fire a moment after alarm_time */ + interval_msec /= 1000; /* convert from usec to msec */ + + str = g_date_time_format (alarm_time, "%F %T"); + g_debug ("%s is the next alarm time", str); + g_free (str); + then = g_date_time_add_seconds (now, interval_msec/1000); + str = g_date_time_format (then, "%F %T"); + g_debug ("%s is when we'll wake up for it", str); + g_free (str); + g_date_time_unref (then); + + p->alarm_timer = g_timeout_add_full (G_PRIORITY_HIGH, + (guint) interval_msec, + on_alarm_timer, + self, + NULL); + } g_date_time_unref (now); } @@ -810,20 +851,33 @@ static void add_appointments (IndicatorDatetimeService * self, GMenu * menu, gboolean terse) { const int MAX_APPTS = 5; - GDateTime * now = indicator_datetime_service_get_localtime (self); + GDateTime * now; + GHashTable * added; GSList * appts; GSList * l; int i; + now = indicator_datetime_service_get_localtime (self); + + added = g_hash_table_new (g_str_hash, g_str_equal); + /* build appointment menuitems */ appts = self->priv->upcoming_appointments; for (l=appts, i=0; l!=NULL && inext, i++) { struct IndicatorDatetimeAppt * appt = l->data; - char * fmt = get_appointment_time_format (appt, now, self->priv->settings, terse); - const gint64 unix_time = g_date_time_to_unix (appt->begin); + char * fmt; + gint64 unix_time; GMenuItem * menu_item; + if (g_hash_table_contains (added, appt->uid)) + continue; + + g_hash_table_add (added, appt->uid); + + fmt = get_appointment_time_format (appt, now, self->priv->settings, terse); + unix_time = g_date_time_to_unix (appt->begin); + menu_item = g_menu_item_new (appt->summary, NULL); if (appt->color && !appt->has_alarms) @@ -846,6 +900,7 @@ add_appointments (IndicatorDatetimeService * self, GMenu * menu, gboolean terse) } /* cleanup */ + g_hash_table_unref (added); g_date_time_unref (now); } @@ -1661,6 +1716,10 @@ set_upcoming_appointments (IndicatorDatetimeService * self, /* sync the menus/actions */ rebuild_appointments_section_soon (self); + + /* alarm timer is keyed off of the next alarm time, + so it needs to be rebuilt when tehe appointment list changes */ + set_alarm_timer (self); } static void @@ -2040,7 +2099,7 @@ indicator_datetime_service_init (IndicatorDatetimeService * self) on_local_time_jumped (self); - start_alarm_timer (self); + set_alarm_timer (self); for (i=0; i Date: Wed, 9 Oct 2013 13:28:15 +0000 Subject: remove debugging stubs --- src/service.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/service.c b/src/service.c index 07f6a51..28ef32d 100644 --- a/src/service.c +++ b/src/service.c @@ -387,8 +387,8 @@ static gboolean appointment_has_alarm_url (const struct IndicatorDatetimeAppt * appt) { return (appt->has_alarms) && - (appt->url != NULL);// && - //(g_str_has_prefix (appt->url, "alarm:///")); + (appt->url != NULL) && + (g_str_has_prefix (appt->url, "alarm:///")); } static gboolean -- cgit v1.2.3 From 1282befc5d9629ba0daacc2099811ccf19e4ed1b Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 9 Oct 2013 11:39:36 -0500 Subject: add url activation for appointment menuitems on the phone profile. --- src/service.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/service.c b/src/service.c index 28ef32d..1de4617 100644 --- a/src/service.c +++ b/src/service.c @@ -378,7 +378,7 @@ start_header_timer (IndicatorDatetimeService * self) } /*** -**** +**** ALARMS ***/ static void set_alarm_timer (IndicatorDatetimeService * self); @@ -407,6 +407,22 @@ datetimes_have_the_same_minute (GDateTime * a, GDateTime * b) (g_date_time_get_minute (a) == g_date_time_get_minute (b)); } +static void +dispatch_alarm_url (const struct IndicatorDatetimeAppt * appt) +{ + gchar * str; + + g_return_if_fail (appt != NULL); + g_return_if_fail (appointment_has_alarm_url (appt)); + + str = g_date_time_format (appt->begin, "%F %T"); + g_debug ("dispatching url \"%s\" for appointment \"%s\", which begins at %s", + appt->url, appt->summary, str); + g_free (str); + + url_dispatch_send (appt->url, NULL, NULL); +} + /* Check for alarms that start at the current time. If we find any, we dispatch the URL associated with them. */ static void @@ -419,15 +435,8 @@ dispatch_alarm_urls (IndicatorDatetimeService * self) { const struct IndicatorDatetimeAppt * appt = l->data; - if (appointment_has_alarm_url (appt) && - datetimes_have_the_same_minute (now, appt->begin)) - { - gchar * str = g_date_time_format (appt->begin, "%F %T"); - g_debug ("at %s, dispatching url \"%s\" for appointment \"%s\"", - str, appt->url, appt->summary); - url_dispatch_send (appt->url, NULL, NULL); - g_free (str); - } + if (appointment_has_alarm_url (appt) && datetimes_have_the_same_minute (now, appt->begin)) + dispatch_alarm_url (appt); } g_date_time_unref (now); @@ -848,7 +857,7 @@ get_appointment_time_format (struct IndicatorDatetimeAppt * appt, } static void -add_appointments (IndicatorDatetimeService * self, GMenu * menu, gboolean terse) +add_appointments (IndicatorDatetimeService * self, GMenu * menu, gboolean phone) { const int MAX_APPTS = 5; GDateTime * now; @@ -875,7 +884,7 @@ add_appointments (IndicatorDatetimeService * self, GMenu * menu, gboolean terse) g_hash_table_add (added, appt->uid); - fmt = get_appointment_time_format (appt, now, self->priv->settings, terse); + fmt = get_appointment_time_format (appt, now, self->priv->settings, phone); unix_time = g_date_time_to_unix (appt->begin); menu_item = g_menu_item_new (appt->summary, NULL); @@ -891,9 +900,15 @@ add_appointments (IndicatorDatetimeService * self, GMenu * menu, gboolean terse) g_menu_item_set_attribute (menu_item, "x-canonical-type", "s", appt->has_alarms ? "com.canonical.indicator.alarm" : "com.canonical.indicator.appointment"); - g_menu_item_set_action_and_target_value (menu_item, - "indicator.activate-planner", - g_variant_new_int64 (unix_time)); + + if (phone) + g_menu_item_set_action_and_target_value (menu_item, + "indicator.activate-appointment", + g_variant_new_string (appt->uid)); + else + g_menu_item_set_action_and_target_value (menu_item, + "indicator.activate-planner", + g_variant_new_int64 (unix_time)); g_menu_append_item (menu, menu_item); g_object_unref (menu_item); g_free (fmt); @@ -1432,6 +1447,34 @@ on_phone_settings_activated (GSimpleAction * a G_GNUC_UNUSED, url_dispatch_send ("settings:///system/time-date", NULL, NULL); } +static void +on_activate_appointment (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param, + gpointer gself) +{ + priv_t * p = INDICATOR_DATETIME_SERVICE(gself)->priv; + const gchar * uid = g_variant_get_string (param, NULL); + + if (uid != NULL) + { + const struct IndicatorDatetimeAppt * appt; + GSList * l; + + /* find the appointment that matches that uid */ + for (l=p->upcoming_appointments, appt=NULL; l && !appt; l=l->next) + { + const struct IndicatorDatetimeAppt * tmp = l->data; + if (!g_strcmp0 (uid, tmp->uid)) + appt = tmp; + } + + /* if that appointment's an alarm, dispatch its url */ + g_debug ("%s: uri '%s'; matching appt is %p", G_STRFUNC, uid, appt); + if (appt && appointment_has_alarm_url (appt)) + dispatch_alarm_url (appt); + } +} + static void on_activate_planner (GSimpleAction * a G_GNUC_UNUSED, GVariant * param, @@ -1486,6 +1529,7 @@ init_gactions (IndicatorDatetimeService * self) { "activate-desktop-settings", on_desktop_settings_activated }, { "activate-phone-settings", on_phone_settings_activated }, { "activate-planner", on_activate_planner, "x", NULL }, + { "activate-appointment", on_activate_appointment, "s", NULL }, { "set-location", on_set_location, "s" } }; -- cgit v1.2.3 From 70487ccce4dbcf04f9dfb02ba50f7e88e428f14a Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 9 Oct 2013 21:02:17 -0500 Subject: move planner instantiation to main.c so that we can prepare to pass in a mock planner for testing --- src/main.c | 12 ++++-- src/service.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++---------- src/service.h | 7 +++- 3 files changed, 118 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index c75b2d7..710db66 100644 --- a/src/main.c +++ b/src/main.c @@ -25,6 +25,7 @@ #include #include +#include "planner-eds.h" #include "service.h" /*** @@ -41,23 +42,28 @@ on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop) int main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) { - GMainLoop * loop; + IndicatorDatetimePlanner * planner; IndicatorDatetimeService * service; + GMainLoop * loop; /* boilerplate i18n */ setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); textdomain (GETTEXT_PACKAGE); + /* get the planner */ + planner = indicator_datetime_planner_eds_new (); + /* run */ - service = indicator_datetime_service_new (); + service = indicator_datetime_service_new (planner); loop = g_main_loop_new (NULL, FALSE); g_signal_connect (service, INDICATOR_DATETIME_SERVICE_SIGNAL_NAME_LOST, G_CALLBACK(on_name_lost), loop); g_main_loop_run (loop); /* cleanup */ - g_clear_object (&service); g_main_loop_unref (loop); + g_object_unref (service); + g_object_unref (planner); return 0; } diff --git a/src/service.c b/src/service.c index 1de4617..57d0a7e 100644 --- a/src/service.c +++ b/src/service.c @@ -27,7 +27,6 @@ #include #include "dbus-shared.h" -#include "planner-eds.h" #include "timezone-file.h" #include "timezone-geoclue.h" #include "service.h" @@ -49,6 +48,15 @@ enum static guint signals[LAST_SIGNAL] = { 0 }; +enum +{ + PROP_0, + PROP_PLANNER, + PROP_LAST +}; + +static GParamSpec * properties[PROP_LAST] = { 0 }; + enum { SECTION_HEADER = (1<<0), @@ -1935,6 +1943,45 @@ on_name_lost (GDBusConnection * connection G_GNUC_UNUSED, **** GObject virtual functions ***/ +static void +my_get_property (GObject * o, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (o); + + switch (property_id) + { + case PROP_PLANNER: + g_value_set_object (value, self->priv->planner); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + } +} + +static void +my_set_property (GObject * o, + guint property_id, + const GValue * value, + GParamSpec * pspec) +{ + IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (o); + + switch (property_id) + { + case PROP_PLANNER: + indicator_datetime_service_set_planner (self, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + } +} + + static void my_dispose (GObject * o) { @@ -1958,13 +2005,7 @@ my_dispose (GObject * o) set_detect_location_enabled (self, FALSE); - if (p->planner != NULL) - { - 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); + indicator_datetime_service_set_planner (self, NULL); if (p->login1_manager != NULL) { @@ -2064,16 +2105,6 @@ indicator_datetime_service_init (IndicatorDatetimeService * self) p->cancellable = g_cancellable_new (); - /*** - **** Create the planner and listen for changes - ***/ - - p->planner = indicator_datetime_planner_eds_new (); - - g_signal_connect_swapped (p->planner, "appointments-changed", - G_CALLBACK(update_appointment_lists), self); - - /*** **** Create the settings object and listen for changes ***/ @@ -2155,9 +2186,12 @@ static void indicator_datetime_service_class_init (IndicatorDatetimeServiceClass * klass) { GObjectClass * object_class = G_OBJECT_CLASS (klass); + const GParamFlags flags = G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS; object_class->dispose = my_dispose; object_class->finalize = my_finalize; + object_class->get_property = my_get_property; + object_class->set_property = my_set_property; g_type_class_add_private (klass, sizeof (IndicatorDatetimeServicePrivate)); @@ -2169,6 +2203,18 @@ indicator_datetime_service_class_init (IndicatorDatetimeServiceClass * klass) NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + + /* install properties */ + + properties[PROP_0] = NULL; + + properties[PROP_PLANNER] = g_param_spec_object ("planner", + "Planner", + "The appointment provider", + INDICATOR_TYPE_DATETIME_PLANNER, + flags); + + g_object_class_install_properties (object_class, PROP_LAST, properties); } /*** @@ -2176,9 +2222,11 @@ indicator_datetime_service_class_init (IndicatorDatetimeServiceClass * klass) ***/ IndicatorDatetimeService * -indicator_datetime_service_new (void) +indicator_datetime_service_new (IndicatorDatetimePlanner * planner) { - GObject * o = g_object_new (INDICATOR_TYPE_DATETIME_SERVICE, NULL); + GObject * o = g_object_new (INDICATOR_TYPE_DATETIME_SERVICE, + "planner", planner, + NULL); return INDICATOR_DATETIME_SERVICE (o); } @@ -2209,3 +2257,38 @@ indicator_datetime_service_set_calendar_date (IndicatorDatetimeService * self, if (dirty) update_appointment_lists (self); } + +void +indicator_datetime_service_set_planner (IndicatorDatetimeService * self, + IndicatorDatetimePlanner * planner) +{ + priv_t * p; + + g_return_if_fail (INDICATOR_IS_DATETIME_SERVICE (self)); + g_return_if_fail (INDICATOR_IS_DATETIME_PLANNER (planner)); + + p = self->priv; + + /* clear the old planner & appointments */ + + if (p->planner != NULL) + { + 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); + + /* set the new planner & begin fetching appointments from it */ + + if (planner != NULL) + { + p->planner = g_object_ref (planner); + + g_signal_connect_swapped (p->planner, "appointments-changed", + G_CALLBACK(update_appointment_lists), self); + + update_appointment_lists (self); + } +} diff --git a/src/service.h b/src/service.h index b142882..25bb59a 100644 --- a/src/service.h +++ b/src/service.h @@ -22,6 +22,7 @@ #include #include +#include "planner.h" G_BEGIN_DECLS @@ -62,13 +63,17 @@ struct _IndicatorDatetimeServiceClass GType indicator_datetime_service_get_type (void); -IndicatorDatetimeService * indicator_datetime_service_new (void); +IndicatorDatetimeService * indicator_datetime_service_new (IndicatorDatetimePlanner * planner); GDateTime * indicator_datetime_service_get_localtime (IndicatorDatetimeService * service); void indicator_datetime_service_set_calendar_date (IndicatorDatetimeService * self, GDateTime * date); +void indicator_datetime_service_set_planner (IndicatorDatetimeService * self, + IndicatorDatetimePlanner * planner); + + G_END_DECLS -- cgit v1.2.3 From ba639a9fb011ad337eef8d2bd5e4bcbdca3b136a Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 9 Oct 2013 21:04:31 -0500 Subject: remove vestigal function declaration from planner-eds.h --- src/planner-eds.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/planner-eds.h b/src/planner-eds.h index a2c803a..dea9371 100644 --- a/src/planner-eds.h +++ b/src/planner-eds.h @@ -51,8 +51,6 @@ struct _IndicatorDatetimePlannerEdsClass IndicatorDatetimePlannerClass parent_class; }; -gboolean indicator_datetime_planner_eds_is_usable (void); - IndicatorDatetimePlanner * indicator_datetime_planner_eds_new (void); G_END_DECLS -- cgit v1.2.3 From bc40e6a71d5eccf0fce96807d71d2f220207259b Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 9 Oct 2013 21:06:35 -0500 Subject: move the implementation of indicator_datetime_appt_free() from planner-eds.c to planner.c --- src/planner-eds.c | 19 ------------------- src/planner.c | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/planner-eds.c b/src/planner-eds.c index e5f0b43..b188392 100644 --- a/src/planner-eds.c +++ b/src/planner-eds.c @@ -41,25 +41,6 @@ G_DEFINE_TYPE (IndicatorDatetimePlannerEds, G_DEFINE_QUARK ("source-client", source_client) -/*** -**** -***/ - -void -indicator_datetime_appt_free (struct IndicatorDatetimeAppt * appt) -{ - if (appt != NULL) - { - g_date_time_unref (appt->end); - g_date_time_unref (appt->begin); - g_free (appt->color); - g_free (appt->summary); - g_free (appt->url); - g_free (appt->uid); - g_slice_free (struct IndicatorDatetimeAppt, appt); - } -} - /*** **** **** my_get_appointments() helpers diff --git a/src/planner.c b/src/planner.c index e826c2c..9b9a77f 100644 --- a/src/planner.c +++ b/src/planner.c @@ -259,3 +259,23 @@ indicator_datetime_planner_get_timezone (IndicatorDatetimePlanner * self) return self->priv->timezone; } + +/*** +**** +***/ + +void +indicator_datetime_appt_free (struct IndicatorDatetimeAppt * appt) +{ + if (appt != NULL) + { + g_date_time_unref (appt->end); + g_date_time_unref (appt->begin); + g_free (appt->color); + g_free (appt->summary); + g_free (appt->url); + g_free (appt->uid); + g_slice_free (struct IndicatorDatetimeAppt, appt); + } +} + -- cgit v1.2.3 From c8a8c56f668f50e5cdeff5255ec74e82e3af7e32 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 9 Oct 2013 21:24:43 -0500 Subject: planner-eds's is_configured() function should be private --- src/planner-eds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/planner-eds.c b/src/planner-eds.c index b188392..876fdfc 100644 --- a/src/planner-eds.c +++ b/src/planner-eds.c @@ -379,7 +379,7 @@ my_get_appointments_finish (IndicatorDatetimePlanner * self G_GNUC_UNUSED, return g_task_propagate_pointer (G_TASK(res), error); } -gboolean +static gboolean my_is_configured (IndicatorDatetimePlanner * planner) { IndicatorDatetimePlannerEds * self; -- cgit v1.2.3 From b6b0c140f922385d947fa12dfff179a5491a1722 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 9 Oct 2013 21:31:13 -0500 Subject: add a preliminary mock planner for testing alarms/appointments isolated apart from the EDS backend --- src/Makefile.am | 2 + src/main.c | 11 +++- src/planner-mock.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/planner-mock.h | 58 +++++++++++++++++ 4 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 src/planner-mock.c create mode 100644 src/planner-mock.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 093a258..640650a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,6 +20,8 @@ libindicator_datetime_service_a_CFLAGS = \ libindicator_datetime_service_a_SOURCES = \ planner.c \ planner.h \ + planner-mock.c \ + planner-mock.h \ planner-eds.c \ planner-eds.h \ service.c \ diff --git a/src/main.c b/src/main.c index 710db66..073c876 100644 --- a/src/main.c +++ b/src/main.c @@ -26,6 +26,7 @@ #include #include "planner-eds.h" +#include "planner-mock.h" #include "service.h" /*** @@ -52,7 +53,15 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) textdomain (GETTEXT_PACKAGE); /* get the planner */ - planner = indicator_datetime_planner_eds_new (); + if (g_getenv ("INDICATOR_DATETIME_USE_FAKE_PLANNER") != NULL) + { + g_message ("Using fake appointment book for testing"); + planner = indicator_datetime_planner_mock_new (); + } + else + { + planner = indicator_datetime_planner_eds_new (); + } /* run */ service = indicator_datetime_service_new (planner); diff --git a/src/planner-mock.c b/src/planner-mock.c new file mode 100644 index 0000000..e67ad7e --- /dev/null +++ b/src/planner-mock.c @@ -0,0 +1,178 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 "config.h" + +#include "planner-mock.h" + +struct _IndicatorDatetimePlannerMockPriv +{ + gboolean is_configured; +}; + +typedef IndicatorDatetimePlannerMockPriv priv_t; + +G_DEFINE_TYPE (IndicatorDatetimePlannerMock, + indicator_datetime_planner_mock, + INDICATOR_TYPE_DATETIME_PLANNER) + +/*** +**** IndicatorDatetimePlanner virtual funcs +***/ + +static void +my_get_appointments (IndicatorDatetimePlanner * planner, + GDateTime * begin_datetime, + GDateTime * end_datetime G_GNUC_UNUSED, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask * task; + GSList * appointments; + struct IndicatorDatetimeAppt * appt; + struct IndicatorDatetimeAppt * prev; + + task = g_task_new (planner, NULL, callback, user_data); + + /** + *** Build the appointments list + **/ + + appointments = NULL; + + /* add a daily appointment that occurs at the beginning of the next minute */ + appt = g_slice_new0 (struct IndicatorDatetimeAppt); + appt->is_daily = TRUE; + appt->begin = g_date_time_add_seconds (begin_datetime, 60-g_date_time_get_seconds(begin_datetime)); + appt->end = g_date_time_add_minutes (appt->begin, 1); + appt->color = g_strdup ("#00FF00"); + appt->is_event = TRUE; + appt->summary = g_strdup ("Daily alarm"); + appt->uid = g_strdup ("this uid isn't very random."); + appt->has_alarms = TRUE; + appt->url = g_strdup ("alarm:///some-alarm-info-goes-here"); + appointments = g_slist_prepend (appointments, appt); + prev = appt; + + /* and add one for a minute later that has an alarm uri */ + appt = g_slice_new0 (struct IndicatorDatetimeAppt); + appt->is_daily = TRUE; + appt->begin = g_date_time_add_minutes (prev->end, 1); + appt->end = g_date_time_add_minutes (appt->begin, 1); + appt->color = g_strdup ("#0000FF"); + appt->is_event = TRUE; + appt->summary = g_strdup ("Second Daily alarm"); + appt->uid = g_strdup ("this uid isn't very random either."); + appt->has_alarms = FALSE; + appointments = g_slist_prepend (appointments, appt); + + /* done */ + g_task_return_pointer (task, appointments, NULL); + g_object_unref (task); +} + +static GSList * +my_get_appointments_finish (IndicatorDatetimePlanner * self G_GNUC_UNUSED, + GAsyncResult * res, + GError ** error) +{ + return g_task_propagate_pointer (G_TASK(res), error); +} + +static gboolean +my_is_configured (IndicatorDatetimePlanner * planner) +{ + IndicatorDatetimePlannerMock * self; + self = INDICATOR_DATETIME_PLANNER_MOCK (planner); + return self->priv->is_configured; +} + +static void +my_activate (IndicatorDatetimePlanner * self G_GNUC_UNUSED) +{ + g_message ("%s %s", G_STRLOC, G_STRFUNC); +} + +static void +my_activate_time (IndicatorDatetimePlanner * self G_GNUC_UNUSED, + GDateTime * activate_time) +{ + gchar * str = g_date_time_format (activate_time, "%F %T"); + g_message ("%s %s: %s", G_STRLOC, G_STRFUNC, str); + g_free (str); +} + +/*** +**** GObject virtual funcs +***/ + +static void +my_dispose (GObject * o) +{ + G_OBJECT_CLASS (indicator_datetime_planner_mock_parent_class)->dispose (o); +} + +/*** +**** Instantiation +***/ + +static void +indicator_datetime_planner_mock_class_init (IndicatorDatetimePlannerMockClass * klass) +{ + GObjectClass * object_class; + IndicatorDatetimePlannerClass * planner_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = my_dispose; + + planner_class = INDICATOR_DATETIME_PLANNER_CLASS (klass); + planner_class->is_configured = my_is_configured; + 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 (IndicatorDatetimePlannerMockPriv)); +} + +static void +indicator_datetime_planner_mock_init (IndicatorDatetimePlannerMock * self) +{ + priv_t * p; + + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_DATETIME_PLANNER_MOCK, + IndicatorDatetimePlannerMockPriv); + + p->is_configured = TRUE; + + self->priv = p; +} + +/*** +**** Public +***/ + +IndicatorDatetimePlanner * +indicator_datetime_planner_mock_new (void) +{ + gpointer o = g_object_new (INDICATOR_TYPE_DATETIME_PLANNER_MOCK, NULL); + + return INDICATOR_DATETIME_PLANNER (o); +} diff --git a/src/planner-mock.h b/src/planner-mock.h new file mode 100644 index 0000000..8d7d7c2 --- /dev/null +++ b/src/planner-mock.h @@ -0,0 +1,58 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . + */ + +#ifndef __INDICATOR_DATETIME_PLANNER_MOCK__H__ +#define __INDICATOR_DATETIME_PLANNER_MOCK__H__ + +#include "planner.h" /* parent class */ + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_DATETIME_PLANNER_MOCK (indicator_datetime_planner_mock_get_type()) +#define INDICATOR_DATETIME_PLANNER_MOCK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_DATETIME_PLANNER_MOCK, IndicatorDatetimePlannerMock)) +#define INDICATOR_DATETIME_PLANNER_MOCK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_DATETIME_PLANNER_MOCK, IndicatorDatetimePlannerMockClass)) +#define INDICATOR_IS_DATETIME_PLANNER_MOCK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_DATETIME_PLANNER_MOCK)) + +typedef struct _IndicatorDatetimePlannerMock IndicatorDatetimePlannerMock; +typedef struct _IndicatorDatetimePlannerMockPriv IndicatorDatetimePlannerMockPriv; +typedef struct _IndicatorDatetimePlannerMockClass IndicatorDatetimePlannerMockClass; + +GType indicator_datetime_planner_mock_get_type (void); + +/** + * An IndicatorDatetimePlanner which uses Evolution Data Server + * to get its list of appointments. + */ +struct _IndicatorDatetimePlannerMock +{ + /*< private >*/ + IndicatorDatetimePlanner parent; + IndicatorDatetimePlannerMockPriv * priv; +}; + +struct _IndicatorDatetimePlannerMockClass +{ + IndicatorDatetimePlannerClass parent_class; +}; + +IndicatorDatetimePlanner * indicator_datetime_planner_mock_new (void); + +G_END_DECLS + +#endif /* __INDICATOR_DATETIME_PLANNER_MOCK__H__ */ -- cgit v1.2.3 From a52e3b86ee0dbce56221d1327c6c62a6d8e163e3 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 9 Oct 2013 21:33:15 -0500 Subject: preliminary implementation of snap decision --- src/main.c | 6 +++++ src/service.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 70 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 073c876..34e9b98 100644 --- a/src/main.c +++ b/src/main.c @@ -24,6 +24,7 @@ #include #include +#include #include "planner-eds.h" #include "planner-mock.h" @@ -52,6 +53,11 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); textdomain (GETTEXT_PACKAGE); + /* init libnotify */ + if (!notify_init ("indicator-datetime-service")) + g_critical ("libnotify initialization failed"); + + /* get the planner */ if (g_getenv ("INDICATOR_DATETIME_USE_FAKE_PLANNER") != NULL) { diff --git a/src/service.c b/src/service.c index 57d0a7e..c76b07e 100644 --- a/src/service.c +++ b/src/service.c @@ -24,6 +24,7 @@ #include #include +#include #include #include "dbus-shared.h" @@ -431,31 +432,80 @@ dispatch_alarm_url (const struct IndicatorDatetimeAppt * appt) url_dispatch_send (appt->url, NULL, NULL); } -/* Check for alarms that start at the current time. - If we find any, we dispatch the URL associated with them. */ +#if 0 static void -dispatch_alarm_urls (IndicatorDatetimeService * self) +on_notification_closed (NotifyNotification * nn, gpointer gself) { - GDateTime * now = indicator_datetime_service_get_localtime (self); - GSList * l; + //IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself); - for (l=self->priv->upcoming_appointments; l!=NULL; l=l->next) - { - const struct IndicatorDatetimeAppt * appt = l->data; + g_message ("hello world"); - if (appointment_has_alarm_url (appt) && datetimes_have_the_same_minute (now, appt->begin)) - dispatch_alarm_url (appt); - } + /* cleanup */ + g_signal_handlers_disconnect_by_data (nn, gself); + g_object_unref (nn); +} +#endif - g_date_time_unref (now); +static void +on_alarm_popup_ok_clicked (NotifyNotification * nn G_GNUC_UNUSED, char * action G_GNUC_UNUSED, gpointer gurl) +{ + const char * url = gurl; + url_dispatch_send (url, NULL, NULL); } +#define ALARM_ICON_NAME "alarm-symbolic" + static void update_appointment_lists (IndicatorDatetimeService * self); static gboolean -on_alarm_timer (gpointer self) +on_alarm_timer (gpointer gself) { - dispatch_alarm_urls (self); + GDateTime * now; + GSList * l; + IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself); + + /* Check for alarms that start at the current time. + * If we find one, trigger a snap decision displaying + * the appointment text and a single button to dismiss */ + now = indicator_datetime_service_get_localtime (self); + for (l=self->priv->upcoming_appointments; l!=NULL; l=l->next) + { + gchar * title; + const gchar * body; + const struct IndicatorDatetimeAppt * appt = l->data; + NotifyNotification * nn; + GError * error; + + if (!appointment_has_alarm_url (appt)) + continue; + + if (!datetimes_have_the_same_minute (now, appt->begin)) + continue; + + title = g_date_time_format (now, get_terse_time_format_string (now)); + body = appt->summary; + nn = notify_notification_new (title, body, ALARM_ICON_NAME); + + notify_notification_set_hint (nn, "x-canonical-snap-decisions", + g_variant_new_boolean(TRUE)); + notify_notification_set_hint (nn, "x-canonical-private-button-tint", + g_variant_new_boolean(TRUE)); + notify_notification_add_action (nn, "ok", _("OK"), + on_alarm_popup_ok_clicked, + g_strdup (appt->url), g_free); + //g_signal_connect (nn, "closed", G_CALLBACK(on_notification_closed), self); + + error = NULL; + notify_notification_show (nn, &error); + if (error != NULL) + { + g_warning ("Unable to show alarm '%s' popup: %s", body, error->message); + g_error_free (error); + dispatch_alarm_url (appt); + } + g_free (title); + } + g_date_time_unref (now); /* rebuild the alarm list asynchronously. when it's done, set_upcoming_appointments() will update the alarm timer */ -- cgit v1.2.3 From dae4fdd39e5381083345e87759dbaffddabe14e4 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 9 Oct 2013 22:55:26 -0500 Subject: more wiring in of mock objects --- src/main.c | 38 +++++++++++++++++++++++++++----------- src/service.c | 7 +++++-- 2 files changed, 32 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 34e9b98..45ee180 100644 --- a/src/main.c +++ b/src/main.c @@ -21,6 +21,7 @@ #include #include /* exit() */ +#include #include #include @@ -30,6 +31,8 @@ #include "planner-mock.h" #include "service.h" +#define TEST_MODE + /*** **** ***/ @@ -41,6 +44,18 @@ on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop) g_main_loop_quit ((GMainLoop*)loop); } +#ifdef TEST_MODE +static void +log_handler (const gchar * log_domain, + GLogLevelFlags log_level, + const gchar * message, + gpointer fp) +{ + fprintf (fp, "%s %d %s\n", log_domain, (int)log_level, message); + fflush (fp); +} +#endif + int main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) { @@ -57,17 +72,15 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) if (!notify_init ("indicator-datetime-service")) g_critical ("libnotify initialization failed"); - - /* get the planner */ - if (g_getenv ("INDICATOR_DATETIME_USE_FAKE_PLANNER") != NULL) - { - g_message ("Using fake appointment book for testing"); - planner = indicator_datetime_planner_mock_new (); - } - else - { - planner = indicator_datetime_planner_eds_new (); - } + /* set up the planner */ +#ifdef TEST_MODE + g_warning ("Using fake appointment book for testing! Probably shouldn't merge this to trunk."); + FILE * fp = fopen ("/tmp/indicator-datetime-log.txt", "w+"); + g_log_set_handler ("Indicator-Datetime", G_LOG_LEVEL_MASK, log_handler, fp); + planner = indicator_datetime_planner_mock_new (); +#else + planner = indicator_datetime_planner_eds_new (); +#endif /* run */ service = indicator_datetime_service_new (planner); @@ -80,5 +93,8 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) g_main_loop_unref (loop); g_object_unref (service); g_object_unref (planner); +#ifdef TEST_MODE + fclose (fp); +#endif return 0; } diff --git a/src/service.c b/src/service.c index c76b07e..61d50aa 100644 --- a/src/service.c +++ b/src/service.c @@ -472,6 +472,7 @@ on_alarm_timer (gpointer gself) { gchar * title; const gchar * body; + const gchar * icon_name; const struct IndicatorDatetimeAppt * appt = l->data; NotifyNotification * nn; GError * error; @@ -484,8 +485,10 @@ on_alarm_timer (gpointer gself) title = g_date_time_format (now, get_terse_time_format_string (now)); body = appt->summary; - nn = notify_notification_new (title, body, ALARM_ICON_NAME); - + icon_name = ALARM_ICON_NAME; + g_debug ("creating a snap decision with title '%s', body '%s', icon '%s'", + title, body, icon_name); + nn = notify_notification_new (title, body, icon_name); notify_notification_set_hint (nn, "x-canonical-snap-decisions", g_variant_new_boolean(TRUE)); notify_notification_set_hint (nn, "x-canonical-private-button-tint", -- cgit v1.2.3 From da87e44c2fedfea688a77137b7e10e227538e63a Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 9 Oct 2013 23:26:26 -0500 Subject: extract-method: show_snap_decision_for_alarm --- src/service.c | 73 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 37 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/service.c b/src/service.c index 61d50aa..37f5756 100644 --- a/src/service.c +++ b/src/service.c @@ -453,7 +453,40 @@ on_alarm_popup_ok_clicked (NotifyNotification * nn G_GNUC_UNUSED, char * action url_dispatch_send (url, NULL, NULL); } -#define ALARM_ICON_NAME "alarm-symbolic" +static void +show_snap_decision_for_alarm (const struct IndicatorDatetimeAppt * appt) +{ + gchar * title; + const gchar * body; + const gchar * icon_name; + NotifyNotification * nn; + GError * error; + + title = g_date_time_format (appt->begin, + get_terse_time_format_string (appt->begin)); + body = appt->summary; + icon_name = "alarm-symbolic"; + g_debug ("creating a snap decision with title '%s', body '%s', icon '%s'", + title, body, icon_name); + nn = notify_notification_new (title, body, icon_name); + notify_notification_set_hint (nn, "x-canonical-snap-decisions", + g_variant_new_boolean(TRUE)); + notify_notification_set_hint (nn, "x-canonical-private-button-tint", + g_variant_new_boolean(TRUE)); + notify_notification_add_action (nn, "ok", _("OK"), + on_alarm_popup_ok_clicked, + g_strdup (appt->url), g_free); + error = NULL; + notify_notification_show (nn, &error); + if (error != NULL) + { + g_warning ("Unable to show alarm '%s' popup: %s", body, error->message); + g_error_free (error); + dispatch_alarm_url (appt); + } + + g_free (title); +} static void update_appointment_lists (IndicatorDatetimeService * self); @@ -470,43 +503,11 @@ on_alarm_timer (gpointer gself) now = indicator_datetime_service_get_localtime (self); for (l=self->priv->upcoming_appointments; l!=NULL; l=l->next) { - gchar * title; - const gchar * body; - const gchar * icon_name; const struct IndicatorDatetimeAppt * appt = l->data; - NotifyNotification * nn; - GError * error; - if (!appointment_has_alarm_url (appt)) - continue; - - if (!datetimes_have_the_same_minute (now, appt->begin)) - continue; - - title = g_date_time_format (now, get_terse_time_format_string (now)); - body = appt->summary; - icon_name = ALARM_ICON_NAME; - g_debug ("creating a snap decision with title '%s', body '%s', icon '%s'", - title, body, icon_name); - nn = notify_notification_new (title, body, icon_name); - notify_notification_set_hint (nn, "x-canonical-snap-decisions", - g_variant_new_boolean(TRUE)); - notify_notification_set_hint (nn, "x-canonical-private-button-tint", - g_variant_new_boolean(TRUE)); - notify_notification_add_action (nn, "ok", _("OK"), - on_alarm_popup_ok_clicked, - g_strdup (appt->url), g_free); - //g_signal_connect (nn, "closed", G_CALLBACK(on_notification_closed), self); - - error = NULL; - notify_notification_show (nn, &error); - if (error != NULL) - { - g_warning ("Unable to show alarm '%s' popup: %s", body, error->message); - g_error_free (error); - dispatch_alarm_url (appt); - } - g_free (title); + if (appointment_has_alarm_url (appt)) + if (datetimes_have_the_same_minute (now, appt->begin)) + show_snap_decision_for_alarm (appt); } g_date_time_unref (now); -- cgit v1.2.3 From 8441fc4f840d668e2b7fe1582f90eef66e272652 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 14 Oct 2013 23:54:40 -0500 Subject: tweak snap decision comments --- src/service.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/service.c b/src/service.c index 37f5756..270f214 100644 --- a/src/service.c +++ b/src/service.c @@ -493,13 +493,11 @@ static void update_appointment_lists (IndicatorDatetimeService * self); static gboolean on_alarm_timer (gpointer gself) { + IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself); GDateTime * now; GSList * l; - IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself); - /* Check for alarms that start at the current time. - * If we find one, trigger a snap decision displaying - * the appointment text and a single button to dismiss */ + /* If there are any alarms at the current time, show a snap decision */ now = indicator_datetime_service_get_localtime (self); for (l=self->priv->upcoming_appointments; l!=NULL; l=l->next) { @@ -512,7 +510,8 @@ on_alarm_timer (gpointer gself) g_date_time_unref (now); /* rebuild the alarm list asynchronously. - when it's done, set_upcoming_appointments() will update the alarm timer */ + set_upcoming_appointments() will update the alarm timer when this + async call is done, so no need to restart the timer here... */ update_appointment_lists (self); return G_SOURCE_REMOVE; -- cgit v1.2.3 From 8dadf00b78312867f33a2f6dcd39118a1beb150c Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 16 Oct 2013 14:52:54 -0500 Subject: for testing purposes, fire off a snap decision as soon as the datetime indicator is started. this way one can test on phablet by running as user phablet --- src/main.c | 57 ++++++++++++++++++++++++++++++++++++++++----------------- src/service.c | 33 ++++++++++----------------------- 2 files changed, 50 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 45ee180..c7ad34a 100644 --- a/src/main.c +++ b/src/main.c @@ -31,30 +31,55 @@ #include "planner-mock.h" #include "service.h" -#define TEST_MODE - /*** **** ***/ static void -on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop) +on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop G_GNUC_UNUSED) { g_message ("exiting: service couldn't acquire or lost ownership of busname"); g_main_loop_quit ((GMainLoop*)loop); } -#ifdef TEST_MODE static void -log_handler (const gchar * log_domain, - GLogLevelFlags log_level, - const gchar * message, - gpointer fp) +action_ok (NotifyNotification *notification G_GNUC_UNUSED, + char *action, + gpointer gurl) { - fprintf (fp, "%s %d %s\n", log_domain, (int)log_level, message); - fflush (fp); + const char * url = gurl; + g_message ("'%s' clicked for snap decision; url is '%s'", action, url); +} + +static void +show_snap_decision (void) +{ + const gchar * title = "Title"; + const gchar * body = "Body"; + const gchar * icon_name = "alarm-clock"; + NotifyNotification * nn; + GError * error; + + g_debug ("creating a snap decision with title '%s', body '%s', icon '%s'", + title, body, icon_name); + + nn = notify_notification_new (title, body, icon_name); + notify_notification_set_hint (nn, "x-canonical-snap-decisions", + g_variant_new_boolean(TRUE)); + notify_notification_set_hint (nn, "x-canonical-private-button-tint", + g_variant_new_boolean(TRUE)); + notify_notification_add_action (nn, "action_accept", _("OK"), + action_ok, g_strdup("hello world"), g_free); + + g_message ("showing notification %p", nn); + error = NULL; + notify_notification_show (nn, &error); + if (error != NULL) + { + g_warning ("Unable to show alarm '%s' popup: %s", body, error->message); + g_error_free (error); + } } -#endif int main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) @@ -74,14 +99,15 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) /* set up the planner */ #ifdef TEST_MODE - g_warning ("Using fake appointment book for testing! Probably shouldn't merge this to trunk."); - FILE * fp = fopen ("/tmp/indicator-datetime-log.txt", "w+"); - g_log_set_handler ("Indicator-Datetime", G_LOG_LEVEL_MASK, log_handler, fp); + g_warning ("Using fake appointment book for testing! " + "Probably shouldn't merge this to trunk."); planner = indicator_datetime_planner_mock_new (); #else planner = indicator_datetime_planner_eds_new (); #endif + show_snap_decision (); + /* run */ service = indicator_datetime_service_new (planner); loop = g_main_loop_new (NULL, FALSE); @@ -93,8 +119,5 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) g_main_loop_unref (loop); g_object_unref (service); g_object_unref (planner); -#ifdef TEST_MODE - fclose (fp); -#endif return 0; } diff --git a/src/service.c b/src/service.c index 270f214..fd3d937 100644 --- a/src/service.c +++ b/src/service.c @@ -432,24 +432,13 @@ dispatch_alarm_url (const struct IndicatorDatetimeAppt * appt) url_dispatch_send (appt->url, NULL, NULL); } -#if 0 static void -on_notification_closed (NotifyNotification * nn, gpointer gself) -{ - //IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself); - - g_message ("hello world"); - - /* cleanup */ - g_signal_handlers_disconnect_by_data (nn, gself); - g_object_unref (nn); -} -#endif - -static void -on_alarm_popup_ok_clicked (NotifyNotification * nn G_GNUC_UNUSED, char * action G_GNUC_UNUSED, gpointer gurl) +action_ok (NotifyNotification *notification G_GNUC_UNUSED, + char *action, + gpointer gurl) { const char * url = gurl; + g_debug ("'%s' clicked for snap decision %s", action, url); url_dispatch_send (url, NULL, NULL); } @@ -465,17 +454,18 @@ show_snap_decision_for_alarm (const struct IndicatorDatetimeAppt * appt) title = g_date_time_format (appt->begin, get_terse_time_format_string (appt->begin)); body = appt->summary; - icon_name = "alarm-symbolic"; + icon_name = "alarm-clock"; g_debug ("creating a snap decision with title '%s', body '%s', icon '%s'", title, body, icon_name); + nn = notify_notification_new (title, body, icon_name); notify_notification_set_hint (nn, "x-canonical-snap-decisions", g_variant_new_boolean(TRUE)); notify_notification_set_hint (nn, "x-canonical-private-button-tint", g_variant_new_boolean(TRUE)); - notify_notification_add_action (nn, "ok", _("OK"), - on_alarm_popup_ok_clicked, - g_strdup (appt->url), g_free); + notify_notification_add_action (nn, "action_accept", _("OK"), + action_ok, g_strdup(appt->url), g_free); + error = NULL; notify_notification_show (nn, &error); if (error != NULL) @@ -1981,14 +1971,11 @@ on_name_lost (GDBusConnection * connection G_GNUC_UNUSED, { IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself); - if (connection == NULL) - g_error ("Unable to get bus connection to own name '%s'", name); - g_debug ("%s %s name lost %s", G_STRLOC, G_STRFUNC, name); unexport (self); - g_signal_emit (self, signals[SIGNAL_NAME_LOST], 0, NULL); + //g_signal_emit (self, signals[SIGNAL_NAME_LOST], 0, NULL); } -- cgit v1.2.3 From a96e714329ea80e676af5dc5db69ba5b62a25b6e Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 16 Oct 2013 16:48:01 -0500 Subject: add a test mode for alarms. --- src/main.c | 78 ++++++++++++++++++++++++-------------------------------------- 1 file changed, 30 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index c7ad34a..3be51eb 100644 --- a/src/main.c +++ b/src/main.c @@ -35,55 +35,28 @@ **** ***/ +/* When enabled, new alarms will show up every minute to test snap decisions */ +static gboolean test_alarms = FALSE; + +static GOptionEntry entries[] = { + { "test-alarms", '\0', 0, G_OPTION_ARG_NONE, &test_alarms, "Test Alarms", NULL }, + { NULL } +}; + static void on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop G_GNUC_UNUSED) { g_message ("exiting: service couldn't acquire or lost ownership of busname"); - g_main_loop_quit ((GMainLoop*)loop); -} -static void -action_ok (NotifyNotification *notification G_GNUC_UNUSED, - char *action, - gpointer gurl) -{ - const char * url = gurl; - g_message ("'%s' clicked for snap decision; url is '%s'", action, url); -} - -static void -show_snap_decision (void) -{ - const gchar * title = "Title"; - const gchar * body = "Body"; - const gchar * icon_name = "alarm-clock"; - NotifyNotification * nn; - GError * error; - - g_debug ("creating a snap decision with title '%s', body '%s', icon '%s'", - title, body, icon_name); - - nn = notify_notification_new (title, body, icon_name); - notify_notification_set_hint (nn, "x-canonical-snap-decisions", - g_variant_new_boolean(TRUE)); - notify_notification_set_hint (nn, "x-canonical-private-button-tint", - g_variant_new_boolean(TRUE)); - notify_notification_add_action (nn, "action_accept", _("OK"), - action_ok, g_strdup("hello world"), g_free); - - g_message ("showing notification %p", nn); - error = NULL; - notify_notification_show (nn, &error); - if (error != NULL) - { - g_warning ("Unable to show alarm '%s' popup: %s", body, error->message); - g_error_free (error); - } + if (!test_alarms) + g_main_loop_quit ((GMainLoop*)loop); } int main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) { + GOptionContext * context; + GError * error; IndicatorDatetimePlanner * planner; IndicatorDatetimeService * service; GMainLoop * loop; @@ -97,16 +70,25 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) if (!notify_init ("indicator-datetime-service")) g_critical ("libnotify initialization failed"); + /* parse command-line options */ + context = g_option_context_new (NULL); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + g_print("option parsing failed: %s\n", error->message); + return EXIT_FAILURE; + } + /* set up the planner */ -#ifdef TEST_MODE - g_warning ("Using fake appointment book for testing! " - "Probably shouldn't merge this to trunk."); - planner = indicator_datetime_planner_mock_new (); -#else - planner = indicator_datetime_planner_eds_new (); -#endif - - show_snap_decision (); + if (test_alarms) + { + g_message ("Using fake appointment book for testing alarms."); + planner = indicator_datetime_planner_mock_new (); + } + else + { + planner = indicator_datetime_planner_eds_new (); + } /* run */ service = indicator_datetime_service_new (planner); -- cgit v1.2.3 From 42b338cdced3f34d719ffda6108818df2e85a84b Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 16 Oct 2013 16:48:28 -0500 Subject: use a two-button snap decision because one-button snap decisions don't show up. --- src/service.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/service.c b/src/service.c index fd3d937..09ee4d4 100644 --- a/src/service.c +++ b/src/service.c @@ -401,8 +401,10 @@ appointment_has_alarm_url (const struct IndicatorDatetimeAppt * appt) } static gboolean -datetimes_have_the_same_minute (GDateTime * a, GDateTime * b) +datetimes_have_the_same_minute (GDateTime * a G_GNUC_UNUSED, GDateTime * b G_GNUC_UNUSED) { +return TRUE; +#if 0 int ay, am, ad; int by, bm, bd; @@ -414,6 +416,7 @@ datetimes_have_the_same_minute (GDateTime * a, GDateTime * b) (ad == bd) && (g_date_time_get_hour (a) == g_date_time_get_hour (b)) && (g_date_time_get_minute (a) == g_date_time_get_minute (b)); +#endif } static void @@ -433,13 +436,18 @@ dispatch_alarm_url (const struct IndicatorDatetimeAppt * appt) } static void -action_ok (NotifyNotification *notification G_GNUC_UNUSED, - char *action, - gpointer gurl) +on_snap_decided (NotifyNotification * notification G_GNUC_UNUSED, + char * action, + gpointer gurl) { - const char * url = gurl; - g_debug ("'%s' clicked for snap decision %s", action, url); - url_dispatch_send (url, NULL, NULL); + g_debug ("%s: %s", G_STRFUNC, action); + + if (!g_strcmp0 (action, "ok")) + { + const gchar * url = gurl; + g_debug ("dispatching url '%s'", url); + url_dispatch_send (url, NULL, NULL); + } } static void @@ -461,10 +469,10 @@ show_snap_decision_for_alarm (const struct IndicatorDatetimeAppt * appt) nn = notify_notification_new (title, body, icon_name); notify_notification_set_hint (nn, "x-canonical-snap-decisions", g_variant_new_boolean(TRUE)); - notify_notification_set_hint (nn, "x-canonical-private-button-tint", - g_variant_new_boolean(TRUE)); - notify_notification_add_action (nn, "action_accept", _("OK"), - action_ok, g_strdup(appt->url), g_free); + notify_notification_add_action (nn, "ok", _("OK"), + on_snap_decided, g_strdup(appt->url), g_free); + notify_notification_add_action (nn, "cancel", _("Cancel"), + on_snap_decided, NULL, NULL); error = NULL; notify_notification_show (nn, &error); @@ -493,6 +501,8 @@ on_alarm_timer (gpointer gself) { const struct IndicatorDatetimeAppt * appt = l->data; +g_message ("[%s][%s]", g_date_time_format (appt->begin, "%F %T"), appt->url); + if (appointment_has_alarm_url (appt)) if (datetimes_have_the_same_minute (now, appt->begin)) show_snap_decision_for_alarm (appt); @@ -1975,7 +1985,7 @@ on_name_lost (GDBusConnection * connection G_GNUC_UNUSED, unexport (self); - //g_signal_emit (self, signals[SIGNAL_NAME_LOST], 0, NULL); + g_signal_emit (self, signals[SIGNAL_NAME_LOST], 0, NULL); } -- cgit v1.2.3 From 831b21bca8afb458cc33e878d8246a00f68e6dbd Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 16 Oct 2013 21:40:13 -0500 Subject: change ok/cancel buttons to the slightly-more-informative show/dismiss --- src/service.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/service.c b/src/service.c index e83410e..9c30310 100644 --- a/src/service.c +++ b/src/service.c @@ -451,7 +451,7 @@ on_snap_decided (NotifyNotification * notification G_GNUC_UNUSED, { g_debug ("%s: %s", G_STRFUNC, action); - if (!g_strcmp0 (action, "ok")) + if (!g_strcmp0 (action, "show")) { const gchar * url = gurl; g_debug ("dispatching url '%s'", url); @@ -478,9 +478,9 @@ show_snap_decision_for_alarm (const struct IndicatorDatetimeAppt * appt) nn = notify_notification_new (title, body, icon_name); notify_notification_set_hint (nn, "x-canonical-snap-decisions", g_variant_new_boolean(TRUE)); - notify_notification_add_action (nn, "ok", _("OK"), + notify_notification_add_action (nn, "show", _("Show"), on_snap_decided, g_strdup(appt->url), g_free); - notify_notification_add_action (nn, "cancel", _("Cancel"), + notify_notification_add_action (nn, "dismiss", _("Dismiss"), on_snap_decided, NULL, NULL); error = NULL; -- cgit v1.2.3 From 05c1039f4b9f0014371bb767089755317ea2d322 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 16 Oct 2013 21:41:28 -0500 Subject: in the alarm snap decision, add x-canonical-private-button-tint hint to highlight the 'Show' button --- src/service.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/service.c b/src/service.c index 9c30310..e42b689 100644 --- a/src/service.c +++ b/src/service.c @@ -476,8 +476,12 @@ show_snap_decision_for_alarm (const struct IndicatorDatetimeAppt * appt) title, body, icon_name); nn = notify_notification_new (title, body, icon_name); - notify_notification_set_hint (nn, "x-canonical-snap-decisions", - g_variant_new_boolean(TRUE)); + notify_notification_set_hint_string (nn, + "x-canonical-snap-decisions", + "true"); + notify_notification_set_hint_string (nn, + "x-canonical-private-button-tint", + "true"); notify_notification_add_action (nn, "show", _("Show"), on_snap_decided, g_strdup(appt->url), g_free); notify_notification_add_action (nn, "dismiss", _("Dismiss"), -- cgit v1.2.3