diff options
author | Florian Brosch <flo.brosch@gmail.com> | 2017-10-29 17:23:48 +0100 |
---|---|---|
committer | Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | 2017-12-11 22:13:16 -0200 |
commit | eceb826e77c0f7b052e3ea96f9355409c3017189 (patch) | |
tree | 279992bcdf9db07c2e986482002c31645c1e43d3 | |
parent | d51d1ea2cdc32baf1d39a14c8e35c43225720b56 (diff) | |
download | gnome-calendar-wip/flb/weather-forecast.tar.gz |
Whitespace changeswip/flb/weather-forecast
-rw-r--r-- | src/gcal-manager.c | 66 | ||||
-rw-r--r-- | src/gcal-search-view.c | 28 | ||||
-rw-r--r-- | src/gcal-timer.c | 51 | ||||
-rw-r--r-- | src/gcal-timer.h | 26 | ||||
-rw-r--r-- | src/gcal-utils.h | 127 | ||||
-rw-r--r-- | src/gcal-weather-info.c | 39 | ||||
-rw-r--r-- | src/gcal-weather-info.h | 18 | ||||
-rw-r--r-- | src/gcal-weather-service.c | 1751 | ||||
-rw-r--r-- | src/gcal-weather-service.h | 38 | ||||
-rw-r--r-- | src/gcal-window.c | 198 | ||||
-rw-r--r-- | src/views/gcal-week-header.c | 46 | ||||
-rw-r--r-- | src/views/gcal-week-view.c | 24 | ||||
-rw-r--r-- | src/views/gcal-year-view.c | 87 | ||||
-rw-r--r-- | src/views/gcal-year-view.h | 14 |
14 files changed, 1209 insertions, 1304 deletions
diff --git a/src/gcal-manager.c b/src/gcal-manager.c index 2e8b7955..caba7ea3 100644 --- a/src/gcal-manager.c +++ b/src/gcal-manager.c @@ -38,70 +38,70 @@ typedef struct { - GcalEvent *event; - GcalManager *manager; + GcalEvent *event; + GcalManager *manager; } AsyncOpsData; typedef struct { ECalDataModelSubscriber *subscriber; - gchar *query; + gchar *query; - guint sources_left; - gboolean passed_start; - gboolean search_done; + guint sources_left; + gboolean passed_start; + gboolean search_done; } ViewStateData; typedef struct { - ECalClient *client; - gboolean connected; + ECalClient *client; + gboolean connected; } GcalManagerUnit; typedef struct { - gchar *event_uid; - GcalManagerUnit *unit; - GcalManagerUnit *new_unit; - ECalComponent *new_component; - GcalManager *manager; + gchar *event_uid; + GcalManagerUnit *unit; + GcalManagerUnit *new_unit; + ECalComponent *new_component; + GcalManager *manager; } MoveEventData; struct _GcalManager { - GObject parent; + GObject parent; /** * The list of clients we are managing. * Each value is of type GCalStoreUnit * And each key is the source uid */ - GHashTable *clients; + GHashTable *clients; - ESourceRegistry *source_registry; + ESourceRegistry *source_registry; ECredentialsPrompter *credentials_prompter; - ECalDataModel *e_data_model; - ECalDataModel *search_data_model; + ECalDataModel *e_data_model; + ECalDataModel *search_data_model; - ECalDataModel *shell_search_data_model; - ViewStateData *search_view_data; + ECalDataModel *shell_search_data_model; + ViewStateData *search_view_data; - GCancellable *async_ops; + GCancellable *async_ops; - GoaClient *goa_client; + GoaClient *goa_client; - GcalClock *clock; + GcalClock *clock; /* state flags */ - gboolean goa_client_ready; - gint sources_at_launch; + gboolean goa_client_ready; + gint sources_at_launch; /* timezone */ - icaltimezone *system_timezone; + icaltimezone *system_timezone; /* property */ - GSettings *settings; + GSettings *settings; }; G_DEFINE_TYPE (GcalManager, gcal_manager, G_TYPE_OBJECT) @@ -131,12 +131,12 @@ static GParamSpec *properties[NUM_PROPS] = { NULL, }; /* -- start: threading related code provided by Milan Crha */ typedef struct { - EThreadJobFunc func; - gpointer user_data; - GDestroyNotify free_user_data; + EThreadJobFunc func; + gpointer user_data; + GDestroyNotify free_user_data; - GCancellable *cancellable; - GError *error; + GCancellable *cancellable; + GError *error; } ThreadJobData; static void @@ -175,7 +175,7 @@ thread_job_thread (gpointer user_data) return g_thread_self (); } -static GCancellable * +static GCancellable* submit_thread_job (EThreadJobFunc func, gpointer user_data, GDestroyNotify free_user_data) diff --git a/src/gcal-search-view.c b/src/gcal-search-view.c index 45a208d8..219121c2 100644 --- a/src/gcal-search-view.c +++ b/src/gcal-search-view.c @@ -35,10 +35,10 @@ typedef struct struct _GcalSearchView { - GtkPopover parent; + GtkPopover parent; - GtkWidget *listbox; - GtkWidget *stack; + GtkWidget *listbox; + GtkWidget *stack; /* Since the user can have (literally) * thousands of events, the usage of @@ -46,23 +46,23 @@ struct _GcalSearchView * the RowEventData lookup constant * time. */ - GHashTable *uuid_to_event; + GHashTable *uuid_to_event; /* misc */ - gint no_results_timeout_id; - gint num_results; - gchar *field; - gchar *query; - time_t current_utc_date; - guint search_timeout_id; + gint no_results_timeout_id; + gint num_results; + gchar *field; + gchar *query; + time_t current_utc_date; + guint search_timeout_id; /* property */ - icaltimetype *date; - GcalManager *manager; /* weak reference */ + icaltimetype *date; + GcalManager *manager; /* weak reference */ /* flags */ - gboolean format_24h; - gboolean subscribed; + gboolean format_24h; + gboolean subscribed; }; enum diff --git a/src/gcal-timer.c b/src/gcal-timer.c index 66fd56c4..abba7770 100644 --- a/src/gcal-timer.c +++ b/src/gcal-timer.c @@ -31,9 +31,9 @@ */ typedef struct _GcalTimer { - GSource parent; - gint64 last_event; - gint64 default_duration; + GSource parent; + gint64 last_event; + gint64 default_duration; } GcalTimer; @@ -48,25 +48,24 @@ typedef struct _GcalTimer */ typedef struct { - GcalTimer *timer; /* unowned */ - GCalTimerFunc callback; - GDestroyNotify destroy_notify; - gpointer data; + GcalTimer *timer; /* unowned */ + GCalTimerFunc callback; + GDestroyNotify destroy_notify; + gpointer data; } CbWrapperData; -static void timer_func_destroy_notify_wrapper (CbWrapperData *wrapper); +static void timer_func_destroy_notify_wrapper (CbWrapperData *wrapper); -static gboolean timer_func_wrapper (CbWrapperData *wrapper); +static gboolean timer_func_wrapper (CbWrapperData *wrapper); -static gboolean timer_source_dispatch (GcalTimer *self, - GSourceFunc callback, - CbWrapperData *user_data); +static gboolean timer_source_dispatch (GcalTimer *self, + GSourceFunc callback, + CbWrapperData *user_data); -static void schedule_next (GcalTimer *self); - -static void timer_source_finalize (GcalTimer *self); +static void schedule_next (GcalTimer *self); +static void timer_source_finalize (GcalTimer *self); @@ -82,8 +81,6 @@ timer_func_destroy_notify_wrapper (CbWrapperData *wrapper) g_free (wrapper); } - - static gboolean timer_func_wrapper (CbWrapperData *wrapper) { @@ -95,8 +92,6 @@ timer_func_wrapper (CbWrapperData *wrapper) return G_SOURCE_CONTINUE; } - - static gboolean timer_source_dispatch (GcalTimer *self, GSourceFunc user_callback, @@ -115,8 +110,6 @@ timer_source_dispatch (GcalTimer *self, return result; } - - static void schedule_next (GcalTimer *self) { @@ -135,8 +128,6 @@ schedule_next (GcalTimer *self) g_source_set_ready_time ((GSource*) self, 0); } - - static void timer_source_finalize (GcalTimer *self) { @@ -182,8 +173,6 @@ gcal_timer_new (gint64 default_duration) return g_steal_pointer (&self); } - - /** * gcal_timer_set_start: * @self: The #GcalTimer. @@ -200,8 +189,6 @@ gcal_timer_start (GcalTimer *self) schedule_next (self); } - - /** * gcal_timer_set_reset: * @self: The #GcalTimer. @@ -218,8 +205,6 @@ gcal_timer_reset (GcalTimer *self) schedule_next (self); } - - /** * gcal_timer_set_stop: * @self: The #GcalTimer. @@ -235,8 +220,6 @@ gcal_timer_stop (GcalTimer *self) g_source_set_ready_time ((GSource*) self, -1); } - - /** * gcal_timer_is_running * @self: The #GcalTimer. @@ -251,8 +234,6 @@ gcal_timer_is_running (GcalTimer *self) return g_source_get_ready_time ((GSource*) self) >= 0; } - - /** * gcal_timer_set_duration: * @self: The #GcalTimer. @@ -280,8 +261,6 @@ gcal_timer_set_default_duration (GcalTimer *self, schedule_next (self); } - - /** * gcal_timer_get_default_duration: * @self: The #GcalTimer. @@ -296,7 +275,6 @@ gcal_timer_get_default_duration (GcalTimer *self) return self->default_duration; } - /** * gcal_timer_set_callback: * @self: The #GcalTimer. @@ -330,7 +308,6 @@ gcal_timer_set_callback (GcalTimer *self, (GDestroyNotify) timer_func_destroy_notify_wrapper); } - /** * gcal_timer_free: * @self: The #GcalTimer. diff --git a/src/gcal-timer.h b/src/gcal-timer.h index 322d616f..8caabe28 100644 --- a/src/gcal-timer.h +++ b/src/gcal-timer.h @@ -28,27 +28,27 @@ typedef struct _GcalTimer GcalTimer; typedef void (*GCalTimerFunc) (GcalTimer *self, gpointer data); -GcalTimer* gcal_timer_new (gint64 default_duration); +GcalTimer* gcal_timer_new (gint64 default_duration); -void gcal_timer_start (GcalTimer *self); +void gcal_timer_start (GcalTimer *self); -void gcal_timer_reset (GcalTimer *self); +void gcal_timer_reset (GcalTimer *self); -void gcal_timer_stop (GcalTimer *self); +void gcal_timer_stop (GcalTimer *self); -gboolean gcal_timer_is_running (GcalTimer *self); +gboolean gcal_timer_is_running (GcalTimer *self); -void gcal_timer_set_default_duration (GcalTimer *self, - gint64 duration); +void gcal_timer_set_default_duration (GcalTimer *self, + gint64 duration); -gint64 gcal_timer_get_default_duration (GcalTimer *self); +gint64 gcal_timer_get_default_duration (GcalTimer *self); -void gcal_timer_set_callback (GcalTimer *self, - GCalTimerFunc func, - gpointer data, - GDestroyNotify notify); +void gcal_timer_set_callback (GcalTimer *self, + GCalTimerFunc func, + gpointer data, + GDestroyNotify notify); -void gcal_timer_free (GcalTimer *self); +void gcal_timer_free (GcalTimer *self); #endif /* __GCAL_TIMER_H__ */ diff --git a/src/gcal-utils.h b/src/gcal-utils.h index 2b2675ac..a7b19561 100644 --- a/src/gcal-utils.h +++ b/src/gcal-utils.h @@ -70,99 +70,100 @@ typedef enum GCAL_WEEK_DAY_SATURDAY = 1 << 6 } GcalWeekDay; -GType icaltime_get_type (void) G_GNUC_CONST; +GType icaltime_get_type (void) G_GNUC_CONST; -gint datetime_compare_date (GDateTime *dt1, - GDateTime *dt2); +gint datetime_compare_date (GDateTime *dt1, + GDateTime *dt2); -icaltimetype* datetime_to_icaltime (GDateTime *dt); +icaltimetype* datetime_to_icaltime (GDateTime *dt); -gboolean datetime_is_date (GDateTime *dt); +gboolean datetime_is_date (GDateTime *dt); -GDateTime* icaltime_to_datetime (const icaltimetype *date); +GDateTime* icaltime_to_datetime (const icaltimetype *date); -icaltimetype* gcal_dup_icaltime (const icaltimetype *date); +icaltimetype* gcal_dup_icaltime (const icaltimetype *date); -gchar* gcal_get_weekday (gint i); +gchar* gcal_get_weekday (gint i); -gchar* gcal_get_month_name (gint i); +gchar* gcal_get_month_name (gint i); -cairo_surface_t*gcal_get_surface_from_color (GdkRGBA *color, - gint size); +cairo_surface_t* gcal_get_surface_from_color (GdkRGBA *color, + gint size); -cairo_surface_t*get_circle_surface_from_color (GdkRGBA *color, - gint size); +cairo_surface_t* get_circle_surface_from_color (GdkRGBA *color, + gint size); -void get_color_name_from_source (ESource *source, - GdkRGBA *out_color); +void get_color_name_from_source (ESource *source, + GdkRGBA *out_color); -gchar* get_desc_from_component (ECalComponent *component, - const gchar *joint_char); +gchar* get_desc_from_component (ECalComponent *component, + const gchar *joint_char); -gchar* get_uuid_from_component (ESource *source, - ECalComponent *component); +gchar* get_uuid_from_component (ESource *source, + ECalComponent *component); -gint get_first_weekday (void); +gint get_first_weekday (void); -ECalComponent* build_component_from_details (const gchar *summary, - GDateTime *initial_date, - GDateTime *final_date); +ECalComponent* build_component_from_details (const gchar *summary, + GDateTime *initial_date, + GDateTime *final_date); -gint icaltime_compare_date (const icaltimetype *date1, - const icaltimetype *date2); +gint icaltime_compare_date (const icaltimetype *date1, + const icaltimetype *date2); -gint icaltime_compare_with_current (const icaltimetype *date1, - const icaltimetype *date2, - time_t *current_time_t); +gint icaltime_compare_with_current (const icaltimetype *date1, + const icaltimetype *date2, + time_t *current_time_t); -GDateTime* get_start_of_week (icaltimetype *date); +GDateTime* get_start_of_week (icaltimetype *date); -GDateTime* get_end_of_week (icaltimetype *date); +GDateTime* get_end_of_week (icaltimetype *date); -gboolean is_clock_format_24h (void); +gboolean is_clock_format_24h (void); /* code brought from evolution */ -gsize e_strftime_fix_am_pm (gchar *str, - gsize max, - const gchar *fmt, - const struct tm *tm); -gsize e_utf8_strftime_fix_am_pm (gchar *str, +gsize e_strftime_fix_am_pm (gchar *str, + gsize max, + const gchar *fmt, + const struct tm *tm); - gsize max, - const gchar *fmt, - const struct tm *tm); +gsize e_utf8_strftime_fix_am_pm (gchar *str, + gsize max, + const gchar *fmt, + const struct tm *tm); -void fix_popover_menu_icons (GtkPopover *popover); +void fix_popover_menu_icons (GtkPopover *popover); -void get_source_parent_name_color (GcalManager *manager, - ESource *source, - gchar **name, - gchar **color); -gchar* format_utc_offset (gint64 offset); +void get_source_parent_name_color (GcalManager *manager, + ESource *source, + gchar **name, + gchar **color); -gint get_alarm_trigger_minutes (GcalEvent *event, - ECalComponentAlarm *alarm); +gchar* format_utc_offset (gint64 offset); -gboolean should_change_date_for_scroll (gdouble *scroll_value, - GdkEventScroll *scroll_event); +gint get_alarm_trigger_minutes (GcalEvent *event, + ECalComponentAlarm *alarm); -gboolean is_source_enabled (ESource *source); +gboolean should_change_date_for_scroll (gdouble *scroll_value, + GdkEventScroll *scroll_event); -gboolean ask_recurrence_modification_type (GtkWidget *parent, - GcalRecurrenceModType *modtype, - ESource *source); +gboolean is_source_enabled (ESource *source); -gboolean is_workday (guint day); +gboolean ask_recurrence_modification_type (GtkWidget *parent, + GcalRecurrenceModType *modtype, + ESource *source); -GList* filter_event_list_by_uid_and_modtype (GList *widgets, - GcalRecurrenceModType mod, - const gchar *uid); +gboolean is_workday (guint day); -gboolean gcal_translate_child_window_position (GtkWidget *target, - GdkWindow *child_window, - gdouble src_x, - gdouble src_y, - gdouble *real_x, - gdouble *real_y); +GList* filter_event_list_by_uid_and_modtype (GList *widgets, + GcalRecurrenceModType mod, + const gchar *uid); + +gboolean gcal_translate_child_window_position (GtkWidget *target, + GdkWindow *child_window, + gdouble src_x, + gdouble src_y, + gdouble *real_x, + gdouble *real_y); #endif /* __GCAL_UTILS_H__ */ diff --git a/src/gcal-weather-info.c b/src/gcal-weather-info.c index a85353a1..2c8ef9f0 100644 --- a/src/gcal-weather-info.c +++ b/src/gcal-weather-info.c @@ -21,15 +21,6 @@ #include <string.h> #include "gcal-weather-info.h" -static void gcal_weather_info_set_date (GcalWeatherInfo *self, - GDate *date); - -static void gcal_weather_info_set_temperature (GcalWeatherInfo *self, - const gchar *temperature); - -static void gcal_weather_info_set_icon_name (GcalWeatherInfo *self, - const gchar *icon_name); - /* _GcalWeatherInfo: * @date: (not nullable): The day this information belongs to. @@ -51,6 +42,15 @@ struct _GcalWeatherInfo { }; +static void gcal_weather_info_set_date (GcalWeatherInfo *self, + GDate *date); + +static void gcal_weather_info_set_temperature (GcalWeatherInfo *self, + const gchar *temperature); + +static void gcal_weather_info_set_icon_name (GcalWeatherInfo *self, + const gchar *icon_name); + G_DEFINE_TYPE (GcalWeatherInfo, gcal_weather_info, G_TYPE_OBJECT) enum { @@ -79,8 +79,6 @@ gcal_weather_info_finalize (GObject *object) G_OBJECT_CLASS (gcal_weather_info_parent_class)->finalize (object); } - - static void gcal_weather_info_get_property (GObject *object, guint property_id, @@ -107,8 +105,6 @@ gcal_weather_info_get_property (GObject *object, } } - - static void gcal_weather_info_set_property (GObject *object, guint property_id, @@ -138,8 +134,6 @@ gcal_weather_info_set_property (GObject *object, } } - - static void gcal_weather_info_class_init (GcalWeatherInfoClass *klass) { @@ -185,8 +179,6 @@ gcal_weather_info_class_init (GcalWeatherInfoClass *klass) G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); } - - static void gcal_weather_info_init (GcalWeatherInfo *self) { @@ -215,8 +207,6 @@ gcal_weather_info_set_date (GcalWeatherInfo *self, self->date = *date; } - - /* gcal_weather_info_set_temperature: * @self: A #GcalWeatherInfo instance. * @temperature: A weather string. @@ -238,9 +228,7 @@ gcal_weather_info_set_temperature (GcalWeatherInfo *self, } } - - -/* gcal_weather_info_set_icon_name: +/* gcal_weather_info_set_icon_name: * @self: A #GcalWeatherInfo instance. * @icon_name: The name of the icon to display. * @@ -262,6 +250,7 @@ gcal_weather_info_set_icon_name (GcalWeatherInfo *self, } + /* < public > */ /** @@ -293,8 +282,6 @@ gcal_weather_info_new (GDate *date, return info; } - - /** * gcal_weather_info_get_date: * @self: A #GcalWeatherInfo instance. @@ -311,8 +298,6 @@ gcal_weather_info_get_date (GcalWeatherInfo *self, *date = self->date; } - - /** * gcal_weather_info_get_icon_name: * @self: A #GcalWeatherInfo instance. @@ -327,8 +312,6 @@ gcal_weather_info_get_icon_name (GcalWeatherInfo *self) return self->icon_name; } - - /** * gcal_weather_info_get_temperature: * @self: A #GcalWeatherInfo instance. diff --git a/src/gcal-weather-info.h b/src/gcal-weather-info.h index d2e73447..35655e2e 100644 --- a/src/gcal-weather-info.h +++ b/src/gcal-weather-info.h @@ -30,19 +30,19 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (GcalWeatherInfo, gcal_weather_info, GCAL, WEATHER_INFO, GObject) -GcalWeatherInfo* gcal_weather_info_new (GDate *date, - const gchar *icon_name, - const gchar *temperature); +GcalWeatherInfo* gcal_weather_info_new (GDate *date, + const gchar *icon_name, + const gchar *temperature); -void gcal_weather_info_get_date (GcalWeatherInfo *self, - GDate *date); +void gcal_weather_info_get_date (GcalWeatherInfo *self, + GDate *date); -void gcal_weather_info_get_date (GcalWeatherInfo *self, - GDate *date); +void gcal_weather_info_get_date (GcalWeatherInfo *self, + GDate *date); -const gchar* gcal_weather_info_get_icon_name (GcalWeatherInfo *self); +const gchar* gcal_weather_info_get_icon_name (GcalWeatherInfo *self); -const gchar* gcal_weather_info_get_temperature (GcalWeatherInfo *self); +const gchar* gcal_weather_info_get_temperature (GcalWeatherInfo *self); G_END_DECLS diff --git a/src/gcal-weather-service.c b/src/gcal-weather-service.c index 6bc76fbc..aa39598c 100644 --- a/src/gcal-weather-service.c +++ b/src/gcal-weather-service.c @@ -37,8 +37,8 @@ G_BEGIN_DECLS */ typedef struct { - gchar *name; - gboolean night_support; + gchar *name; + gboolean night_support; } GcalWeatherIconInfo; @@ -73,149 +73,151 @@ typedef struct */ struct _GcalWeatherService { - GObjectClass parent; + GObjectClass parent; /* <public> */ /* <private> */ - GTimeZone *time_zone; /* owned, nullable */ + GTimeZone *time_zone; /* owned, nullable */ /* timer: */ - guint check_interval_new; - guint check_interval_renew; - GcalTimer *duration_timer; - GcalTimer *midnight_timer; + guint check_interval_new; + guint check_interval_renew; + GcalTimer *duration_timer; + GcalTimer *midnight_timer; /* network monitoring */ - gulong network_changed_sid; + gulong network_changed_sid; /* locations: */ - GClueSimple *location_service; /* owned, nullable */ - GCancellable *location_cancellable; /* owned, non-null */ - gboolean location_service_running; + GClueSimple *location_service; /* owned, nullable */ + GCancellable *location_cancellable; /* owned, non-null */ + gboolean location_service_running; /* weather: */ - GSList *weather_infos; /* owned[owned] */ - gint64 weather_infos_upated; - gint64 valid_timespan; - GWeatherInfo *gweather_info; /* owned, nullable */ - guint max_days; - gboolean weather_service_running; + GSList *weather_infos; /* owned[owned] */ + gint64 weather_infos_upated; + gint64 valid_timespan; + GWeatherInfo *gweather_info; /* owned, nullable */ + guint max_days; + gboolean weather_service_running; }; +/* Auxiliary methods: */ +static void on_network_change (GNetworkMonitor *monitor, + gboolean available, + GcalWeatherService *self); -enum -{ - PROP_0, - PROP_MAX_DAYS, - PROP_TIME_ZONE, - PROP_CHECK_INTERVAL_NEW, - PROP_CHECK_INTERVAL_RENEW, - PROP_VALID_TIMESPAN, - PROP_NUM, -}; +static void on_gclue_simple_creation (GClueSimple *source, + GAsyncResult *result, + GcalWeatherService *data); -enum -{ - SIG_WEATHER_CHANGED, - SIG_NUM, -}; +static void on_gclue_location_changed (GClueLocation *location, + GcalWeatherService *self); -static guint gcal_weather_service_signals[SIG_NUM] = { 0 }; +static void on_gclue_client_activity_changed (GClueClient *client, + GcalWeatherService *self); +static void on_gclue_client_stop (GClueClient *client, + GAsyncResult *res, + GClueSimple *simple); -G_DEFINE_TYPE (GcalWeatherService, gcal_weather_service, G_TYPE_OBJECT) +static void on_gweather_update (GWeatherInfo *info, + GcalWeatherService *self); +static void on_duration_timer_timeout (GcalTimer *timer, + GcalWeatherService *self); -/* Timer Helpers: */ -static void update_timeout_interval (GcalWeatherService *self); +static void on_midnight_timer_timeout (GcalTimer *timer, + GcalWeatherService *self); -static void schedule_midnight (GcalWeatherService *self); -static void start_timer (GcalWeatherService *self); +/* Timer Helpers: */ +static void update_timeout_interval (GcalWeatherService *self); + +static void schedule_midnight (GcalWeatherService *self); -static void stop_timer (GcalWeatherService *self); +static void start_timer (GcalWeatherService *self); -static void on_network_change (GNetworkMonitor *monitor, - gboolean available, - GcalWeatherService *self); +static void stop_timer (GcalWeatherService *self); /* Internal location API and callbacks: */ -static void gcal_weather_service_update_location (GcalWeatherService *self, - GWeatherLocation *location); -static void gcal_weather_service_update_gclue_location (GcalWeatherService *self, - GClueLocation *location); +static void update_location (GcalWeatherService *self, + GWeatherLocation *location); -static void on_gclue_simple_creation (GClueSimple *source, - GAsyncResult *result, - GcalWeatherService *data); +static void update_gclue_location (GcalWeatherService *self, + GClueLocation *location); -static void on_gclue_location_changed (GClueLocation *location, - GcalWeatherService *self); -static void on_gclue_client_activity_changed (GClueClient *client, - GcalWeatherService *self); +/* Internal Weather API */ +static void set_max_days (GcalWeatherService *self, + guint days); -static void on_gclue_client_stop (GClueClient *client, - GAsyncResult *res, - GClueSimple *simple); +static void set_valid_timespan (GcalWeatherService *self, + gint64 timespan); -/* Internal Weather API */ -static void gcal_weather_service_set_max_days (GcalWeatherService *self, - guint days); +static gboolean has_valid_weather_infos (GcalWeatherService *self); -static void gcal_weather_service_set_valid_timespan (GcalWeatherService *self, - gint64 timespan); +static void update_weather (GcalWeatherService *self, + GWeatherInfo *info, + gboolean reuse_old_on_error); -static gboolean has_valid_weather_infos (GcalWeatherService *self); -static void gcal_weather_service_update_weather (GcalWeatherService *self, - GWeatherInfo *info, - gboolean reuse_old_on_error); +/* Internal weather update API and callbacks */ +static void set_check_interval_new (GcalWeatherService *self, + guint check_interval); -static void on_gweather_update (GWeatherInfo *info, - GcalWeatherService *self); +static void set_check_interval_renew (GcalWeatherService *self, + guint check_interval); -/* Internal weather update timer API and callbacks */ -static void gcal_weather_service_set_check_interval_new (GcalWeatherService *self, - guint check_interval); +static gssize get_normalized_icon_name_len (const gchar *str); -static void gcal_weather_service_set_check_interval_renew (GcalWeatherService *self, - guint check_interval); +static gchar* get_normalized_icon_name (GWeatherInfo *gwi, + gboolean is_night_icon); -static gssize get_normalized_icon_name_len (const gchar *str); +static gint get_icon_name_sortkey (const gchar *icon_name, + gboolean *supports_night_icon); -static gchar* get_normalized_icon_name (GWeatherInfo *gwi, - gboolean is_night_icon); +static gboolean get_time_day_start (GcalWeatherService *self, + GDate *ret_date, + gint64 *ret_unix, + gint64 *ret_unix_exact); -static gint get_icon_name_sortkey (const gchar *icon_name, - gboolean *supports_night_icon); +static inline gboolean get_gweather_temperature (GWeatherInfo *gwi, + gdouble *temp); -static void on_duration_timer_timeout (GcalTimer *timer, - GcalWeatherService *self); +static gboolean compute_weather_info_data (GSList *samples, + gboolean is_today, + gchar **icon_name, + gchar **temperature); -static void on_midnight_timer_timeout (GcalTimer *timer, - GcalWeatherService *self); +static GSList* preprocess_gweather_reports (GcalWeatherService *self, + GSList *samples); -static gboolean get_time_day_start (GcalWeatherService *self, - GDate *ret_date, - gint64 *ret_unix, - gint64 *ret_unix_exact); -static inline gboolean get_gweather_temperature (GWeatherInfo *gwi, - gdouble *temp); +G_DEFINE_TYPE (GcalWeatherService, gcal_weather_service, G_TYPE_OBJECT) -static gboolean compute_weather_info_data (GSList *samples, - gboolean is_today, - gchar **icon_name, - gchar **temperature); +enum +{ + PROP_0, + PROP_MAX_DAYS, + PROP_TIME_ZONE, + PROP_CHECK_INTERVAL_NEW, + PROP_CHECK_INTERVAL_RENEW, + PROP_VALID_TIMESPAN, + PROP_NUM, +}; -static GSList* preprocess_gweather_reports (GcalWeatherService *self, - GSList *samples); +enum +{ + SIG_WEATHER_CHANGED, + SIG_NUM, +}; +static guint gcal_weather_service_signals[SIG_NUM] = { 0 }; G_END_DECLS @@ -265,8 +267,6 @@ gcal_weather_service_finalize (GObject *object) G_OBJECT_CLASS (gcal_weather_service_parent_class)->finalize (object); } - - static void gcal_weather_service_get_property (GObject *object, guint prop_id, @@ -299,8 +299,6 @@ gcal_weather_service_get_property (GObject *object, } } - - static void gcal_weather_service_set_property (GObject *object, guint prop_id, @@ -313,19 +311,19 @@ gcal_weather_service_set_property (GObject *object, switch (prop_id) { case PROP_MAX_DAYS: - gcal_weather_service_set_max_days (self, g_value_get_uint (value)); + set_max_days (self, g_value_get_uint (value)); break; case PROP_TIME_ZONE: gcal_weather_service_set_time_zone (self, g_value_get_pointer (value)); break; case PROP_CHECK_INTERVAL_NEW: - gcal_weather_service_set_check_interval_new (self, g_value_get_uint (value)); + set_check_interval_new (self, g_value_get_uint (value)); break; case PROP_CHECK_INTERVAL_RENEW: - gcal_weather_service_set_check_interval_renew (self, g_value_get_uint (value)); + set_check_interval_renew (self, g_value_get_uint (value)); break; case PROP_VALID_TIMESPAN: - gcal_weather_service_set_valid_timespan (self, g_value_get_int64 (value)); + set_valid_timespan (self, g_value_get_int64 (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -333,8 +331,6 @@ gcal_weather_service_set_property (GObject *object, } } - - static void gcal_weather_service_class_init (GcalWeatherServiceClass *klass) { @@ -428,8 +424,6 @@ gcal_weather_service_class_init (GcalWeatherServiceClass *klass) 0); } - - static void gcal_weather_service_init (GcalWeatherService *self) { @@ -459,46 +453,6 @@ gcal_weather_service_init (GcalWeatherService *self) self); } - - -/* drop_suffix: - * @str: A icon name to normalize. - * - * Translates a given weather icon name to the - * one to display for folded weather reports. - * - * Returns: Number of initial characters that - * belong to the normalized name. - */ -static gssize -get_normalized_icon_name_len (const gchar *str) -{ - const gchar suffix1[] = "-symbolic"; - const gssize suffix1_len = G_N_ELEMENTS (suffix1) - 1; - - const gchar suffix2[] = "-night"; - const gssize suffix2_len = G_N_ELEMENTS (suffix2) - 1; - - gssize clean_len; - gssize str_len; - - g_return_val_if_fail (str != NULL, -1); - - str_len = strlen (str); - - clean_len = str_len - suffix1_len; - if (clean_len >= 0 && memcmp (suffix1, str + clean_len, suffix1_len) == 0) - str_len = clean_len; - - clean_len = str_len - suffix2_len; - if (clean_len >= 0 && memcmp (suffix2, str + clean_len, suffix2_len) == 0) - str_len = clean_len; - - return str_len; -} - - - /* get_normalized_icon_name: * @str: A icon name to normalize. * @@ -556,495 +510,48 @@ get_normalized_icon_name (GWeatherInfo* wi, } - -/* get_icon_name_sortkey: - * - * Returns a sort key for a given weather - * icon name and -1 for unknown ones. - * - * The lower the key, the better the weather. - */ -static gint -get_icon_name_sortkey (const gchar *icon_name, - gboolean *supports_night_icon) -{ - /* Note that we can't use gweathers condition - * field as it is not necessarily holds valid values. - * libgweather uses its own heuristic to determine - * the icon to use. String matching is still better - * than copying their algorithm, I guess. - */ - - gssize normalized_name_len; - - const GcalWeatherIconInfo icons[] = - { {"weather-clear", TRUE}, - {"weather-few-clouds", TRUE}, - {"weather-overcast", FALSE}, - {"weather-fog", FALSE}, - {"weather-showers-scattered", FALSE}, - {"weather-showers", FALSE}, - {"weather-snow", FALSE}, - {"weather-storm", FALSE}, - {"weather-severe-alert", FALSE} - }; - - g_return_val_if_fail (icon_name != NULL, -1); - g_return_val_if_fail (supports_night_icon != NULL, -1); - - *supports_night_icon = FALSE; - - normalized_name_len = get_normalized_icon_name_len (icon_name); - g_return_val_if_fail (normalized_name_len >= 0, -1); - - for (int i = 0; i < G_N_ELEMENTS (icons); i++) - { - if (icons[i].name[normalized_name_len] == '\0' && strncmp (icon_name, icons[i].name, normalized_name_len) == 0) - { - *supports_night_icon = icons[i].night_support; - return i; - } - } - - g_warning ("Unknown weather icon '%s'", icon_name); - - return -1; -} - - - /************** * < private > **************/ -#if PRINT_WEATHER_DATA -static gchar* -gwc2str (GWeatherInfo *gwi) -{ - g_autoptr (GDateTime) date = NULL; - g_autofree gchar *date_str = NULL; - glong update; - - gchar *icon_name; /* unowned */ - gdouble temp; - - if (!gweather_info_get_value_update (gwi, &update)) - return g_strdup ("<null>"); - - date = g_date_time_new_from_unix_local (update); - date_str = g_date_time_format (date, "%F %T"), - - get_gweather_temperature (gwi, &temp); - icon_name = gweather_info_get_symbolic_icon_name (gwi); - - return g_strdup_printf ("(%s: t:%f, w:%s)", - date_str, - temp, - icon_name); -} -#endif - - - -/* get_time_day_start: - * @self: The #GcalWeatherService instance. - * @date: (out) (not nullable): A #GDate that should be set to today. - * @unix: (out) (not nullable): A UNIX time stamp that should be set to today. - * @ret_unix_exact (out) (not nullable): The exact date time this data point predicts. - * - * Provides current date in two different forms. - * - * Returns: %TRUE on success. - */ -static gboolean -get_time_day_start (GcalWeatherService *self, - GDate *ret_date, - gint64 *ret_unix, - gint64 *ret_unix_exact) -{ - g_autoptr (GTimeZone) zone = NULL; - g_autoptr (GDateTime) now = NULL; - g_autoptr (GDateTime) day = NULL; - - g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (ret_date != NULL, FALSE); - g_return_val_if_fail (ret_unix != NULL, FALSE); - g_return_val_if_fail (ret_unix_exact != NULL, FALSE); - - zone = (self->time_zone == NULL) - ? g_time_zone_new_local () - : g_time_zone_ref (self->time_zone); - - now = g_date_time_new_now (zone); - day = g_date_time_new (zone, - g_date_time_get_year (now), - g_date_time_get_month (now), - g_date_time_get_day_of_month (now), - 0, 0, 0); - - g_date_set_dmy (ret_date, - g_date_time_get_day_of_month (day), - g_date_time_get_month (day), - g_date_time_get_year (day)); - - *ret_unix = g_date_time_to_unix (day); - *ret_unix_exact = g_date_time_to_unix (now); - return TRUE; -} - - - -/* get_gweather_temperature: - * @gwi: #GWeatherInfo to extract temperatures from. - * @temp: (out): extracted temperature or %NAN. - * - * Returns sanitized temperatures. Returned values should only - * be used as sort key. - * - * Returns: %TRUE for valid temperatures. - */ -static inline gboolean -get_gweather_temperature (GWeatherInfo *gwi, - gdouble *temp) -{ - gboolean valid; - gdouble value; - - *temp = NAN; - - g_return_val_if_fail (gwi != NULL, FALSE); - g_return_val_if_fail (temp != NULL, FALSE); - - valid = gweather_info_get_value_temp (gwi, - GWEATHER_TEMP_UNIT_DEFAULT, - &value); - - /* TODO: Extract temperatures in Celsius and catch - * implausible cases. - */ - if (valid) - { - *temp = value; - return TRUE; - } - else - { - *temp = NAN; - return FALSE; - } -} - - - -/* compute_weather_info_data: - * @samples: List of received #GWeatherInfos. - * @icon_name: (out): (transfer full): weather icon name or %NULL. - * @temperature: (out): (transfer full): temperature and unit or %NULL. - * - * Computes a icon name and temperature representing @samples. - * - * Returns: %TRUE if there is a valid icon name and temperature. - */ -static gboolean -compute_weather_info_data (GSList *samples, - gboolean is_today, - gchar **icon_name, - gchar **temperature) -{ - gboolean phenomenon_supports_night_icon = FALSE; - gint phenomenon_val = -1; - GWeatherInfo *phenomenon_gwi = NULL; /* unowned */ - gdouble temp_val = NAN; - GWeatherInfo *temp_gwi = NULL; /* unowned */ - gboolean has_daytime = FALSE; - GSList *iter; /* unowned */ - - /* Note: I checked three different gweather consumers - * and they all pick different values. So here is my - * take: I pick up the worst weather for icons and - * the highest temperature. I basically want to know - * whether I need my umbrella for my appointment. - * Not sure about the right temperature. It is probably - * better to pick-up the median of all predictions - * during daytime. - */ - - g_return_val_if_fail (icon_name != NULL, FALSE); - g_return_val_if_fail (temperature != NULL, FALSE); - - for (iter = samples; iter != NULL; iter = iter->next) - { - GWeatherInfo *gwi; /* unowned */ - const gchar *icon_name; /* unowned */ - gint phenomenon = -1; - gboolean supports_night_icon; - gdouble temp; - gboolean valid_temp; - - gwi = GWEATHER_INFO (iter->data); - - icon_name = gweather_info_get_icon_name (gwi); - if (icon_name != NULL) - phenomenon = get_icon_name_sortkey (icon_name, &supports_night_icon); - - valid_temp = get_gweather_temperature (gwi, &temp); - - if (phenomenon >= 0 && (phenomenon_gwi == NULL || phenomenon > phenomenon_val)) - { - phenomenon_supports_night_icon = supports_night_icon; - phenomenon_val = phenomenon; - phenomenon_gwi = gwi; - } - - if (valid_temp && (temp_gwi == NULL || temp > temp_val)) - { - temp_val = temp; - temp_gwi = gwi; - } - - if (gweather_info_is_daytime (gwi)) - has_daytime = TRUE; - } - - if (phenomenon_gwi != NULL && temp_gwi != NULL) - { - *icon_name = get_normalized_icon_name (phenomenon_gwi, is_today && !has_daytime && phenomenon_supports_night_icon); - *temperature = gweather_info_get_temp (temp_gwi); - return TRUE; - } - else - { - /* empty list */ - *icon_name = NULL; - *temperature = NULL; - return FALSE; - } -} - - - -/* preprocess_gweather_reports: - * @self: The #GcalWeatherService instance. - * @samples: Received list of #GWeatherInfos - * - * Computes weather info objects representing specific days - * by combining given #GWeatherInfos. - * - * Returns: (transfer full): List of up to $self->max_days #GcalWeatherInfos. +/* + * Auxiliary methods: */ -static GSList* -preprocess_gweather_reports (GcalWeatherService *self, - GSList *samples) -{ - const glong DAY_SECONDS = 24*60*60; - GSList *result = NULL; /* owned[owned] */ - GSList **days; /* owned[owned[unowned]] */ - GSList *iter; /* unowned */ - GDate cur_gdate; - glong today_unix; - glong unix_now; - - GWeatherInfo *first_tomorrow = NULL; /* unowned */ - glong first_tomorrow_dtime = -1; - - g_return_val_if_fail (GCAL_IS_WEATHER_SERVICE (self), NULL); - - /* This function basically separates samples by - * date and calls compute_weather_info_data for - * every bucket to build weather infos. - * Each bucket represents a single day. - */ - /* All gweather consumers I reviewed presume - * sorted samples. However, there is no documented - * order. Lets assume the worst. - */ - - if (self->max_days <= 0) - return NULL; - - if (!get_time_day_start (self, &cur_gdate, &today_unix, &unix_now)) - return NULL; - - days = g_malloc0 (sizeof (GSList*) * self->max_days); - - /* Split samples to max_days buckets: */ - for (iter = samples; iter != NULL; iter = iter->next) - { - GWeatherInfo *gwi; /* unowned */ - gboolean valid_date; - glong gwi_dtime; - gsize bucket; - - gwi = GWEATHER_INFO (iter->data); - valid_date = gweather_info_get_value_update (gwi, &gwi_dtime); - if (!valid_date) - continue; - - #if PRINT_WEATHER_DATA - { - g_autofree gchar* dbg_str = gwc2str (gwi); - g_message ("WEATHER READING POINT: %s", dbg_str); - } - #endif - - if (gwi_dtime >= 0 && gwi_dtime >= today_unix) - { - bucket = (gwi_dtime - today_unix) / DAY_SECONDS; - if (bucket >= 0 && bucket < self->max_days) - days[bucket] = g_slist_prepend (days[bucket], gwi); - - if (bucket == 1 && (first_tomorrow == NULL || first_tomorrow_dtime > gwi_dtime)) - { - first_tomorrow_dtime = gwi_dtime; - first_tomorrow = gwi; - } - } - else - { - g_debug ("Encountered historic weather information"); - } - } - - if (days[0] == NULL && first_tomorrow != NULL) - { - /* There is no data point left for today. - * Lets borrow one. - */ - glong secs_left_today; - glong secs_between; - - secs_left_today = DAY_SECONDS - (unix_now - today_unix); - secs_between = first_tomorrow_dtime - unix_now; - - if (secs_left_today < 90*60 && secs_between <= 180*60) - days[0] = g_slist_prepend (days[0], first_tomorrow); - } - - /* Produce GcalWeatherInfo for each bucket: */ - for (int i = 0; i < self->max_days; i++) - { - g_autofree gchar *icon_name; - g_autofree gchar *temperature; - - if (compute_weather_info_data (days[i], i == 0, &icon_name, &temperature)) - { - GcalWeatherInfo* gcwi; /* owned */ - - gcwi = gcal_weather_info_new (&cur_gdate, - icon_name, - temperature); - - result = g_slist_prepend (result, - g_steal_pointer (&gcwi)); - } - - g_date_add_days (&cur_gdate, 1); - } - - /* Cleanup: */ - for (int i = 0; i < self->max_days; i++) - g_slist_free (days[i]); - g_free (days); - - return result; -} - - - -/** - * gcal_weather_service_update_location: - * @self: The #GcalWeatherService instance. - * @location: (nullable): The location we want weather information for. +/* on_network_change: + * @monitor: The emitting #GNetworkMonitor + * @available: The current value of “network-available” + * @self: The #GcalWeatherService instance. * - * Registers the location to retrieve weather information from. + * Starts and stops timer based on monitored network + * changes. */ static void -gcal_weather_service_update_location (GcalWeatherService *self, - GWeatherLocation *location) +on_network_change (GNetworkMonitor *monitor, + gboolean available, + GcalWeatherService *self) { - g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); + gboolean is_running; - if (gcal_timer_is_running (self->duration_timer)) - stop_timer (self); + g_return_if_fail (G_IS_NETWORK_MONITOR (monitor)); + g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); - if (self->gweather_info != NULL) - g_clear_object (&self->gweather_info); + g_debug ("network changed, available = %d", available); - if (location == NULL) - { - g_debug ("Could not retrieve current location"); - gcal_weather_service_update_weather (self, NULL, FALSE); - } - else + is_running = gcal_timer_is_running (self->duration_timer); + if (available && !is_running) { - g_debug ("Got new weather service location: '%s'", - (location == NULL)? "<null>" : gweather_location_get_name (location)); - - self->gweather_info = gweather_info_new (location, GWEATHER_FORECAST_ZONE | GWEATHER_FORECAST_LIST); - - /* NOTE: We do not get detailed infos for GWEATHER_PROVIDER_ALL. - * This combination works fine, though. We should open a bug / investigate - * what is going on. - */ - gweather_info_set_enabled_providers (self->gweather_info, GWEATHER_PROVIDER_METAR | GWEATHER_PROVIDER_OWM | GWEATHER_PROVIDER_YR_NO); - g_signal_connect (self->gweather_info, "updated", (GCallback) on_gweather_update, self); - - /* gweather_info_update might or might not trigger a - * GWeatherInfo::update() signal. Therefore, we have to - * remove weather information before querying new one. - * This might result in icon flickering on screen. - * We probably want to introduce a "unknown" or "loading" - * state in gweather-info to soften the effect. - */ - gcal_weather_service_update_weather (self, NULL, FALSE); - gweather_info_update (self->gweather_info); + if (self->gweather_info != NULL) + gweather_info_update (self->gweather_info); start_timer (self); } -} - - - -/** - * gcal_weather_service_update_gclue_location: - * @self: The #GcalWeatherService instance. - * @location: (nullable): The location we want weather information for. - * - * Registers the location to retrieve weather information from. - */ -static void -gcal_weather_service_update_gclue_location (GcalWeatherService *self, - GClueLocation *location) -{ - GWeatherLocation *wlocation = NULL; /* owned */ - - g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); - g_return_if_fail (location == NULL || GCLUE_IS_LOCATION (location)); - - if (location != NULL) + else if (!available && is_running) { - GWeatherLocation *wworld; /* unowned */ - gdouble latitude; - gdouble longitude; - - latitude = gclue_location_get_latitude (location); - longitude = gclue_location_get_longitude (location); - - /* nearest-city works more closely to gnome weather. */ - wworld = gweather_location_get_world (); - wlocation = gweather_location_find_nearest_city (wworld, latitude, longitude); + stop_timer (self); } - - - gcal_weather_service_update_location (self, wlocation); - - if (wlocation != NULL) - gweather_location_unref (wlocation); } - - /* on_gclue_simple_creation: * @source: * @result: Result of gclue_simple_new(). @@ -1092,7 +599,7 @@ on_gclue_simple_creation (GClueSimple *_source, if (location != NULL) { - gcal_weather_service_update_gclue_location (self, location); + update_gclue_location (self, location); g_signal_connect_object (location, "notify::location", @@ -1110,7 +617,6 @@ on_gclue_simple_creation (GClueSimple *_source, g_object_unref (self); } - /* on_gclue_location_changed: * @location: #GClueLocation owned by @self * @self: The #GcalWeatherService @@ -1124,11 +630,9 @@ on_gclue_location_changed (GClueLocation *location, g_return_if_fail (GCLUE_IS_LOCATION (location)); g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); - gcal_weather_service_update_gclue_location (self, location); + update_gclue_location (self, location); } - - /* on_gclue_client_activity_changed: * @client: The #GClueclient ownd by @self * @self: The #GcalWeatherService @@ -1143,11 +647,9 @@ on_gclue_client_activity_changed (GClueClient *client, g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); /* Notify listeners about unknown locations: */ - gcal_weather_service_update_location (self, NULL); + update_location (self, NULL); } - - /* on_gclue_client_stop: * @source_object: A #GClueClient. * @res: Result of gclue_client_call_stop(). @@ -1178,145 +680,65 @@ on_gclue_client_stop (GClueClient *client, g_object_unref (simple); } - - -/* gcal_weather_service_set_max_days: - * @self: The #GcalWeatherService instance. - * @days: Number of days. - * - * Setter for #GcalWeatherInfos:max-days. - */ -static void -gcal_weather_service_set_max_days (GcalWeatherService *self, - guint days) -{ - g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); - g_return_if_fail (days >= 1); - - self->max_days = days; - - g_object_notify ((GObject*) self, "max-days"); -} - - - -/* gcal_weather_service_set_valid_timespan: +/* on_gweather_update: * @self: A #GcalWeatherService instance. * @timespan: Amount of seconds we consider weather information as valid. + * + * Triggered on weather updates with previously handled or no + * location changes. */ static void -gcal_weather_service_set_valid_timespan (GcalWeatherService *self, - gint64 timespan) +on_gweather_update (GWeatherInfo *info, + GcalWeatherService *self) { g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); - g_return_if_fail (timespan >= 0); - - self->valid_timespan = timespan; + g_return_if_fail (info == NULL || GWEATHER_IS_INFO (info)); - g_object_notify ((GObject*) self, "valid-timespan"); + update_weather (self, info, TRUE); } - - -/* has_valid_weather_infos - * @self: A #GcalWeatherService instance. +/* on_duration_timer_timeout + * @self: A #GcalWeatherService. * - * Checks whether weather information are available - * and up-to-date. + * Handles scheduled weather report updates. */ -static gboolean -has_valid_weather_infos (GcalWeatherService *self) +static void +on_duration_timer_timeout (GcalTimer *timer, + GcalWeatherService *self) { - gint64 now; - - g_return_val_if_fail (GCAL_IS_WEATHER_SERVICE (self), FALSE); - - if (self->gweather_info == NULL || self->weather_infos_upated < 0) - return FALSE; + g_return_if_fail (timer != NULL); + g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); - now = g_get_monotonic_time (); - return (now - self->weather_infos_upated) / 1000000 <= self->valid_timespan; + if (self->gweather_info != NULL) + gweather_info_update (self->gweather_info); } - - -/* gcal_weather_service_update_weather: - * @self: A #GcalWeatherService instance. - * @info: (nullable): Newly received weather information or %NULL. - * @reuse_old_on_error: Whether to re-use old but not outdated weather - * information in case we could not fetch new data. +/* on_midnight_timer_timeout + * @self: A #GcalWeatherService. * - * Retrieves weather information for @location and triggers - * #GcalWeatherService::weather-changed. + * Handles scheduled weather report updates. */ static void -gcal_weather_service_update_weather (GcalWeatherService *self, - GWeatherInfo *info, - gboolean reuse_old_on_error) +on_midnight_timer_timeout (GcalTimer *timer, + GcalWeatherService *self) { - GSList *gwforecast = NULL; /* unowned */ - + g_return_if_fail (timer != NULL); g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); - g_return_if_fail (info == NULL || GWEATHER_IS_INFO (info)); - - /* Compute a list of newly received weather infos. */ - if (info == NULL) - { - g_debug ("Could not retrieve valid weather"); - } - else if (gweather_info_is_valid (info)) - { - g_debug ("Received valid weather information"); - gwforecast = gweather_info_get_forecast_list (info); - } - else - { - g_autofree gchar* location_name = gweather_info_get_location_name (info); - g_debug ("Could not retrieve valid weather for location '%s'", location_name); - } - - if (gwforecast == NULL && self->weather_infos_upated >= 0) - { - if (!reuse_old_on_error || !has_valid_weather_infos (self)) - { - g_slist_free_full (self->weather_infos, g_object_unref); - self->weather_infos = NULL; - self->weather_infos_upated = -1; + if (self->gweather_info != NULL) + gweather_info_update (self->gweather_info); - g_signal_emit (self, gcal_weather_service_signals[SIG_WEATHER_CHANGED], 0); - } - } - else if (gwforecast != NULL) - { - g_slist_free_full (self->weather_infos, g_object_unref); - self->weather_infos = preprocess_gweather_reports (self, gwforecast); - self->weather_infos_upated = g_get_monotonic_time (); + if (gcal_timer_is_running (self->duration_timer)) + gcal_timer_reset (self->duration_timer); - g_signal_emit (self, gcal_weather_service_signals[SIG_WEATHER_CHANGED], 0); - } + schedule_midnight (self); } -/* on_gweather_update: - * @self: A #GcalWeatherService instance. - * @timespan: Amount of seconds we consider weather information as valid. - * - * Triggered on weather updates with previously handled or no - * location changes. +/* + * Intenral timer Helpers: */ -static void -on_gweather_update (GWeatherInfo *info, - GcalWeatherService *self) -{ - g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); - g_return_if_fail (info == NULL || GWEATHER_IS_INFO (info)); - - gcal_weather_service_update_weather (self, info, TRUE); -} - - /* update_timeout_interval: * @self: The #GcalWeatherService instance. @@ -1339,8 +761,6 @@ update_timeout_interval (GcalWeatherService *self) gcal_timer_set_default_duration (self->duration_timer, interval); } - - /* schedule_midnight: * @self: The #GcalWeatherService instance. * @@ -1379,8 +799,6 @@ schedule_midnight (GcalWeatherService *self) real_mid - real_now); } - - /* start_timer: * @self: The #GcalWeatherService instance. * @@ -1404,8 +822,6 @@ start_timer (GcalWeatherService *self) } } - - /* stop_timer: * @self: The #GcalWeatherService instance. * @@ -1421,52 +837,258 @@ stop_timer (GcalWeatherService *self) } +/* + * Internal location API: + */ -/* on_network_change: - * @monitor: The emitting #GNetworkMonitor - * @available: The current value of “network-available” - * @self: The #GcalWeatherService instance. +/** + * update_location: + * @self: The #GcalWeatherService instance. + * @location: (nullable): The location we want weather information for. * - * Starts and stops timer based on monitored network - * changes. + * Registers the location to retrieve weather information from. */ static void -on_network_change (GNetworkMonitor *monitor, - gboolean available, - GcalWeatherService *self) +update_location (GcalWeatherService *self, + GWeatherLocation *location) { - gboolean is_running; - - g_return_if_fail (G_IS_NETWORK_MONITOR (monitor)); g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); - g_debug ("network changed, available = %d", available); + if (gcal_timer_is_running (self->duration_timer)) + stop_timer (self); - is_running = gcal_timer_is_running (self->duration_timer); - if (available && !is_running) + if (self->gweather_info != NULL) + g_clear_object (&self->gweather_info); + + if (location == NULL) { - if (self->gweather_info != NULL) - gweather_info_update (self->gweather_info); + g_debug ("Could not retrieve current location"); + update_weather (self, NULL, FALSE); + } + else + { + g_debug ("Got new weather service location: '%s'", + (location == NULL)? "<null>" : gweather_location_get_name (location)); + + self->gweather_info = gweather_info_new (location, GWEATHER_FORECAST_ZONE | GWEATHER_FORECAST_LIST); + + /* NOTE: We do not get detailed infos for GWEATHER_PROVIDER_ALL. + * This combination works fine, though. We should open a bug / investigate + * what is going on. + */ + gweather_info_set_enabled_providers (self->gweather_info, GWEATHER_PROVIDER_METAR | GWEATHER_PROVIDER_OWM | GWEATHER_PROVIDER_YR_NO); + g_signal_connect (self->gweather_info, "updated", (GCallback) on_gweather_update, self); + + /* gweather_info_update might or might not trigger a + * GWeatherInfo::update() signal. Therefore, we have to + * remove weather information before querying new one. + * This might result in icon flickering on screen. + * We probably want to introduce a "unknown" or "loading" + * state in gweather-info to soften the effect. + */ + update_weather (self, NULL, FALSE); + gweather_info_update (self->gweather_info); start_timer (self); } - else if (!available && is_running) +} + +/** + * update_gclue_location: + * @self: The #GcalWeatherService instance. + * @location: (nullable): The location we want weather information for. + * + * Registers the location to retrieve weather information from. + */ +static void +update_gclue_location (GcalWeatherService *self, + GClueLocation *location) +{ + GWeatherLocation *wlocation = NULL; /* owned */ + + g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); + g_return_if_fail (location == NULL || GCLUE_IS_LOCATION (location)); + + if (location != NULL) { - stop_timer (self); + GWeatherLocation *wworld; /* unowned */ + gdouble latitude; + gdouble longitude; + + latitude = gclue_location_get_latitude (location); + longitude = gclue_location_get_longitude (location); + + /* nearest-city works more closely to gnome weather. */ + wworld = gweather_location_get_world (); + wlocation = gweather_location_find_nearest_city (wworld, latitude, longitude); + } + + + update_location (self, wlocation); + + if (wlocation != NULL) + gweather_location_unref (wlocation); +} + + + +/* + * Internal Weather API + */ + +#if PRINT_WEATHER_DATA +static gchar* +gwc2str (GWeatherInfo *gwi) +{ + g_autoptr (GDateTime) date = NULL; + g_autofree gchar *date_str = NULL; + glong update; + + gchar *icon_name; /* unowned */ + gdouble temp; + + if (!gweather_info_get_value_update (gwi, &update)) + return g_strdup ("<null>"); + + date = g_date_time_new_from_unix_local (update); + date_str = g_date_time_format (date, "%F %T"), + + get_gweather_temperature (gwi, &temp); + icon_name = gweather_info_get_symbolic_icon_name (gwi); + + return g_strdup_printf ("(%s: t:%f, w:%s)", + date_str, + temp, + icon_name); +} +#endif + +/* set_max_days: + * @self: The #GcalWeatherService instance. + * @days: Number of days. + * + * Setter for #GcalWeatherInfos:max-days. + */ +static void +set_max_days (GcalWeatherService *self, + guint days) +{ + g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); + g_return_if_fail (days >= 1); + + self->max_days = days; + + g_object_notify ((GObject*) self, "max-days"); +} + +/* set_valid_timespan: + * @self: A #GcalWeatherService instance. + * @timespan: Amount of seconds we consider weather information as valid. + */ +static void +set_valid_timespan (GcalWeatherService *self, + gint64 timespan) +{ + g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); + g_return_if_fail (timespan >= 0); + + self->valid_timespan = timespan; + + g_object_notify ((GObject*) self, "valid-timespan"); +} + +/* has_valid_weather_infos + * @self: A #GcalWeatherService instance. + * + * Checks whether weather information are available + * and up-to-date. + */ +static gboolean +has_valid_weather_infos (GcalWeatherService *self) +{ + gint64 now; + + g_return_val_if_fail (GCAL_IS_WEATHER_SERVICE (self), FALSE); + + if (self->gweather_info == NULL || self->weather_infos_upated < 0) + return FALSE; + + now = g_get_monotonic_time (); + return (now - self->weather_infos_upated) / 1000000 <= self->valid_timespan; +} + +/* update_weather: + * @self: A #GcalWeatherService instance. + * @info: (nullable): Newly received weather information or %NULL. + * @reuse_old_on_error: Whether to re-use old but not outdated weather + * information in case we could not fetch new data. + * + * Retrieves weather information for @location and triggers + * #GcalWeatherService::weather-changed. + */ +static void +update_weather (GcalWeatherService *self, + GWeatherInfo *info, + gboolean reuse_old_on_error) +{ + GSList *gwforecast = NULL; /* unowned */ + + g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); + g_return_if_fail (info == NULL || GWEATHER_IS_INFO (info)); + + + /* Compute a list of newly received weather infos. */ + if (info == NULL) + { + g_debug ("Could not retrieve valid weather"); + } + else if (gweather_info_is_valid (info)) + { + g_debug ("Received valid weather information"); + gwforecast = gweather_info_get_forecast_list (info); + } + else + { + g_autofree gchar* location_name = gweather_info_get_location_name (info); + g_debug ("Could not retrieve valid weather for location '%s'", location_name); + } + + if (gwforecast == NULL && self->weather_infos_upated >= 0) + { + if (!reuse_old_on_error || !has_valid_weather_infos (self)) + { + g_slist_free_full (self->weather_infos, g_object_unref); + self->weather_infos = NULL; + self->weather_infos_upated = -1; + + g_signal_emit (self, gcal_weather_service_signals[SIG_WEATHER_CHANGED], 0); + } + } + else if (gwforecast != NULL) + { + g_slist_free_full (self->weather_infos, g_object_unref); + self->weather_infos = preprocess_gweather_reports (self, gwforecast); + self->weather_infos_upated = g_get_monotonic_time (); + + g_signal_emit (self, gcal_weather_service_signals[SIG_WEATHER_CHANGED], 0); } } -/* gcal_weather_service_set_check_interval_new: +/* + * Internal weather update API and callbacks + */ + +/* set_check_interval_new: * @self: The #GcalWeatherService instance. * @days: Number of days. * * Setter for GcalWeatherInfos:check-interval-new. */ static void -gcal_weather_service_set_check_interval_new (GcalWeatherService *self, - guint interval) +set_check_interval_new (GcalWeatherService *self, + guint interval) { g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); g_return_if_fail (interval > 0); @@ -1477,17 +1099,15 @@ gcal_weather_service_set_check_interval_new (GcalWeatherService *self, g_object_notify ((GObject*) self, "check-interval-new"); } - - -/* gcal_weather_service_set_check_interval_renew: +/* set_check_interval_renew: * @self: The #GcalWeatherService instance. * @days: Number of days. * * Setter for GcalWeatherInfos:check-interval-renew. */ static void -gcal_weather_service_set_check_interval_renew (GcalWeatherService *self, - guint interval) +set_check_interval_renew (GcalWeatherService *self, + guint interval) { g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); g_return_if_fail (interval > 0); @@ -1498,201 +1118,426 @@ gcal_weather_service_set_check_interval_renew (GcalWeatherService *self, g_object_notify ((GObject*) self, "check-interval-renew"); } - - -/* on_duration_timer_timeout - * @self: A #GcalWeatherService. +/* drop_suffix: + * @str: A icon name to normalize. * - * Handles scheduled weather report updates. + * Translates a given weather icon name to the + * one to display for folded weather reports. + * + * Returns: Number of initial characters that + * belong to the normalized name. */ -static void -on_duration_timer_timeout (GcalTimer *timer, - GcalWeatherService *self) +static gssize +get_normalized_icon_name_len (const gchar *str) { - g_return_if_fail (timer != NULL); - g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); + const gchar suffix1[] = "-symbolic"; + const gssize suffix1_len = G_N_ELEMENTS (suffix1) - 1; - if (self->gweather_info != NULL) - gweather_info_update (self->gweather_info); -} + const gchar suffix2[] = "-night"; + const gssize suffix2_len = G_N_ELEMENTS (suffix2) - 1; + gssize clean_len; + gssize str_len; + g_return_val_if_fail (str != NULL, -1); -/* on_midnight_timer_timeout - * @self: A #GcalWeatherService. + str_len = strlen (str); + + clean_len = str_len - suffix1_len; + if (clean_len >= 0 && memcmp (suffix1, str + clean_len, suffix1_len) == 0) + str_len = clean_len; + + clean_len = str_len - suffix2_len; + if (clean_len >= 0 && memcmp (suffix2, str + clean_len, suffix2_len) == 0) + str_len = clean_len; + + return str_len; +} + +/* get_icon_name_sortkey: * - * Handles scheduled weather report updates. + * Returns a sort key for a given weather + * icon name and -1 for unknown ones. + * + * The lower the key, the better the weather. */ -static void -on_midnight_timer_timeout (GcalTimer *timer, - GcalWeatherService *self) +static gint +get_icon_name_sortkey (const gchar *icon_name, + gboolean *supports_night_icon) { - g_return_if_fail (timer != NULL); - g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); + /* Note that we can't use gweathers condition + * field as it is not necessarily holds valid values. + * libgweather uses its own heuristic to determine + * the icon to use. String matching is still better + * than copying their algorithm, I guess. + */ - if (self->gweather_info != NULL) - gweather_info_update (self->gweather_info); + gssize normalized_name_len; - if (gcal_timer_is_running (self->duration_timer)) - gcal_timer_reset (self->duration_timer); + const GcalWeatherIconInfo icons[] = + { {"weather-clear", TRUE}, + {"weather-few-clouds", TRUE}, + {"weather-overcast", FALSE}, + {"weather-fog", FALSE}, + {"weather-showers-scattered", FALSE}, + {"weather-showers", FALSE}, + {"weather-snow", FALSE}, + {"weather-storm", FALSE}, + {"weather-severe-alert", FALSE} + }; - schedule_midnight (self); -} + g_return_val_if_fail (icon_name != NULL, -1); + g_return_val_if_fail (supports_night_icon != NULL, -1); + *supports_night_icon = FALSE; + normalized_name_len = get_normalized_icon_name_len (icon_name); + g_return_val_if_fail (normalized_name_len >= 0, -1); -/************* - * < public > - *************/ + for (int i = 0; i < G_N_ELEMENTS (icons); i++) + { + if (icons[i].name[normalized_name_len] == '\0' && strncmp (icon_name, icons[i].name, normalized_name_len) == 0) + { + *supports_night_icon = icons[i].night_support; + return i; + } + } -/** - * gcal_weather_service_new: - * @max_days: mumber of days to fetch forecasts for. - * @check_interval_new: timeout used when fetching new weather reports. - * @check_interval_renew: timeout used to update valid weather reports. + g_warning ("Unknown weather icon '%s'", icon_name); + + return -1; +} + +/* get_time_day_start: + * @self: The #GcalWeatherService instance. + * @date: (out) (not nullable): A #GDate that should be set to today. + * @unix: (out) (not nullable): A UNIX time stamp that should be set to today. + * @ret_unix_exact (out) (not nullable): The exact date time this data point predicts. * - * Creates a new #GcalWeatherService. This service listens - * to location and weather changes and reports them. + * Provides current date in two different forms. * - * Returns: (transfer full): A newly created #GcalWeatherService. + * Returns: %TRUE on success. */ -GcalWeatherService * -gcal_weather_service_new (GTimeZone *time_zone, - guint max_days, - guint check_interval_new, - guint check_interval_renew, - gint64 valid_timespan) +static gboolean +get_time_day_start (GcalWeatherService *self, + GDate *ret_date, + gint64 *ret_unix, + gint64 *ret_unix_exact) { - return g_object_new (GCAL_TYPE_WEATHER_SERVICE, - "time-zone", time_zone, - "max-days", max_days, - "check-interval-new", check_interval_new, - "check-interval-renew", check_interval_renew, - "valid-timespan", valid_timespan, - NULL); -} + g_autoptr (GTimeZone) zone = NULL; + g_autoptr (GDateTime) now = NULL; + g_autoptr (GDateTime) day = NULL; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (ret_date != NULL, FALSE); + g_return_val_if_fail (ret_unix != NULL, FALSE); + g_return_val_if_fail (ret_unix_exact != NULL, FALSE); + zone = (self->time_zone == NULL) + ? g_time_zone_new_local () + : g_time_zone_ref (self->time_zone); + now = g_date_time_new_now (zone); + day = g_date_time_new (zone, + g_date_time_get_year (now), + g_date_time_get_month (now), + g_date_time_get_day_of_month (now), + 0, 0, 0); -/** - * gcal_weather_service_run: - * @self: The #GcalWeatherService instance. - * @location: (nullable): A fixed location or %NULL to use Gclue. + g_date_set_dmy (ret_date, + g_date_time_get_day_of_month (day), + g_date_time_get_month (day), + g_date_time_get_year (day)); + + *ret_unix = g_date_time_to_unix (day); + *ret_unix_exact = g_date_time_to_unix (now); + return TRUE; +} + +/* get_gweather_temperature: + * @gwi: #GWeatherInfo to extract temperatures from. + * @temp: (out): extracted temperature or %NAN. * - * Starts to monitor location and weather changes. - * Use ::weather-changed to catch responses. + * Returns sanitized temperatures. Returned values should only + * be used as sort key. + * + * Returns: %TRUE for valid temperatures. */ -void -gcal_weather_service_run (GcalWeatherService *self, - GWeatherLocation *location) +static inline gboolean +get_gweather_temperature (GWeatherInfo *gwi, + gdouble *temp) { - g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); + gboolean valid; + gdouble value; - g_debug ("Start weather service"); + *temp = NAN; - if (self->location_service_running || self->weather_service_running) - gcal_weather_service_stop (self); + g_return_val_if_fail (gwi != NULL, FALSE); + g_return_val_if_fail (temp != NULL, FALSE); - if (location == NULL) + valid = gweather_info_get_value_temp (gwi, + GWEATHER_TEMP_UNIT_DEFAULT, + &value); + + /* TODO: Extract temperatures in Celsius and catch + * implausible cases. + */ + if (valid) { - /* Start location and weather service: */ - self->location_service_running = TRUE; - self->weather_service_running = TRUE; - g_cancellable_cancel (self->location_cancellable); - g_cancellable_reset (self->location_cancellable); - gclue_simple_new (DESKTOP_FILE_NAME, - GCLUE_ACCURACY_LEVEL_EXACT, - self->location_cancellable, - (GAsyncReadyCallback) on_gclue_simple_creation, - g_object_ref (self)); + *temp = value; + return TRUE; } else { - /* Use the given location to retrieve weather information: */ - self->location_service_running = FALSE; - self->weather_service_running = TRUE; - - /*_update_location starts timer if necessary */ - gcal_weather_service_update_location (self, location); + *temp = NAN; + return FALSE; } } +/* compute_weather_info_data: + * @samples: List of received #GWeatherInfos. + * @icon_name: (out): (transfer full): weather icon name or %NULL. + * @temperature: (out): (transfer full): temperature and unit or %NULL. + * + * Computes a icon name and temperature representing @samples. + * + * Returns: %TRUE if there is a valid icon name and temperature. + */ +static gboolean +compute_weather_info_data (GSList *samples, + gboolean is_today, + gchar **icon_name, + gchar **temperature) +{ + gboolean phenomenon_supports_night_icon = FALSE; + gint phenomenon_val = -1; + GWeatherInfo *phenomenon_gwi = NULL; /* unowned */ + gdouble temp_val = NAN; + GWeatherInfo *temp_gwi = NULL; /* unowned */ + gboolean has_daytime = FALSE; + GSList *iter; /* unowned */ + + /* Note: I checked three different gweather consumers + * and they all pick different values. So here is my + * take: I pick up the worst weather for icons and + * the highest temperature. I basically want to know + * whether I need my umbrella for my appointment. + * Not sure about the right temperature. It is probably + * better to pick-up the median of all predictions + * during daytime. + */ + g_return_val_if_fail (icon_name != NULL, FALSE); + g_return_val_if_fail (temperature != NULL, FALSE); -/** - * gcal_weather_service_stop: - * @self: The #GcalWeatherService instance. + for (iter = samples; iter != NULL; iter = iter->next) + { + GWeatherInfo *gwi; /* unowned */ + const gchar *icon_name; /* unowned */ + gint phenomenon = -1; + gboolean supports_night_icon; + gdouble temp; + gboolean valid_temp; + + gwi = GWEATHER_INFO (iter->data); + + icon_name = gweather_info_get_icon_name (gwi); + if (icon_name != NULL) + phenomenon = get_icon_name_sortkey (icon_name, &supports_night_icon); + + valid_temp = get_gweather_temperature (gwi, &temp); + + if (phenomenon >= 0 && (phenomenon_gwi == NULL || phenomenon > phenomenon_val)) + { + phenomenon_supports_night_icon = supports_night_icon; + phenomenon_val = phenomenon; + phenomenon_gwi = gwi; + } + + if (valid_temp && (temp_gwi == NULL || temp > temp_val)) + { + temp_val = temp; + temp_gwi = gwi; + } + + if (gweather_info_is_daytime (gwi)) + has_daytime = TRUE; + } + + if (phenomenon_gwi != NULL && temp_gwi != NULL) + { + *icon_name = get_normalized_icon_name (phenomenon_gwi, is_today && !has_daytime && phenomenon_supports_night_icon); + *temperature = gweather_info_get_temp (temp_gwi); + return TRUE; + } + else + { + /* empty list */ + *icon_name = NULL; + *temperature = NULL; + return FALSE; + } +} + +/* preprocess_gweather_reports: + * @self: The #GcalWeatherService instance. + * @samples: Received list of #GWeatherInfos * - * Stops the service. Returns gracefully if service is - * not running. + * Computes weather info objects representing specific days + * by combining given #GWeatherInfos. + * + * Returns: (transfer full): List of up to $self->max_days #GcalWeatherInfos. */ -void -gcal_weather_service_stop (GcalWeatherService *self) +static GSList* +preprocess_gweather_reports (GcalWeatherService *self, + GSList *samples) { - g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); + const glong DAY_SECONDS = 24*60*60; + GSList *result = NULL; /* owned[owned] */ + GSList **days; /* owned[owned[unowned]] */ + GSList *iter; /* unowned */ + GDate cur_gdate; + glong today_unix; + glong unix_now; - g_debug ("Stop weather service"); + GWeatherInfo *first_tomorrow = NULL; /* unowned */ + glong first_tomorrow_dtime = -1; - if (!self->location_service_running && !self->weather_service_running) - return ; + g_return_val_if_fail (GCAL_IS_WEATHER_SERVICE (self), NULL); - self->location_service_running = FALSE; - self->weather_service_running = FALSE; + /* This function basically separates samples by + * date and calls compute_weather_info_data for + * every bucket to build weather infos. + * Each bucket represents a single day. + */ - /* Notify all listeners about unknown location: */ - gcal_weather_service_update_location (self, NULL); + /* All gweather consumers I reviewed presume + * sorted samples. However, there is no documented + * order. Lets assume the worst. + */ - if (self->location_service == NULL) + if (self->max_days <= 0) + return NULL; + + if (!get_time_day_start (self, &cur_gdate, &today_unix, &unix_now)) + return NULL; + + days = g_malloc0 (sizeof (GSList*) * self->max_days); + + /* Split samples to max_days buckets: */ + for (iter = samples; iter != NULL; iter = iter->next) { - /* location service is under construction. Cancel creation. */ - g_cancellable_cancel (self->location_cancellable); + GWeatherInfo *gwi; /* unowned */ + gboolean valid_date; + glong gwi_dtime; + gsize bucket; + + gwi = GWEATHER_INFO (iter->data); + valid_date = gweather_info_get_value_update (gwi, &gwi_dtime); + if (!valid_date) + continue; + + #if PRINT_WEATHER_DATA + { + g_autofree gchar* dbg_str = gwc2str (gwi); + g_message ("WEATHER READING POINT: %s", dbg_str); + } + #endif + + if (gwi_dtime >= 0 && gwi_dtime >= today_unix) + { + bucket = (gwi_dtime - today_unix) / DAY_SECONDS; + if (bucket >= 0 && bucket < self->max_days) + days[bucket] = g_slist_prepend (days[bucket], gwi); + + if (bucket == 1 && (first_tomorrow == NULL || first_tomorrow_dtime > gwi_dtime)) + { + first_tomorrow_dtime = gwi_dtime; + first_tomorrow = gwi; + } + } + else + { + g_debug ("Encountered historic weather information"); + } } - else + + if (days[0] == NULL && first_tomorrow != NULL) { - GClueClient *client; /* unowned */ + /* There is no data point left for today. + * Lets borrow one. + */ + glong secs_left_today; + glong secs_between; - client = gclue_simple_get_client (self->location_service); + secs_left_today = DAY_SECONDS - (unix_now - today_unix); + secs_between = first_tomorrow_dtime - unix_now; - gclue_client_call_stop (client, - NULL, - (GAsyncReadyCallback) on_gclue_client_stop, - g_steal_pointer (&self->location_service)); + if (secs_left_today < 90*60 && secs_between <= 180*60) + days[0] = g_slist_prepend (days[0], first_tomorrow); } -} + /* Produce GcalWeatherInfo for each bucket: */ + for (int i = 0; i < self->max_days; i++) + { + g_autofree gchar *icon_name; + g_autofree gchar *temperature; + if (compute_weather_info_data (days[i], i == 0, &icon_name, &temperature)) + { + GcalWeatherInfo* gcwi; /* owned */ -/** - * gcal_weather_service_get_max_days: - * @self: The #GcalWeatherService instance. - * - * Getter for #GcalWeatherService:max-days. - */ -guint -gcal_weather_service_get_max_days (GcalWeatherService *self) -{ - g_return_val_if_fail (GCAL_IS_WEATHER_SERVICE (self), 0); + gcwi = gcal_weather_info_new (&cur_gdate, + icon_name, + temperature); - return self->max_days; + result = g_slist_prepend (result, + g_steal_pointer (&gcwi)); + } + + g_date_add_days (&cur_gdate, 1); + } + + /* Cleanup: */ + for (int i = 0; i < self->max_days; i++) + g_slist_free (days[i]); + g_free (days); + + return result; } +/************* + * < public > + *************/ /** - * gcal_weather_service_get_valid_timespan: - * @self: The #GcalWeatherService instance. + * gcal_weather_service_new: + * @max_days: mumber of days to fetch forecasts for. + * @check_interval_new: timeout used when fetching new weather reports. + * @check_interval_renew: timeout used to update valid weather reports. * - * Getter for #GcalWeatherService:valid-interval. + * Creates a new #GcalWeatherService. This service listens + * to location and weather changes and reports them. + * + * Returns: (transfer full): A newly created #GcalWeatherService. */ -gint64 -gcal_weather_service_get_valid_timespan (GcalWeatherService *self) +GcalWeatherService * +gcal_weather_service_new (GTimeZone *time_zone, + guint max_days, + guint check_interval_new, + guint check_interval_renew, + gint64 valid_timespan) { - g_return_val_if_fail (GCAL_IS_WEATHER_SERVICE (self), 0); - return self->valid_timespan; + return g_object_new (GCAL_TYPE_WEATHER_SERVICE, + "time-zone", time_zone, + "max-days", max_days, + "check-interval-new", check_interval_new, + "check-interval-renew", check_interval_renew, + "valid-timespan", valid_timespan, + NULL); } - - /** * gcal_weather_service_get_time_zone: * @self: The #GcalWeatherService instance. @@ -1706,8 +1551,6 @@ gcal_weather_service_get_time_zone (GcalWeatherService *self) return self->time_zone; } - - /** * gcal_weather_service_set_time_zone: * @self: The #GcalWeatherService instance. @@ -1742,8 +1585,32 @@ gcal_weather_service_set_time_zone (GcalWeatherService *self, } } +/** + * gcal_weather_service_get_max_days: + * @self: The #GcalWeatherService instance. + * + * Getter for #GcalWeatherService:max-days. + */ +guint +gcal_weather_service_get_max_days (GcalWeatherService *self) +{ + g_return_val_if_fail (GCAL_IS_WEATHER_SERVICE (self), 0); + return self->max_days; +} +/** + * gcal_weather_service_get_valid_timespan: + * @self: The #GcalWeatherService instance. + * + * Getter for #GcalWeatherService:valid-interval. + */ +gint64 +gcal_weather_service_get_valid_timespan (GcalWeatherService *self) +{ + g_return_val_if_fail (GCAL_IS_WEATHER_SERVICE (self), 0); + return self->valid_timespan; +} /** * gcal_weather_service_get_check_interval_new: @@ -1759,8 +1626,6 @@ gcal_weather_service_get_check_interval_new (GcalWeatherService *self) return self->check_interval_new; } - - /** * gcal_weather_service_get_check_interval_renew: * @self: The #GcalWeatherService instance. @@ -1775,8 +1640,6 @@ gcal_weather_service_get_check_interval_renew (GcalWeatherService *self) return self->check_interval_renew; } - - /** * gcal_weather_service_get_weather_infos: * @self: The #GcalWeatherService instance. @@ -1791,8 +1654,6 @@ gcal_weather_service_get_weather_infos (GcalWeatherService *self) return self->weather_infos; } - - /** * gcal_weather_service_get_attribution: * @self: The #GcalWeatherService instance. @@ -1812,8 +1673,6 @@ gcal_weather_service_get_attribution (GcalWeatherService *self) return NULL; } - - /** * gcal_weather_service_update: * @self: The #GcalWeatherService instance. @@ -1833,3 +1692,87 @@ gcal_weather_service_update (GcalWeatherService *self) gcal_timer_reset (self->duration_timer); } } + +/** + * gcal_weather_service_run: + * @self: The #GcalWeatherService instance. + * @location: (nullable): A fixed location or %NULL to use Gclue. + * + * Starts to monitor location and weather changes. + * Use ::weather-changed to catch responses. + */ +void +gcal_weather_service_run (GcalWeatherService *self, + GWeatherLocation *location) +{ + g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); + + g_debug ("Start weather service"); + + if (self->location_service_running || self->weather_service_running) + gcal_weather_service_stop (self); + + if (location == NULL) + { + /* Start location and weather service: */ + self->location_service_running = TRUE; + self->weather_service_running = TRUE; + g_cancellable_cancel (self->location_cancellable); + g_cancellable_reset (self->location_cancellable); + gclue_simple_new (DESKTOP_FILE_NAME, + GCLUE_ACCURACY_LEVEL_EXACT, + self->location_cancellable, + (GAsyncReadyCallback) on_gclue_simple_creation, + g_object_ref (self)); + } + else + { + /* Use the given location to retrieve weather information: */ + self->location_service_running = FALSE; + self->weather_service_running = TRUE; + + /*_update_location starts timer if necessary */ + update_location (self, location); + } +} + +/** + * gcal_weather_service_stop: + * @self: The #GcalWeatherService instance. + * + * Stops the service. Returns gracefully if service is + * not running. + */ +void +gcal_weather_service_stop (GcalWeatherService *self) +{ + g_return_if_fail (GCAL_IS_WEATHER_SERVICE (self)); + + g_debug ("Stop weather service"); + + if (!self->location_service_running && !self->weather_service_running) + return ; + + self->location_service_running = FALSE; + self->weather_service_running = FALSE; + + /* Notify all listeners about unknown location: */ + update_location (self, NULL); + + if (self->location_service == NULL) + { + /* location service is under construction. Cancel creation. */ + g_cancellable_cancel (self->location_cancellable); + } + else + { + GClueClient *client; /* unowned */ + + client = gclue_simple_get_client (self->location_service); + + gclue_client_call_stop (client, + NULL, + (GAsyncReadyCallback) on_gclue_client_stop, + g_steal_pointer (&self->location_service)); + } +} diff --git a/src/gcal-weather-service.h b/src/gcal-weather-service.h index b9093d08..52f78d40 100644 --- a/src/gcal-weather-service.h +++ b/src/gcal-weather-service.h @@ -37,37 +37,35 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (GcalWeatherService, gcal_weather_service, GCAL, WEATHER_SERVICE, GObject) -GcalWeatherService* gcal_weather_service_new (GTimeZone *time_zone, - guint max_days, - guint check_interval_new, - guint check_interval_renew, - gint64 valid_timespan); +GcalWeatherService* gcal_weather_service_new (GTimeZone *time_zone, + guint max_days, + guint check_interval_new, + guint check_interval_renew, + gint64 valid_timespan); -GTimeZone* gcal_weather_service_get_time_zone (GcalWeatherService *self); +GTimeZone* gcal_weather_service_get_time_zone (GcalWeatherService *self); -void gcal_weather_service_set_time_zone (GcalWeatherService *self, - GTimeZone *value); +void gcal_weather_service_set_time_zone (GcalWeatherService *self, + GTimeZone *value); -void gcal_weather_service_run (GcalWeatherService *self, - GWeatherLocation *location); +guint gcal_weather_service_get_max_days (GcalWeatherService *self); -void gcal_weather_service_stop (GcalWeatherService *self); +gint64 gcal_weather_service_get_valid_timespan (GcalWeatherService *self); -guint gcal_weather_service_get_max_days (GcalWeatherService *self); +guint gcal_weather_service_get_check_interval_new (GcalWeatherService *self); -gint64 gcal_weather_service_get_valid_timespan (GcalWeatherService *self); +guint gcal_weather_service_get_check_interval_renew (GcalWeatherService *self); -guint gcal_weather_service_get_check_interval_new - (GcalWeatherService *self); +GSList* gcal_weather_service_get_weather_infos (GcalWeatherService *self); -guint gcal_weather_service_get_check_interval_renew - (GcalWeatherService *self); +const gchar* gcal_weather_service_get_attribution (GcalWeatherService *self); -GSList* gcal_weather_service_get_weather_infos (GcalWeatherService *self); +void gcal_weather_service_update (GcalWeatherService *self); -const gchar* gcal_weather_service_get_attribution (GcalWeatherService *self); +void gcal_weather_service_run (GcalWeatherService *self, + GWeatherLocation *location); -void gcal_weather_service_update (GcalWeatherService *self); +void gcal_weather_service_stop (GcalWeatherService *self); G_END_DECLS diff --git a/src/gcal-window.c b/src/gcal-window.c index c6c09756..5fb6e9ad 100644 --- a/src/gcal-window.c +++ b/src/gcal-window.c @@ -84,16 +84,16 @@ typedef struct { - gint x; - gint y; - GDateTime *start_date; - GDateTime *end_date; + gint x; + gint y; + GDateTime *start_date; + GDateTime *end_date; } NewEventData; typedef struct { - GcalWindow *window; - gchar *uuid; + GcalWindow *window; + gchar *uuid; } OpenEditDialogData; /* WeatherSigs: @@ -107,8 +107,8 @@ typedef struct */ typedef struct { - GObject *obj; /* unowned */ - gulong id; + GObject *obj; /* unowned */ + gulong id; } WeatherSigs; struct _GcalWindow @@ -116,86 +116,86 @@ struct _GcalWindow GtkApplicationWindow parent; /* timeout ids */ - guint notification_timeout; + guint notification_timeout; /* upper level widgets */ - GtkWidget *main_box; - - GtkWidget *header_bar; - GtkWidget *search_bar; - GtkWidget *views_overlay; - GtkWidget *views_stack; - GtkWidget *week_view; - GtkWidget *month_view; - GtkWidget *year_view; - GtkWidget *notification; - GtkWidget *notification_label; - GtkWidget *notification_action_button; - GtkWidget *notification_close_button; + GtkWidget *main_box; + + GtkWidget *header_bar; + GtkWidget *search_bar; + GtkWidget *views_overlay; + GtkWidget *views_stack; + GtkWidget *week_view; + GtkWidget *month_view; + GtkWidget *year_view; + GtkWidget *notification; + GtkWidget *notification_label; + GtkWidget *notification_action_button; + GtkWidget *notification_close_button; /* header_bar widets */ - GtkWidget *menu_button; - GtkWidget *search_button; - GtkWidget *calendars_button; - GtkWidget *search_entry; - GtkWidget *back_button; - GtkWidget *today_button; - GtkWidget *forward_button; - GtkWidget *views_switcher; + GtkWidget *menu_button; + GtkWidget *search_button; + GtkWidget *calendars_button; + GtkWidget *search_entry; + GtkWidget *back_button; + GtkWidget *today_button; + GtkWidget *forward_button; + GtkWidget *views_switcher; /* new event popover widgets */ - GtkWidget *quick_add_popover; + GtkWidget *quick_add_popover; - GtkWidget *search_view; + GtkWidget *search_view; /* day, week, month, year, list */ - GtkWidget *views [6]; - GtkWidget *edit_dialog; + GtkWidget *views [6]; + GtkWidget *edit_dialog; - GcalManager *manager; - GcalWindowViewType active_view; - icaltimetype *active_date; + GcalManager *manager; + GcalWindowViewType active_view; + icaltimetype *active_date; - gboolean rtl; + gboolean rtl; /* states */ - gboolean new_event_mode; - gboolean search_mode; + gboolean new_event_mode; + gboolean search_mode; - NewEventData *event_creation_data; + NewEventData *event_creation_data; - GcalEvent *event_to_delete; - GcalRecurrenceModType event_to_delete_mod; + GcalEvent *event_to_delete; + GcalRecurrenceModType event_to_delete_mod; /* calendar management */ - GtkWidget *calendar_popover; - GtkWidget *calendar_listbox; - GtkWidget *source_dialog; + GtkWidget *calendar_popover; + GtkWidget *calendar_listbox; + GtkWidget *source_dialog; - gint refresh_timeout; - gint refresh_timeout_id; - gint open_edit_dialog_timeout_id; + gint refresh_timeout; + gint refresh_timeout_id; + gint open_edit_dialog_timeout_id; /* weather management */ - GcalWeatherService *weather_service; /* owned */ - GtkSwitch *weather; /* unowned */ - GtkSwitch *auto_location; /* unowned */ - GtkBox *auto_location_box; /* unowned */ + GcalWeatherService *weather_service; /* owned */ + GtkSwitch *weather; /* unowned */ + GtkSwitch *auto_location; /* unowned */ + GtkBox *auto_location_box; /* unowned */ GWeatherLocationEntry *location_entry; /* unowned */ - WeatherSigs weather_cb_ids[5]; + WeatherSigs weather_cb_ids[5]; /* temp to keep event_creation */ - gboolean open_edit_dialog; + gboolean open_edit_dialog; /* handler for the searh_view */ - gint click_outside_handler_id; + gint click_outside_handler_id; /* Window states */ - gint width; - gint height; - gint pos_x; - gint pos_y; - gboolean is_maximized; + gint width; + gint height; + gint pos_x; + gint pos_y; + gboolean is_maximized; }; enum @@ -218,60 +218,60 @@ enum } -static void on_show_calendars_action_activated (GSimpleAction *action, - GVariant *param, - gpointer user_data); +static void on_show_calendars_action_activated (GSimpleAction *action, + GVariant *param, + gpointer user_data); + +static void on_view_action_activated (GSimpleAction *action, + GVariant *param, + gpointer user_data); -static void on_view_action_activated (GSimpleAction *action, - GVariant *param, - gpointer user_data); +static void on_menu_button_clicked (GtkMenuButton *menu, + GtkStack *stack); -static void on_toggle_search_bar_activated (GSimpleAction *action, - GVariant *param, - gpointer user_data); +static void on_toggle_search_bar_activated (GSimpleAction *action, + GVariant *param, + gpointer user_data); -static void on_menu_button_clicked (GtkMenuButton *menu, - GtkStack *stack); +static void on_view_menu_open_sub (GtkModelButton *button, + GtkStack *stack); -static void on_view_menu_open_sub (GtkModelButton *button, - GtkStack *stack); +static void on_view_menu_open_parent (GtkModelButton *button, + GtkStack *stack); -static void on_view_menu_open_parent (GtkModelButton *button, - GtkStack *stack); +static void on_weather_location_searchbox_change (GWeatherLocationEntry *entry, + GcalWindow *self); -static void on_weather_location_searchbox_change (GWeatherLocationEntry *entry, - GcalWindow *self); +static void on_show_weather_change (GtkSwitch *wswitch, + GParamSpec *pspec, + GcalWindow *self); -static void on_show_weather_change (GtkSwitch *wswitch, - GParamSpec *pspec, - GcalWindow *self); +static void on_auto_location_change (GtkSwitch *lswitch, + GParamSpec *pspec, + GcalWindow *self); -static void on_auto_location_change (GtkSwitch *lswitch, - GParamSpec *pspec, - GcalWindow *self); +static gboolean on_weather_location_searchbox_match_selected (GtkEntryCompletion *sender, + GtkTreeModel *model, + GtkTreeIter *iter, + GcalWindow *self); -static gboolean on_weather_location_searchbox_match_selected - (GtkEntryCompletion *sender, - GtkTreeModel *model, - GtkTreeIter *iter, - GcalWindow *self); +static void set_model_button_animation (GtkBuilder *builder, + GtkStack *stack, + const char *id, + gboolean go_back); -static void set_model_button_animation (GtkBuilder *builder, - GtkStack *stack, - const char *id, - gboolean go_back); -static void update_menu_weather_sensitivity (GcalWindow *self); +static void update_menu_weather_sensitivity (GcalWindow *self); -static void close_menu (GcalWindow *self); +static void close_menu (GcalWindow *self); -static void safe_weather_settings (GcalWindow *self); +static void safe_weather_settings (GcalWindow *self); -static void load_weather_settings (GcalWindow *self); +static void load_weather_settings (GcalWindow *self); -static void manage_weather_service (GcalWindow *self); +static void manage_weather_service (GcalWindow *self); -static GWeatherLocation* get_checked_fixed_location (GcalWindow *self); +static GWeatherLocation* get_checked_fixed_location (GcalWindow *self); G_DEFINE_TYPE (GcalWindow, gcal_window, GTK_TYPE_APPLICATION_WINDOW) diff --git a/src/views/gcal-week-header.c b/src/views/gcal-week-header.c index 8d48c234..8e9fc600 100644 --- a/src/views/gcal-week-header.c +++ b/src/views/gcal-week-header.c @@ -48,57 +48,57 @@ */ typedef struct { - GcalWeatherInfo *winfo; /* owned */ - GdkPixbuf *icon_buf; /* owned */ + GcalWeatherInfo *winfo; /* owned */ + GdkPixbuf *icon_buf; /* owned */ } WeatherInfoDay; struct _GcalWeekHeader { - GtkGrid parent; + GtkGrid parent; - GtkWidget *grid; - GtkWidget *month_label; - GtkWidget *week_label; - GtkWidget *year_label; - GtkWidget *scrolledwindow; - GtkWidget *expand_button; - GtkWidget *expand_button_box; - GtkWidget *expand_button_image; - GtkWidget *header_labels_box; + GtkWidget *grid; + GtkWidget *month_label; + GtkWidget *week_label; + GtkWidget *year_label; + GtkWidget *scrolledwindow; + GtkWidget *expand_button; + GtkWidget *expand_button_box; + GtkWidget *expand_button_image; + GtkWidget *header_labels_box; - GcalManager *manager; + GcalManager *manager; /* * Stores the events as they come from the week-view * The list will later be iterated after the active date is changed * and the events will be placed */ - GList *events[7]; - GtkWidget *overflow_label[7]; + GList *events[7]; + GtkWidget *overflow_label[7]; - gint first_weekday; + gint first_weekday; /* * Used for checking if the header is in collapsed state or expand state * false is collapse state true is expand state */ - gboolean expanded; + gboolean expanded; - gboolean use_24h_format; + gboolean use_24h_format; - icaltimetype *active_date; + icaltimetype *active_date; - gint selection_start; - gint selection_end; - gint dnd_cell; + gint selection_start; + gint selection_end; + gint dnd_cell; GcalWeatherService *weather_service; /* unowned, nullable */ /* Array of nullable weather infos for each day, starting with Sunday. */ WeatherInfoDay weather_infos[7]; - GtkSizeGroup *sizegroup; + GtkSizeGroup *sizegroup; }; typedef enum diff --git a/src/views/gcal-week-view.c b/src/views/gcal-week-view.c index 7290b957..bc1122fe 100644 --- a/src/views/gcal-week-view.c +++ b/src/views/gcal-week-view.c @@ -43,39 +43,39 @@ static const double dashed [] = struct _GcalWeekView { - GtkBox parent; + GtkBox parent; - GtkWidget *header; - GtkWidget *hours_bar; - GtkWidget *scrolled_window; - GtkWidget *week_grid; + GtkWidget *header; + GtkWidget *hours_bar; + GtkWidget *scrolled_window; + GtkWidget *week_grid; /* * first day of the week according to user locale, being * 0 for Sunday, 1 for Monday and so on */ - gint first_weekday; + gint first_weekday; /* * clock format from GNOME desktop settings */ - gboolean use_24h_format; + gboolean use_24h_format; /* property */ icaltimetype *date; GcalManager *manager; /* owned */ GcalWeatherService *weather_service; /* owned */ - guint scroll_grid_timeout_id; + guint scroll_grid_timeout_id; - gint clicked_cell; + gint clicked_cell; }; -static void schedule_position_scroll (GcalWeekView *self); +static void schedule_position_scroll (GcalWeekView *self); -static void gcal_view_interface_init (GcalViewInterface *iface); +static void gcal_view_interface_init (GcalViewInterface *iface); -static void gcal_data_model_subscriber_interface_init (ECalDataModelSubscriberInterface *iface); +static void gcal_data_model_subscriber_interface_init (ECalDataModelSubscriberInterface *iface); enum { diff --git a/src/views/gcal-year-view.c b/src/views/gcal-year-view.c index f18d1cc9..eaf0f607 100644 --- a/src/views/gcal-year-view.c +++ b/src/views/gcal-year-view.c @@ -35,90 +35,90 @@ typedef struct { /* month span from 0 to 11 */ - gint start_day, start_month; - gint end_day, end_month; - gint hovered_day, hovered_month; - gint dnd_day, dnd_month; + gint start_day, start_month; + gint end_day, end_month; + gint hovered_day, hovered_month; + gint dnd_day, dnd_month; } ButtonData; typedef struct { - gdouble box_side; - GdkPoint coordinates [12]; + gdouble box_side; + GdkPoint coordinates [12]; } GridData; struct _GcalYearView { - GtkBox parent; + GtkBox parent; /* composite, GtkBuilder's widgets */ - GtkWidget *navigator; - GtkWidget *sidebar; - GtkWidget *events_sidebar; - GtkWidget *navigator_stack; - GtkWidget *no_events_title; - GtkWidget *navigator_sidebar; - GtkWidget *scrolled_window; - GtkLabel *temp_label; /* unowned */ - GtkImage *weather_icon; /* unowned */ - - GtkWidget *popover; /* Popover for popover_mode */ + GtkWidget *navigator; + GtkWidget *sidebar; + GtkWidget *events_sidebar; + GtkWidget *navigator_stack; + GtkWidget *no_events_title; + GtkWidget *navigator_sidebar; + GtkWidget *scrolled_window; + GtkLabel *temp_label; /* unowned */ + GtkImage *weather_icon; /* unowned */ + + GtkWidget *popover; /* Popover for popover_mode */ /* manager singleton */ - GcalManager *manager; + GcalManager *manager; GcalWeatherService *weather_service; /* owned, nullable */ /* range shown on the sidebar */ - icaltimetype *start_selected_date; - icaltimetype *end_selected_date; + icaltimetype *start_selected_date; + icaltimetype *end_selected_date; /* geometry info */ - GridData *navigator_grid; - guint number_of_columns; - guint column_width; - guint row_height; - guint header_height; - guint sidebar_width; + GridData *navigator_grid; + guint number_of_columns; + guint column_width; + guint row_height; + guint header_height; + guint sidebar_width; /* state flags */ - gboolean popover_mode; - gboolean button_pressed; - ButtonData *selected_data; + gboolean popover_mode; + gboolean button_pressed; + ButtonData *selected_data; /** * first day of the week according to user locale, being * 0 for Sunday, 1 for Monday and so on */ - gint first_weekday; + gint first_weekday; /* first and last weeks of the year */ - guint first_week_of_year; - guint last_week_of_year; + guint first_week_of_year; + guint last_week_of_year; /* Storage for the accumulated scrolling */ - gdouble scroll_value; + gdouble scroll_value; /** * clock format from GNOME desktop settings */ - gboolean use_24h_format; + gboolean use_24h_format; /* show week numbers from GNOME Shell settings */ - GSettings *calendar_settings; - gboolean show_week_numbers; + GSettings *calendar_settings; + gboolean show_week_numbers; /* text direction factors */ - gint k; + gint k; /* date property */ - icaltimetype *date; + icaltimetype *date; /* * Array with the events at every month. Events * that span multiple months are added multiple * times to the array. */ - GPtrArray *events[12]; + GPtrArray *events[12]; }; enum { @@ -139,9 +139,10 @@ enum static guint signals[NUM_SIGNALS] = { 0, }; static gpointer year_view_parent_class = NULL; -static void gcal_view_interface_init (GcalViewInterface *iface); -static void gcal_data_model_subscriber_interface_init (ECalDataModelSubscriberInterface *iface); -static void update_weather (GcalYearView *self); +static void gcal_view_interface_init (GcalViewInterface *iface); +static void gcal_data_model_subscriber_interface_init (ECalDataModelSubscriberInterface *iface); +static void update_weather (GcalYearView *self); + G_DEFINE_TYPE_WITH_CODE (GcalYearView, gcal_year_view, GTK_TYPE_BOX, G_IMPLEMENT_INTERFACE (GCAL_TYPE_VIEW, gcal_view_interface_init) diff --git a/src/views/gcal-year-view.h b/src/views/gcal-year-view.h index da0d18e7..9cad185a 100644 --- a/src/views/gcal-year-view.h +++ b/src/views/gcal-year-view.h @@ -31,12 +31,14 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (GcalYearView, gcal_year_view, GCAL, YEAR_VIEW, GtkBox) -void gcal_year_view_set_first_weekday (GcalYearView *year_view, - gint nr_day); -void gcal_year_view_set_use_24h_format (GcalYearView *year_view, - gboolean use_24h_format); -void gcal_year_view_set_current_date (GcalYearView *year_view, - icaltimetype *current_date); +void gcal_year_view_set_first_weekday (GcalYearView *year_view, + gint nr_day); + +void gcal_year_view_set_use_24h_format (GcalYearView *year_view, + gboolean use_24h_format); + +void gcal_year_view_set_current_date (GcalYearView *year_view, + icaltimetype *current_date); G_END_DECLS |