month-view: Show weather reports.

This commit triggers two existing issues:
 1. window size calculation
    (this breaks month-cells)
 2. wrong reference counts in views
    (I use :destroy to avoid dangling pointers)
This commit is contained in:
Florian Brosch
2017-12-11 21:54:55 -02:00
committed by Georges Basile Stavracas Neto
parent 9ac45e840d
commit e9e403ce7a
6 changed files with 240 additions and 4 deletions
+2 -1
View File
@@ -1670,13 +1670,14 @@ gcal_window_init (GcalWindow *self)
* FIXME: this is a hack around the issue that happens when trying to bind
* there properties using the GtkBuilder .ui file.
*/
g_object_bind_property (self, "weather-service", self->week_view, "weather-service", G_BINDING_DEFAULT);
g_object_bind_property (self, "manager", self->edit_dialog, "manager", G_BINDING_DEFAULT);
g_object_bind_property (self, "manager", self->source_dialog, "manager", G_BINDING_DEFAULT);
g_object_bind_property (self, "manager", self->week_view, "manager", G_BINDING_DEFAULT);
g_object_bind_property (self, "manager", self->month_view, "manager", G_BINDING_DEFAULT);
g_object_bind_property (self, "manager", self->year_view, "manager", G_BINDING_DEFAULT);
g_object_bind_property (self, "manager", self->quick_add_popover, "manager", G_BINDING_DEFAULT);
g_object_bind_property (self, "weather-service", self->week_view, "weather-service", G_BINDING_DEFAULT);
g_object_bind_property (self, "weather-service", self->month_view, "weather-service", G_BINDING_DEFAULT);
/* setup accels */
app = g_application_get_default ();
+35
View File
@@ -33,6 +33,8 @@ struct _GcalMonthCell
GtkLabel *day_label;
GtkWidget *header_box;
GtkImage *weather_icon;
GtkWidget *overflow_button;
GtkWidget *overflow_label;
GtkWidget *overlay;
@@ -427,6 +429,7 @@ gcal_month_cell_class_init (GcalMonthCellClass *klass)
gtk_widget_class_bind_template_child (widget_class, GcalMonthCell, overflow_button);
gtk_widget_class_bind_template_child (widget_class, GcalMonthCell, overflow_label);
gtk_widget_class_bind_template_child (widget_class, GcalMonthCell, overlay);
gtk_widget_class_bind_template_child (widget_class, GcalMonthCell, weather_icon);
gtk_widget_class_bind_template_callback (widget_class, enter_notify_event_cb);
gtk_widget_class_bind_template_callback (widget_class, leave_notify_event_cb);
@@ -485,6 +488,38 @@ gcal_month_cell_set_date (GcalMonthCell *self,
update_style_flags (self);
}
/**
* gcal_month_cell_set_weather:
* @self: The #GcalMonthCell instance.
* @info: (nullable): The weather information to display.
*
* Sets the weather information to display for this day.
*
* Note that this function does not check dates nor
* manages weather information changes on its own.
*/
void
gcal_month_cell_set_weather (GcalMonthCell *self,
GcalWeatherInfo *info)
{
g_return_if_fail (GCAL_IS_MONTH_CELL (self));
g_return_if_fail (info == NULL || GCAL_IS_WEATHER_INFO (info));
if (info == NULL)
{
gtk_image_clear (self->weather_icon);
}
else
{
const gchar* icon_name; /* unowned */
icon_name = gcal_weather_info_get_icon_name (info);
gtk_image_set_from_icon_name (self->weather_icon, icon_name, GTK_ICON_SIZE_SMALL_TOOLBAR);
}
gtk_widget_show (GTK_WIDGET (self->weather_icon));
}
gboolean
gcal_month_cell_get_different_month (GcalMonthCell *self)
{
+4
View File
@@ -20,6 +20,7 @@
#define GCAL_MONTH_CELL_H
#include "gcal-manager.h"
#include "gcal-weather-info.h"
#include <gtk/gtk.h>
@@ -36,6 +37,9 @@ GDateTime* gcal_month_cell_get_date (GcalMonthCell
void gcal_month_cell_set_date (GcalMonthCell *self,
GDateTime *date);
void gcal_month_cell_set_weather (GcalMonthCell *self,
GcalWeatherInfo *info);
gboolean gcal_month_cell_get_different_month (GcalMonthCell *self);
void gcal_month_cell_set_different_month (GcalMonthCell *self,
+188 -1
View File
@@ -70,7 +70,7 @@ struct _GcalMonthView
/* Grid widgets */
GtkWidget *grid;
GtkWidget *month_cell[6][7];
GtkWidget *month_cell[6][7]; /* unowned */
/*
* Hash to keep children widgets (all of them, parent widgets and its parts if there's any),
@@ -132,6 +132,8 @@ struct _GcalMonthView
icaltimetype *date;
GcalManager *manager;
GcalWeatherService *weather_service;
gboolean pending_event_allocation;
};
@@ -141,6 +143,9 @@ static void gtk_buildable_interface_init (GtkBuildableIf
static void e_data_model_subscriber_interface_init (ECalDataModelSubscriberInterface *iface);
static void update_weather (GcalMonthView *self,
gboolean clear_old);
G_DEFINE_TYPE_WITH_CODE (GcalMonthView, gcal_month_view, GTK_TYPE_CONTAINER,
G_IMPLEMENT_INTERFACE (GCAL_TYPE_VIEW, gcal_view_interface_init)
G_IMPLEMENT_INTERFACE (E_TYPE_CAL_DATA_MODEL_SUBSCRIBER,
@@ -153,6 +158,7 @@ enum
PROP_0,
PROP_DATE,
PROP_MANAGER,
PROP_WEATHER_SERVICE,
N_PROPS
};
@@ -162,6 +168,7 @@ enum
NUM_SIGNALS
};
static gpointer month_view_parent_class = NULL;
static guint signals[NUM_SIGNALS] = { 0, };
@@ -194,6 +201,13 @@ event_widget_visibility_changed_cb (GcalMonthView *self)
gtk_widget_queue_resize (GTK_WIDGET (self));
}
static void
weather_changed_cb (GcalWeatherService *weather_service,
GcalMonthView *self)
{
update_weather (self, TRUE);
}
static void
setup_child_widget (GcalMonthView *self,
GtkWidget *widget)
@@ -896,6 +910,76 @@ setup_month_grid (GcalMonthView *self,
}
}
static void
update_weather (GcalMonthView *self,
gboolean clear_old)
{
g_return_if_fail (GCAL_IS_MONTH_VIEW (self));
/* Drop old weather information */
if (clear_old)
{
guint row;
guint col;
for (row = 0; row < 6; row++)
{
for (col = 0; col < 7; col++)
{
GcalMonthCell *cell;
cell = GCAL_MONTH_CELL (self->month_cell[row][col]);
gcal_month_cell_set_weather (cell, NULL);
}
}
}
/* Set new one */
if (self->weather_service != NULL)
{
GcalMonthCell *fstcell;
GDateTime *firstdt;
GSList *weather_infos;
GSList *witer;
GDate first;
fstcell = GCAL_MONTH_CELL (self->month_cell[0][0]);
firstdt = gcal_month_cell_get_date (fstcell);
g_date_set_dmy (&first,
g_date_time_get_day_of_month (firstdt),
g_date_time_get_month (firstdt),
g_date_time_get_year (firstdt));
weather_infos = gcal_weather_service_get_weather_infos (self->weather_service);
for (witer = weather_infos; witer; witer = witer->next)
{
GcalWeatherInfo *info;
GDate weather_date;
gint day_difference;
info = GCAL_WEATHER_INFO (witer->data);
gcal_weather_info_get_date (info, &weather_date);
day_difference = g_date_days_between (&first, &weather_date);
if (day_difference >= 0 && day_difference < 6 * 7)
{
GcalMonthCell *wcell;
guint row;
guint column;
row = day_difference / 7;
column = day_difference % 7;
wcell = GCAL_MONTH_CELL (self->month_cell[row][column]);
gcal_month_cell_set_weather (wcell, info);
}
}
}
}
static gboolean
update_month_cells (GcalMonthView *self)
{
@@ -928,6 +1012,7 @@ update_month_cells (GcalMonthView *self)
cell_date = g_date_time_add_days (dt, row * 7 + col - self->days_delay);
gcal_month_cell_set_date (cell, cell_date);
gcal_month_cell_set_weather (cell, NULL);
/* Different month */
different_month = day < self->days_delay ||
@@ -976,6 +1061,8 @@ update_month_cells (GcalMonthView *self)
}
}
update_weather (self, FALSE);
self->update_grid_id = 0;
return G_SOURCE_REMOVE;
@@ -1685,6 +1772,9 @@ gcal_month_view_set_property (GObject *object,
g_object_notify (object, "manager");
break;
case PROP_WEATHER_SERVICE:
gcal_month_view_set_weather_service (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -1709,17 +1799,48 @@ gcal_month_view_get_property (GObject *object,
g_value_set_object (value, self->manager);
break;
case PROP_WEATHER_SERVICE:
g_value_set_boxed (value, gcal_month_view_get_weather_service (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/*
* Called when self is destroyed.
*
* WARNING: This is a workaround. This is one of the views where
* reference counts are off. We overwrite destroy to avoid dangling
* pointers. This issue needs to be addressed and this function removed.
*/
static void
gcal_month_view_destroyed (GtkWidget *widget)
{
GcalMonthView *self = GCAL_MONTH_VIEW (widget);
if (self->weather_service)
{
g_signal_handlers_disconnect_by_func (self->weather_service, weather_changed_cb, self);
g_clear_object (&self->weather_service);
}
GTK_WIDGET_CLASS (month_view_parent_class)->destroy ((GtkWidget*) G_TYPE_CHECK_INSTANCE_CAST (self, GTK_TYPE_GRID, GtkGrid));
}
static void
gcal_month_view_finalize (GObject *object)
{
GcalMonthView *self = GCAL_MONTH_VIEW (object);
if (self->weather_service)
{
g_signal_handlers_disconnect_by_func (self->weather_service, weather_changed_cb, self);
g_clear_object (&self->weather_service);
}
g_clear_pointer (&self->date, g_free);
g_clear_pointer (&self->children, g_hash_table_destroy);
g_clear_pointer (&self->single_cell_children, g_hash_table_destroy);
@@ -2086,6 +2207,18 @@ gcal_month_view_class_init (GcalMonthViewClass *klass)
g_object_class_override_property (object_class, PROP_DATE, "active-date");
g_object_class_override_property (object_class, PROP_MANAGER, "manager");
/**
* GcalWeekView:weather-service:
*
* Sets the weather service to use.
*/
g_object_class_install_property
(object_class,
PROP_WEATHER_SERVICE,
g_param_spec_object ("weather-service", "weather-service", "weather-service",
GCAL_TYPE_WEATHER_SERVICE,
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE));
signals[EVENT_ACTIVATED] = g_signal_new ("event-activated",
GCAL_TYPE_MONTH_VIEW,
G_SIGNAL_RUN_LAST,
@@ -2111,6 +2244,10 @@ gcal_month_view_class_init (GcalMonthViewClass *klass)
gtk_widget_class_set_css_name (widget_class, "calendar-view");
g_type_ensure (GCAL_TYPE_MONTH_POPOVER);
/* FIXME: Hack to deal with broken reference counts */
month_view_parent_class = g_type_class_peek_parent (klass);
((GtkWidgetClass *) klass)->destroy = (void (*) (GtkWidget *)) gcal_month_view_destroyed;
}
static void
@@ -2120,6 +2257,7 @@ gcal_month_view_init (GcalMonthView *self)
gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
self->weather_service = NULL;
self->children = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_list_free);
self->single_cell_children = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_list_free);
self->overflow_cells = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_list_free);
@@ -2189,3 +2327,52 @@ gcal_month_view_set_use_24h_format (GcalMonthView *self,
{
self->use_24h_format = use_24h;
}
/**
* gcal_month_view_set_weather_service:
* @self: The #GcalWeatherView instance.
* @service: (nullable): The weather service to query.
*
* Sets the service to query for weather reports.
*/
void
gcal_month_view_set_weather_service (GcalMonthView *self,
GcalWeatherService *service)
{
g_return_if_fail (GCAL_IS_MONTH_VIEW (self));
g_return_if_fail (!service || GCAL_IS_WEATHER_SERVICE (service));
if (self->weather_service == service)
return;
if (self->weather_service)
g_signal_handlers_disconnect_by_func (self->weather_service, weather_changed_cb, self);
g_set_object (&self->weather_service, service);
if (service)
{
g_signal_connect (service,
"weather-changed",
G_CALLBACK (weather_changed_cb),
self);
}
update_weather (self, TRUE);
g_object_notify (G_OBJECT (self), "weather-service");
}
/**
* gcal_month_view_get_weather_service:
* @self: The #GcalWeatherView instance.
*
* Returns: (transfer none): The internal weather service object.
*/
GcalWeatherService*
gcal_month_view_get_weather_service (GcalMonthView *self)
{
g_return_val_if_fail (GCAL_IS_MONTH_VIEW (self), NULL);
return self->weather_service;
}
+6
View File
@@ -21,6 +21,7 @@
#define __GCAL_MONTH_VIEW_H__
#include "gcal-manager.h"
#include "gcal-weather-service.h"
G_BEGIN_DECLS
@@ -34,6 +35,11 @@ void gcal_month_view_set_first_weekday (GcalMonthView
void gcal_month_view_set_use_24h_format (GcalMonthView *self,
gboolean use_24h);
void gcal_month_view_set_weather_service (GcalMonthView *self,
GcalWeatherService *service);
GcalWeatherService* gcal_month_view_get_weather_service (GcalMonthView *self);
G_END_DECLS
#endif /* __GCAL_MONTH_VIEW_H__ */