398
388
g_date_time_unref (now);
405
static void set_alarm_timer (IndicatorDatetimeService * self);
408
appointment_has_alarm_url (const struct IndicatorDatetimeAppt * appt)
410
return (appt->has_alarms) &&
411
(appt->url != NULL) &&
412
(g_str_has_prefix (appt->url, "alarm:///"));
416
datetimes_have_the_same_minute (GDateTime * a G_GNUC_UNUSED, GDateTime * b G_GNUC_UNUSED)
421
g_date_time_get_ymd (a, &ay, &am, &ad);
422
g_date_time_get_ymd (b, &by, &bm, &bd);
427
(g_date_time_get_hour (a) == g_date_time_get_hour (b)) &&
428
(g_date_time_get_minute (a) == g_date_time_get_minute (b));
432
dispatch_alarm_url (const struct IndicatorDatetimeAppt * appt)
436
g_return_if_fail (appt != NULL);
437
g_return_if_fail (appointment_has_alarm_url (appt));
439
str = g_date_time_format (appt->begin, "%F %T");
440
g_debug ("dispatching url \"%s\" for appointment \"%s\", which begins at %s",
441
appt->url, appt->summary, str);
444
url_dispatch_send (appt->url, NULL, NULL);
448
on_snap_decided (NotifyNotification * notification G_GNUC_UNUSED,
452
g_debug ("%s: %s", G_STRFUNC, action);
454
if (!g_strcmp0 (action, "show"))
456
const gchar * url = gurl;
457
g_debug ("dispatching url '%s'", url);
458
url_dispatch_send (url, NULL, NULL);
463
show_snap_decision_for_alarm (const struct IndicatorDatetimeAppt * appt)
467
const gchar * icon_name;
468
NotifyNotification * nn;
471
title = g_date_time_format (appt->begin,
472
get_terse_time_format_string (appt->begin));
473
body = appt->summary;
474
icon_name = ALARM_CLOCK_ICON_NAME;
475
g_debug ("creating a snap decision with title '%s', body '%s', icon '%s'",
476
title, body, icon_name);
478
nn = notify_notification_new (title, body, icon_name);
479
notify_notification_set_hint_string (nn,
480
"x-canonical-snap-decisions",
482
notify_notification_set_hint_string (nn,
483
"x-canonical-private-button-tint",
485
notify_notification_add_action (nn, "show", _("Show"),
486
on_snap_decided, g_strdup(appt->url), g_free);
487
notify_notification_add_action (nn, "dismiss", _("Dismiss"),
488
on_snap_decided, NULL, NULL);
491
notify_notification_show (nn, &error);
494
g_warning ("Unable to show alarm '%s' popup: %s", body, error->message);
495
g_error_free (error);
496
dispatch_alarm_url (appt);
502
static void update_appointment_lists (IndicatorDatetimeService * self);
505
on_alarm_timer (gpointer gself)
507
IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself);
511
/* If there are any alarms at the current time, show a snap decision */
512
now = indicator_datetime_service_get_localtime (self);
513
for (l=self->priv->upcoming_appointments; l!=NULL; l=l->next)
515
const struct IndicatorDatetimeAppt * appt = l->data;
517
if (appointment_has_alarm_url (appt))
518
if (datetimes_have_the_same_minute (now, appt->begin))
519
show_snap_decision_for_alarm (appt);
521
g_date_time_unref (now);
523
/* rebuild the alarm list asynchronously.
524
set_upcoming_appointments() will update the alarm timer when this
525
async call is done, so no need to restart the timer here... */
526
update_appointment_lists (self);
528
return G_SOURCE_REMOVE;
531
/* if there are upcoming alarms, set the alarm timer to the nearest one.
532
otherwise, unset the alarm timer. */
534
set_alarm_timer (IndicatorDatetimeService * self)
538
GDateTime * alarm_time;
542
indicator_clear_timer (&p->alarm_timer);
544
now = indicator_datetime_service_get_localtime (self);
546
/* find the time of the next alarm on our calendar */
548
for (l=p->upcoming_appointments; l!=NULL; l=l->next)
550
const struct IndicatorDatetimeAppt * appt = l->data;
552
if (appointment_has_alarm_url (appt))
553
if (g_date_time_compare (appt->begin, now) > 0)
554
if (!alarm_time || g_date_time_compare (alarm_time, appt->begin) > 0)
555
alarm_time = appt->begin;
558
/* if there's an upcoming alarm, set a timer to wake up at that time */
559
if (alarm_time != NULL)
561
GTimeSpan interval_msec;
565
interval_msec = g_date_time_difference (alarm_time, now);
566
interval_msec += G_USEC_PER_SEC; /* fire a moment after alarm_time */
567
interval_msec /= 1000; /* convert from usec to msec */
569
str = g_date_time_format (alarm_time, "%F %T");
570
g_debug ("%s is the next alarm time", str);
572
then = g_date_time_add_seconds (now, interval_msec/1000);
573
str = g_date_time_format (then, "%F %T");
574
g_debug ("%s is when we'll wake up for it", str);
576
g_date_time_unref (then);
578
p->alarm_timer = g_timeout_add_full (G_PRIORITY_HIGH,
579
(guint) interval_msec,
585
g_date_time_unref (now);
593
392
update_internal_timezone (IndicatorDatetimeService * self)
947
add_appointments (IndicatorDatetimeService * self, GMenu * menu, gboolean phone)
746
add_appointments (IndicatorDatetimeService * self, GMenu * menu, gboolean terse)
949
748
const int MAX_APPTS = 5;
749
GDateTime * now = indicator_datetime_service_get_localtime (self);
956
now = indicator_datetime_service_get_localtime (self);
958
added = g_hash_table_new (g_str_hash, g_str_equal);
960
754
/* build appointment menuitems */
961
755
appts = self->priv->upcoming_appointments;
962
756
for (l=appts, i=0; l!=NULL && i<MAX_APPTS; l=l->next, i++)
964
758
struct IndicatorDatetimeAppt * appt = l->data;
759
char * fmt = get_appointment_time_format (appt, now, self->priv->settings, terse);
760
const gint64 unix_time = g_date_time_to_unix (appt->begin);
967
761
GMenuItem * menu_item;
969
if (g_hash_table_contains (added, appt->uid))
972
g_hash_table_add (added, appt->uid);
974
fmt = get_appointment_time_format (appt, now, self->priv->settings, phone);
975
unix_time = g_date_time_to_unix (appt->begin);
977
763
menu_item = g_menu_item_new (appt->summary, NULL);
979
765
if (appt->has_alarms)
990
776
g_menu_item_set_attribute (menu_item, "x-canonical-type",
991
777
"s", appt->has_alarms ? "com.canonical.indicator.alarm"
992
778
: "com.canonical.indicator.appointment");
995
g_menu_item_set_action_and_target_value (menu_item,
996
"indicator.activate-appointment",
997
g_variant_new_string (appt->uid));
999
g_menu_item_set_action_and_target_value (menu_item,
1000
"indicator.activate-planner",
1001
g_variant_new_int64 (unix_time));
779
g_menu_item_set_action_and_target_value (menu_item,
780
"indicator.activate-planner",
781
g_variant_new_int64 (unix_time));
1002
782
g_menu_append_item (menu, menu_item);
1003
783
g_object_unref (menu_item);
1008
g_hash_table_unref (added);
1009
788
g_date_time_unref (now);
1587
on_activate_appointment (GSimpleAction * a G_GNUC_UNUSED,
1591
priv_t * p = INDICATOR_DATETIME_SERVICE(gself)->priv;
1592
const gchar * uid = g_variant_get_string (param, NULL);
1596
const struct IndicatorDatetimeAppt * appt;
1599
/* find the appointment that matches that uid */
1600
for (l=p->upcoming_appointments, appt=NULL; l && !appt; l=l->next)
1602
const struct IndicatorDatetimeAppt * tmp = l->data;
1603
if (!g_strcmp0 (uid, tmp->uid))
1607
/* if that appointment's an alarm, dispatch its url */
1608
g_debug ("%s: uri '%s'; matching appt is %p", G_STRFUNC, uid, appt);
1609
if (appt && appointment_has_alarm_url (appt))
1610
dispatch_alarm_url (appt);
1615
1366
on_phone_clock_activated (GSimpleAction * a G_GNUC_UNUSED,
1616
1367
GVariant * param G_GNUC_UNUSED,
1617
1368
gpointer gself G_GNUC_UNUSED)
2400
2103
update_appointment_lists (self);
2404
indicator_datetime_service_set_planner (IndicatorDatetimeService * self,
2405
IndicatorDatetimePlanner * planner)
2409
g_return_if_fail (INDICATOR_IS_DATETIME_SERVICE (self));
2410
g_return_if_fail (INDICATOR_IS_DATETIME_PLANNER (planner));
2414
/* clear the old planner & appointments */
2416
if (p->planner != NULL)
2418
g_signal_handlers_disconnect_by_data (p->planner, self);
2419
g_clear_object (&p->planner);
2422
g_clear_pointer (&p->upcoming_appointments, indicator_datetime_planner_free_appointments);
2423
g_clear_pointer (&p->calendar_appointments, indicator_datetime_planner_free_appointments);
2425
/* set the new planner & begin fetching appointments from it */
2427
if (planner != NULL)
2429
p->planner = g_object_ref (planner);
2431
g_signal_connect_swapped (p->planner, "appointments-changed",
2432
G_CALLBACK(update_appointment_lists), self);
2434
update_appointment_lists (self);