[Xfce4-commits] <xfce4-weather-plugin:master> Merge branch 'cache-data'

Harald Judt noreply at xfce.org
Sun Dec 9 23:44:35 CET 2012


Updating branch refs/heads/master
         to 7918026fe7a732cebbae73a2e29406af639bc1fa (commit)
       from 6af7d40743b5c10cc00430a6964a517eba72c698 (commit)

commit 7918026fe7a732cebbae73a2e29406af639bc1fa
Merge: 6af7d40 24d45e3
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 23:41:23 2012 +0100

    Merge branch 'cache-data'

commit 24d45e3256ac896a90e64bf3825ece68466bcbe2
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:25:09 2012 +0100

    Rewrite code for calculating forecast and current weather data.
    
    This should work much better now and is easier to read.

commit 29d0da2a09d1583e97b8a1fdf8d554079244571a
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:25:06 2012 +0100

    Add function to determine timeslice type.
    
    Check whether timeslice contains interval or point data.

commit 4eec4c7d19b113ecf422139ab0c5877b2df471a9
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:25:05 2012 +0100

    Add function for comparing xml_time structs.

commit d3c97d0e4de01fc13c451346b5a3d5ba4f74f1b7
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:25:03 2012 +0100

    Fix high download retry frequency.
    
    If download fails, retries will happen too often, four times a minute.
    That is absolutely wrong. The update code clearly needs to be rewritten,
    but let's fix that error first, set the retry interval to 3 minutes
    and fix this properly later.

commit 89a12b770faf16c3dbb0ffa2522c2bde60b3d7c6
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:56 2012 +0100

    Protect against NULL in data parsing.

commit 1eda67307db7d676cb77724805abdfed42dc444b
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:54 2012 +0100

    Fix crashes related to updates and timer handling.
    
    Closing the dialog will clear its data, so the update routine will only get
    a NULL pointer and cause a crash. Reading data from the cache file is not
    the task of the config dialog, but of the update_with_reset function, so
    it belongs there and read_cache_file can be static. Also it shouldn't happen
    after we have downloaded the new data but before it, so the new data won't
    get overwritten by the old data. Finally, set timer ids to 0 so the checks
    for them are actually useful.

commit 2081c67d3c8fe5290b4ef2365cb573f00d69223d
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:49 2012 +0100

    Add hidden option for cache file max age.
    
    Some users might not want to use cached data at all, others might want
    to increase the expiration date. However, most users won't change this
    or won't even want to know about it, so make it a hidden option instead
    of putting it somewhere in the configuration dialog.

commit 05a906619fb3393e718b037f987d0cab9f1fd06d
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:47 2012 +0100

    Set expiration date on cache file.
    
    Primarily the purpose of the cache file is to preserve data across panel
    restarts. It won't make much sense to keep old forecasts, they will be
    wrong anyway (if they were ever right). So better put an expiration
    date on the cache file and do not rely on old data. Let's try 2 days
    first - though I'd go for 24 hours actually - and tune it later, or
    perhaps make it a (hidden?) option.

commit c6c608b5fe6ec5f8155c97b80540f383ce55a92a
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:44 2012 +0100

    Rename xfceweather_data to plugin_data and fix some compile warnings.

commit e1f2d5cd89066ad06dd660302a8930e4f5462e0c
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:43 2012 +0100

    Increase download frequency of weather data to 3 times per hour.
    
    That's much better now because data won't be cleared on download.

commit c5e073f4462b05f9080bbac1066f2a617116c687
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:42 2012 +0100

    Optimize current conditions update interval a bit.
    
    Use multiples of 5 minutes when data is available.

commit 8d49530dc8d3db010a0b1fba1148c97eba32fde5
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:40 2012 +0100

    Import cached data on plugin start or location change.

commit 901a886e66085117a74b42bb73aabe3fc7e42155
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:38 2012 +0100

    Write cache file after downloading weather data.
    
    Write a file with the current weather data that can be imported on
    plugin startup or when the location changes.

commit ec83b55e004d7b66c2db064e5ebcc5af9796f507
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:37 2012 +0100

    Add make_cache_filename() helper function.

commit a822fe9ac482aaabbf362223673fcfd63a68c9bc
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:35 2012 +0100

    Add some assertions to parse_weather().

commit dca05f6933f222b668d68edc0e1102eac2172d6e
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:34 2012 +0100

    Add merge_timeslice() helper function.

commit 3105a3adee74c89f40e27e89b8a55c8509e441de
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:30 2012 +0100

    Only clear weather data on location changes, not on all downloads.
    
    Clearing weather data is only required when the location changes, otherwise
    the downloaded data can be merged.

commit 9a6b1f82ebe0152ba6d56222a595d3331269c102
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:29 2012 +0100

    Add parameter to get_timeslice() to store the index.
    
    If the calling function provides an address, store the index of the timeslice
    found in it so that it can be accessed later. If no timeslice was found,
    this value will be undefined, so the calling function has to check whether
    get_timeslice() returned NULL.

commit 2d984af0c2c53a8a55327bd25d771c244f3de758
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:27 2012 +0100

    Add xml_time_copy() helper function.

commit 7c0c6c7dab09b58e2f70acf596ab82546fbcda51
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:26 2012 +0100

    Rename parse_xml_timestring to parse_timestring and make it public.

commit bb9cc2acb6f9038d3af9fa60677324607485b1c2
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:25 2012 +0100

    Add make_timeslice() helper function.

commit 189bb0d6f014fafdaadb0f6b5e45ca395d37ae61
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:24 2012 +0100

    Clean up old weather data.
    
    Data older than a day will be removed from the timeslices array.

commit 4b609e943be937964aa92cef313a7dcfd5e018eb
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:22 2012 +0100

    Factor out code to dump timeslice data.

commit 4cafe32a4c565414ae88b27894f821788f3ac7a6
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:21 2012 +0100

    Fix possible crash in xml_weather_free().

commit b500f916eca04815f9eb0ac21da3bc1745375edb
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:21 2012 +0100

    Merge new weather data with existing one.
    
    Let's overwrite existing timeslice data and append new ones. That way,
    weather data gets updated without removing the existing data we already
    have and want to use.

commit cc9db7bb5fa11519433f5ab351a27c305ef1cdf3
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:20 2012 +0100

    Protect against some possible crashes.

commit ffecf234ed36e75113e7c0073d07ddfb74ece837
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:19 2012 +0100

    Replace variable names "data" with "wd" for weather data.
    
    Use consistent naming; "data" is usually used for plugin data,
    so make weather data distinct for clarity reasons.

commit b9fcca223ae6922deb7919060d471565e0d69062
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:17 2012 +0100

    Replace timeslice array with GArray.
    
    This makes inserting, removing and updating much easier, and the GArray
    can grow dynamically. The get_timeslice rewrite makes has_timeslice
    redundant, which is a small performance improvement.

commit 5ffddb58d7a7f2fa4bf110f30f00b92d46481c53
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:32 2012 +0100

    Make weather cache and config directory names consistent.

commit ceb132572312e560e00923379c1abc2556897151
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:04 2012 +0100

    Move code to create and get cache directory into its own function.

commit dd32a6346f87b14874ad0de07e174c4467fe8463
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:25:16 2012 +0100

    Make sure coordinates from search results do not exceed spin button precision.

commit abc52690c5c5bf6b4870c8b773625afde118f169
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:59 2012 +0100

    Fix assertion when closing summary window.

commit f8f26779f3fd840ff22970d1ebfd8f9b2fd1ff66
Author: Harald Judt <h.judt at gmx.at>
Date:   Sun Dec 9 19:24:46 2012 +0100

    Better interpolation for wind degrees.
    
    It's quite unlikely that the wind direction changes from 340 to 15 degrees
    by decrementing. The more probable direction would be incrementing from
    340 to (360 + 15) degrees, so let's do just that.

 panel-plugin/weather-config.c  |  223 ++++++++++---------
 panel-plugin/weather-config.h  |    4 +-
 panel-plugin/weather-data.c    |  477 +++++++++++++++++++++++++++-------------
 panel-plugin/weather-data.h    |   14 +-
 panel-plugin/weather-debug.c   |   62 ++++--
 panel-plugin/weather-debug.h   |    6 +-
 panel-plugin/weather-icon.c    |    2 +-
 panel-plugin/weather-parsers.c |  275 +++++++++++++++++------
 panel-plugin/weather-parsers.h |   28 ++-
 panel-plugin/weather-summary.c |   28 +--
 panel-plugin/weather-summary.h |    2 +-
 panel-plugin/weather.c         |  462 ++++++++++++++++++++++++++++++++++-----
 panel-plugin/weather.h         |   16 +-
 13 files changed, 1159 insertions(+), 440 deletions(-)

diff --git a/panel-plugin/weather-config.c b/panel-plugin/weather-config.c
index 64885b1..924f28d 100644
--- a/panel-plugin/weather-config.c
+++ b/panel-plugin/weather-config.c
@@ -116,21 +116,21 @@ static void
 update_summary_window(xfceweather_dialog *dialog,
                       gboolean restore_position)
 {
-    if (dialog->wd->summary_window) {
-        guint x, y;
+    if (dialog->pd->summary_window) {
+        gint x, y;
 
         /* remember position */
         if (restore_position)
-            gtk_window_get_position(GTK_WINDOW(dialog->wd->summary_window),
+            gtk_window_get_position(GTK_WINDOW(dialog->pd->summary_window),
                                     &x, &y);
 
         /* call toggle function two times to close and open dialog */
-        forecast_click(dialog->wd->summary_window, dialog->wd);
-        forecast_click(dialog->wd->summary_window, dialog->wd);
+        forecast_click(dialog->pd->summary_window, dialog->pd);
+        forecast_click(dialog->pd->summary_window, dialog->pd);
 
         /* ask wm to restore position of new window */
         if (restore_position)
-            gtk_window_move(GTK_WINDOW(dialog->wd->summary_window), x, y);
+            gtk_window_move(GTK_WINDOW(dialog->pd->summary_window), x, y);
 
         /* bring config dialog to the front, it might have been hidden
          * beneath the summary window */
@@ -143,13 +143,12 @@ static gboolean
 schedule_data_update(gpointer user_data)
 {
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
-
-    if (dialog == NULL)
-        return FALSE;
+    plugin_data *pd = dialog->pd;
 
     /* force update of downloaded data */
     weather_debug("Delayed update timer expired, now scheduling data update.");
-    update_weatherdata_with_reset(dialog->wd);
+    update_weatherdata_with_reset(pd, TRUE);
+
     gtk_spinner_stop(GTK_SPINNER(dialog->update_spinner));
     gtk_widget_hide(GTK_WIDGET(dialog->update_spinner));
     return FALSE;
@@ -161,12 +160,16 @@ schedule_delayed_data_update(xfceweather_dialog *dialog)
 {
     weather_debug("Starting delayed data update.");
     /* cancel any update that was scheduled before */
-    if (dialog->timer_id)
+    if (dialog->timer_id) {
         g_source_remove(dialog->timer_id);
+        dialog->timer_id = 0;
+    }
 
     /* stop any updates that could be performed by weather.c */
-    if (dialog->wd->updatetimeout)
-        g_source_remove(dialog->wd->updatetimeout);
+    if (dialog->pd->updatetimeout) {
+        g_source_remove(dialog->pd->updatetimeout);
+        dialog->pd->updatetimeout = 0;
+    }
 
     gtk_widget_show(GTK_WIDGET(dialog->update_spinner));
     gtk_spinner_start(GTK_SPINNER(dialog->update_spinner));
@@ -229,7 +232,7 @@ cb_lookup_altitude(SoupSession *session,
         alt = string_to_double(altitude->altitude, -9999);
         weather_debug("Altitude returned by GeoNames: %.0f meters", alt);
         if (alt >= -420) {
-            if (dialog->wd->units->altitude == FEET)
+            if (dialog->pd->units->altitude == FEET)
                 alt /= 0.3048;
             gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->spin_alt),
                                       alt);
@@ -279,14 +282,14 @@ lookup_altitude_timezone(const gpointer user_data)
     url = g_strdup_printf("http://api.geonames.org"
                           "/srtm3XML?lat=%s&lng=%s&username=%s",
                           &latbuf[0], &lonbuf[0], GEONAMES_USERNAME);
-    weather_http_queue_request(dialog->wd->session, url,
+    weather_http_queue_request(dialog->pd->session, url,
                                cb_lookup_altitude, user_data);
     g_free(url);
 
     /* lookup timezone */
     url = g_strdup_printf("http://www.earthtools.org/timezone/%s/%s",
                           &latbuf[0], &lonbuf[0]);
-    weather_http_queue_request(dialog->wd->session, url,
+    weather_http_queue_request(dialog->pd->session, url,
                                cb_lookup_timezone, user_data);
     g_free(url);
 }
@@ -336,7 +339,7 @@ start_auto_locate(xfceweather_dialog *dialog)
     gtk_widget_set_sensitive(dialog->text_loc_name, FALSE);
     gtk_entry_set_text(GTK_ENTRY(dialog->text_loc_name), _("Detecting..."));
     gtk_spinner_start(GTK_SPINNER(dialog->update_spinner));
-    weather_search_by_ip(dialog->wd->session, auto_locate_cb, dialog);
+    weather_search_by_ip(dialog->pd->session, auto_locate_cb, dialog);
 }
 
 
@@ -346,16 +349,22 @@ cb_findlocation(GtkButton *button,
 {
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
     search_dialog *sdialog;
-    gchar *loc_name;
+    gchar *loc_name, *lat, *lon;
+    gchar latbuf[15], lonbuf[15];
 
-    sdialog = create_search_dialog(NULL, dialog->wd->session);
+    sdialog = create_search_dialog(NULL, dialog->pd->session);
 
     gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
     if (run_search_dialog(sdialog)) {
+        /* limit digit precision of coordinates from search results */
+        lat = g_ascii_formatd(latbuf, 15, "%.7f",
+                              string_to_double(sdialog->result_lat, 0));
         gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->spin_lat),
-                                  string_to_double(sdialog->result_lat, 0));
+                                  string_to_double(lat, 0));
+        lon = g_ascii_formatd(lonbuf, 15, "%.7f",
+                              string_to_double(sdialog->result_lon, 0));
         gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->spin_lon),
-                                  string_to_double(sdialog->result_lon, 0));
+                                  string_to_double(lon, 0));
         loc_name = sanitize_location_name(sdialog->result_name);
         gtk_entry_set_text(GTK_ENTRY(dialog->text_loc_name), loc_name);
         g_free(loc_name);
@@ -375,14 +384,14 @@ setup_altitude(xfceweather_dialog *dialog)
     g_signal_handlers_block_by_func(dialog->spin_alt,
                                     G_CALLBACK(spin_alt_value_changed),
                                     dialog);
-    switch (dialog->wd->units->altitude) {
+    switch (dialog->pd->units->altitude) {
     case METERS:
         gtk_label_set_text(GTK_LABEL(dialog->label_alt_unit),
                            _("meters"));
         gtk_spin_button_set_range(GTK_SPIN_BUTTON(dialog->spin_alt),
                                   -420, 10000);
         gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->spin_alt),
-                                  (gdouble) (dialog->wd->msl));
+                                  (gdouble) (dialog->pd->msl));
         break;
 
     case FEET:
@@ -391,7 +400,7 @@ setup_altitude(xfceweather_dialog *dialog)
         gtk_spin_button_set_range(GTK_SPIN_BUTTON(dialog->spin_alt),
                                   -1378.0, 32808);
         gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->spin_alt),
-                                  (gdouble) dialog->wd->msl / 0.3048);
+                                  (gdouble) dialog->pd->msl / 0.3048);
         break;
     }
     g_signal_handlers_unblock_by_func(dialog->spin_alt,
@@ -406,8 +415,8 @@ text_loc_name_changed(const GtkWidget *spin,
                       gpointer user_data)
 {
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
-    g_free(dialog->wd->location_name);
-    dialog->wd->location_name =
+    g_free(dialog->pd->location_name);
+    dialog->pd->location_name =
         g_strdup(gtk_entry_get_text(GTK_ENTRY(dialog->text_loc_name)));
 }
 
@@ -421,8 +430,8 @@ spin_lat_value_changed(const GtkWidget *spin,
     gdouble val;
 
     val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin));
-    g_free(dialog->wd->lat);
-    dialog->wd->lat = g_strdup(g_ascii_formatd(latbuf, 10, "%.6f", val));
+    g_free(dialog->pd->lat);
+    dialog->pd->lat = g_strdup(g_ascii_formatd(latbuf, 10, "%.6f", val));
     schedule_delayed_data_update(dialog);
 }
 
@@ -436,8 +445,8 @@ spin_lon_value_changed(const GtkWidget *spin,
     gdouble val;
 
     val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin));
-    g_free(dialog->wd->lon);
-    dialog->wd->lon = g_strdup(g_ascii_formatd(lonbuf, 10, "%.6f", val));
+    g_free(dialog->pd->lon);
+    dialog->pd->lon = g_strdup(g_ascii_formatd(lonbuf, 10, "%.6f", val));
     schedule_delayed_data_update(dialog);
 }
 
@@ -450,9 +459,9 @@ spin_alt_value_changed(const GtkWidget *spin,
     gdouble val;
 
     val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin));
-    if (dialog->wd->units->altitude == FEET)
+    if (dialog->pd->units->altitude == FEET)
         val *= 0.3048;
-    dialog->wd->msl = (gint) val;
+    dialog->pd->msl = (gint) val;
     schedule_delayed_data_update(dialog);
 }
 
@@ -463,7 +472,7 @@ spin_timezone_value_changed(const GtkWidget *spin,
 {
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
 
-    dialog->wd->timezone =
+    dialog->pd->timezone =
         gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
 }
 
@@ -501,9 +510,9 @@ create_location_page(xfceweather_dialog *dialog)
                      G_CALLBACK(cb_findlocation), dialog);
     gtk_box_pack_start(GTK_BOX(hbox), button_loc_change,
                        FALSE, FALSE, 0);
-    if (dialog->wd->location_name)
+    if (dialog->pd->location_name)
         gtk_entry_set_text(GTK_ENTRY(dialog->text_loc_name),
-                           dialog->wd->location_name);
+                           dialog->pd->location_name);
     else
         gtk_entry_set_text(GTK_ENTRY(dialog->text_loc_name), _("Unset"));
     /* update spinner */
@@ -516,7 +525,7 @@ create_location_page(xfceweather_dialog *dialog)
     hbox = gtk_hbox_new(FALSE, BORDER);
     ADD_LABEL(_("Latitud_e:"), sg_label);
     ADD_SPIN(dialog->spin_lat, -90, 90, 1,
-             (string_to_double(dialog->wd->lat, 0)), 6, sg_spin);
+             (string_to_double(dialog->pd->lat, 0)), 6, sg_spin);
     SET_TOOLTIP(dialog->spin_lat,
                 _("Latitude specifies the north-south position of a point on "
                   "the Earth's surface. If you change this value manually, "
@@ -530,7 +539,7 @@ create_location_page(xfceweather_dialog *dialog)
     hbox = gtk_hbox_new(FALSE, BORDER);
     ADD_LABEL(_("L_ongitude:"), sg_label);
     ADD_SPIN(dialog->spin_lon, -180, 180, 1,
-             (string_to_double(dialog->wd->lon, 0)), 6, sg_spin);
+             (string_to_double(dialog->pd->lon, 0)), 6, sg_spin);
     SET_TOOLTIP(dialog->spin_lon,
                 _("Longitude specifies the east-west position of a point on "
                   "the Earth's surface. If you change this value manually, "
@@ -543,7 +552,7 @@ create_location_page(xfceweather_dialog *dialog)
     /* altitude */
     hbox = gtk_hbox_new(FALSE, BORDER);
     ADD_LABEL(_("_Altitude:"), sg_label);
-    ADD_SPIN(dialog->spin_alt, -420, 10000, 1, dialog->wd->msl, 0, sg_spin);
+    ADD_SPIN(dialog->spin_alt, -420, 10000, 1, dialog->pd->msl, 0, sg_spin);
     SET_TOOLTIP
         (dialog->spin_alt,
          _("For locations outside Norway the elevation model that's used by "
@@ -567,7 +576,7 @@ create_location_page(xfceweather_dialog *dialog)
     hbox = gtk_hbox_new(FALSE, BORDER);
     ADD_LABEL(_("_Timezone:"), sg_label);
     ADD_SPIN(dialog->spin_timezone, -24, 24, 1,
-             dialog->wd->timezone, 0, sg_spin);
+             dialog->pd->timezone, 0, sg_spin);
     SET_TOOLTIP
         (dialog->spin_timezone,
          _("If the chosen location is not in your current timezone, this "
@@ -602,9 +611,9 @@ combo_unit_temperature_changed(GtkWidget *combo,
                                gpointer user_data)
 {
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
-    dialog->wd->units->temperature =
+    dialog->pd->units->temperature =
         gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
-    update_scrollbox(dialog->wd);
+    update_scrollbox(dialog->pd);
     update_summary_window(dialog, TRUE);
 }
 
@@ -614,9 +623,9 @@ combo_unit_pressure_changed(GtkWidget *combo,
                             gpointer user_data)
 {
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
-    dialog->wd->units->pressure =
+    dialog->pd->units->pressure =
         gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
-    update_scrollbox(dialog->wd);
+    update_scrollbox(dialog->pd);
     update_summary_window(dialog, TRUE);
 }
 
@@ -626,9 +635,9 @@ combo_unit_windspeed_changed(GtkWidget *combo,
                              gpointer user_data)
 {
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
-    dialog->wd->units->windspeed =
+    dialog->pd->units->windspeed =
         gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
-    update_scrollbox(dialog->wd);
+    update_scrollbox(dialog->pd);
     update_summary_window(dialog, TRUE);
 }
 
@@ -638,9 +647,9 @@ combo_unit_precipitations_changed(GtkWidget *combo,
                                   gpointer user_data)
 {
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
-    dialog->wd->units->precipitations =
+    dialog->pd->units->precipitations =
         gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
-    update_scrollbox(dialog->wd);
+    update_scrollbox(dialog->pd);
     update_summary_window(dialog, TRUE);
 }
 
@@ -651,7 +660,7 @@ combo_unit_altitude_changed(GtkWidget *combo,
 {
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
 
-    dialog->wd->units->altitude =
+    dialog->pd->units->altitude =
         gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
     setup_altitude(dialog);
     update_summary_window(dialog, TRUE);
@@ -725,8 +734,8 @@ create_units_page(xfceweather_dialog *dialog)
     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, BORDER);
 
     /* initialize widgets with current data */
-    if (dialog->wd)
-        setup_units(dialog, dialog->wd->units);
+    if (dialog->pd)
+        setup_units(dialog, dialog->pd->units);
 
     gtk_box_pack_start(GTK_BOX(page), vbox, FALSE, FALSE, 0);
     g_object_unref(G_OBJECT(sg_label));
@@ -741,7 +750,7 @@ combo_icon_theme_set_tooltip(GtkWidget *combo,
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
     gchar *text;
 
-    if (G_UNLIKELY(dialog->wd->icon_theme == NULL)) {
+    if (G_UNLIKELY(dialog->pd->icon_theme == NULL)) {
         /* this should never happen, but who knows... */
         gtk_widget_set_tooltip_text(GTK_WIDGET(combo),
                                     _("Choose an icon theme."));
@@ -753,10 +762,10 @@ combo_icon_theme_set_tooltip(GtkWidget *combo,
            "<b>Author:</b> %s\n\n"
            "<b>Description:</b> %s\n\n"
            "<b>License:</b> %s"),
-           TEXT_UNKNOWN(dialog->wd->icon_theme->dir),
-           TEXT_UNKNOWN(dialog->wd->icon_theme->author),
-           TEXT_UNKNOWN(dialog->wd->icon_theme->description),
-           TEXT_UNKNOWN(dialog->wd->icon_theme->license));
+           TEXT_UNKNOWN(dialog->pd->icon_theme->dir),
+           TEXT_UNKNOWN(dialog->pd->icon_theme->author),
+           TEXT_UNKNOWN(dialog->pd->icon_theme->description),
+           TEXT_UNKNOWN(dialog->pd->icon_theme->license));
     gtk_widget_set_tooltip_markup(GTK_WIDGET(combo), text);
     g_free(text);
 }
@@ -774,14 +783,14 @@ combo_icon_theme_changed(GtkWidget *combo,
     if (G_UNLIKELY(i == -1))
         return;
 
-    theme = g_array_index(dialog->icon_themes, icon_theme*, i);
+    theme = g_array_index(dialog->icon_themes, icon_theme *, i);
     if (G_UNLIKELY(theme == NULL))
         return;
 
-    icon_theme_free(dialog->wd->icon_theme);
-    dialog->wd->icon_theme = icon_theme_copy(theme);
+    icon_theme_free(dialog->pd->icon_theme);
+    dialog->pd->icon_theme = icon_theme_copy(theme);
     combo_icon_theme_set_tooltip(combo, dialog);
-    update_icon(dialog->wd);
+    update_icon(dialog->pd);
     update_summary_window(dialog, TRUE);
 }
 
@@ -791,7 +800,7 @@ combo_tooltip_style_changed(GtkWidget *combo,
                             gpointer user_data)
 {
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
-    dialog->wd->tooltip_style = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
+    dialog->pd->tooltip_style = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
 }
 
 
@@ -800,7 +809,7 @@ combo_forecast_layout_changed(GtkWidget *combo,
                               gpointer user_data)
 {
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
-    dialog->wd->forecast_layout =
+    dialog->pd->forecast_layout =
         gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
     update_summary_window(dialog, FALSE);
 }
@@ -811,7 +820,7 @@ spin_forecast_days_value_changed(const GtkWidget *spin,
                                  gpointer user_data)
 {
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
-    dialog->wd->forecast_days =
+    dialog->pd->forecast_days =
         gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
     update_summary_window(dialog, FALSE);
 }
@@ -822,9 +831,9 @@ check_round_values_toggled(GtkWidget *button,
                            gpointer user_data)
 {
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
-    dialog->wd->round =
+    dialog->pd->round =
         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
-    update_scrollbox(dialog->wd);
+    update_scrollbox(dialog->pd);
     update_summary_window(dialog, TRUE);
 }
 
@@ -848,11 +857,11 @@ create_appearance_page(xfceweather_dialog *dialog)
     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
     dialog->icon_themes = find_icon_themes();
     for (i = 0; i < dialog->icon_themes->len; i++) {
-        theme = g_array_index(dialog->icon_themes, icon_theme*, i);
+        theme = g_array_index(dialog->icon_themes, icon_theme *, i);
         ADD_COMBO_VALUE(dialog->combo_icon_theme, theme->name);
         /* set selection to current theme */
-        if (G_LIKELY(dialog->wd->icon_theme) &&
-            !strcmp(theme->dir, dialog->wd->icon_theme->dir)) {
+        if (G_LIKELY(dialog->pd->icon_theme) &&
+            !strcmp(theme->dir, dialog->pd->icon_theme->dir)) {
             SET_COMBO_VALUE(dialog->combo_icon_theme, i);
             combo_icon_theme_set_tooltip(dialog->combo_icon_theme, dialog);
         }
@@ -864,7 +873,7 @@ create_appearance_page(xfceweather_dialog *dialog)
     ADD_COMBO(dialog->combo_tooltip_style);
     ADD_COMBO_VALUE(dialog->combo_tooltip_style, _("Simple"));
     ADD_COMBO_VALUE(dialog->combo_tooltip_style, _("Verbose"));
-    SET_COMBO_VALUE(dialog->combo_tooltip_style, dialog->wd->tooltip_style);
+    SET_COMBO_VALUE(dialog->combo_tooltip_style, dialog->pd->tooltip_style);
     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
     gtk_box_pack_start(GTK_BOX(page), vbox, FALSE, FALSE, 0);
 
@@ -879,14 +888,14 @@ create_appearance_page(xfceweather_dialog *dialog)
     ADD_COMBO_VALUE(dialog->combo_forecast_layout, _("Days in columns"));
     ADD_COMBO_VALUE(dialog->combo_forecast_layout, _("Days in rows"));
     SET_COMBO_VALUE(dialog->combo_forecast_layout,
-                    dialog->wd->forecast_layout);
+                    dialog->pd->forecast_layout);
     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
 
     /* number of days shown in forecast */
     hbox = gtk_hbox_new(FALSE, BORDER);
     ADD_LABEL(_("_Number of forecast _days:"), sg);
     ADD_SPIN(dialog->spin_forecast_days, 1, MAX_FORECAST_DAYS, 1,
-             (dialog->wd->forecast_days ? dialog->wd->forecast_days : 5),
+             (dialog->pd->forecast_days ? dialog->pd->forecast_days : 5),
              0, NULL);
     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
     gtk_box_pack_start(GTK_BOX(page), vbox, FALSE, FALSE, 0);
@@ -904,7 +913,7 @@ create_appearance_page(xfceweather_dialog *dialog)
     gtk_box_pack_start(GTK_BOX(vbox), dialog->check_round_values,
                        FALSE, FALSE, 0);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->check_round_values),
-                                 dialog->wd->round);
+                                 dialog->pd->round);
 
     gtk_box_pack_start(GTK_BOX(page), vbox, FALSE, FALSE, 0);
     g_object_unref(G_OBJECT(sg));
@@ -917,9 +926,9 @@ check_scrollbox_show_toggled(GtkWidget *button,
                              gpointer user_data)
 {
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
-    dialog->wd->show_scrollbox =
+    dialog->pd->show_scrollbox =
         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
-    scrollbox_set_visible(dialog->wd);
+    scrollbox_set_visible(dialog->pd);
 }
 
 
@@ -928,9 +937,9 @@ spin_scrollbox_lines_value_changed(const GtkWidget *spin,
                                    gpointer user_data)
 {
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
-    dialog->wd->scrollbox_lines =
+    dialog->pd->scrollbox_lines =
         (guint) gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
-    update_scrollbox(dialog->wd);
+    update_scrollbox(dialog->pd);
 }
 
 
@@ -945,9 +954,9 @@ button_scrollbox_font_pressed(GtkWidget *button,
         return FALSE;
 
     if (event->button == 2) {
-        g_free(dialog->wd->scrollbox_font);
-        dialog->wd->scrollbox_font = NULL;
-        gtk_scrollbox_set_fontname(GTK_SCROLLBOX(dialog->wd->scrollbox),
+        g_free(dialog->pd->scrollbox_font);
+        dialog->pd->scrollbox_font = NULL;
+        gtk_scrollbox_set_fontname(GTK_SCROLLBOX(dialog->pd->scrollbox),
                                    NULL);
         gtk_button_set_label(GTK_BUTTON(button), _("Select _font"));
         return TRUE;
@@ -967,18 +976,18 @@ button_scrollbox_font_clicked(GtkWidget *button,
 
     fsd = GTK_FONT_SELECTION_DIALOG
         (gtk_font_selection_dialog_new(_("Select font")));
-    if (dialog->wd->scrollbox_font)
+    if (dialog->pd->scrollbox_font)
         gtk_font_selection_dialog_set_font_name(fsd,
-                                                dialog->wd->scrollbox_font);
+                                                dialog->pd->scrollbox_font);
 
     result = gtk_dialog_run(GTK_DIALOG(fsd));
     if (result == GTK_RESPONSE_OK || result == GTK_RESPONSE_ACCEPT) {
         fontname = gtk_font_selection_dialog_get_font_name(fsd);
         if (fontname != NULL) {
             gtk_button_set_label(GTK_BUTTON(button), fontname);
-            g_free(dialog->wd->scrollbox_font);
-            dialog->wd->scrollbox_font = fontname;
-            gtk_scrollbox_set_fontname(GTK_SCROLLBOX(dialog->wd->scrollbox),
+            g_free(dialog->pd->scrollbox_font);
+            dialog->pd->scrollbox_font = fontname;
+            gtk_scrollbox_set_fontname(GTK_SCROLLBOX(dialog->pd->scrollbox),
                                        fontname);
         }
     }
@@ -1001,8 +1010,8 @@ button_scrollbox_color_pressed(GtkWidget *button,
         return FALSE;
 
     if (event->button == 2) {
-        dialog->wd->scrollbox_use_color = FALSE;
-        gtk_scrollbox_clear_color(GTK_SCROLLBOX(dialog->wd->scrollbox));
+        dialog->pd->scrollbox_use_color = FALSE;
+        gtk_scrollbox_clear_color(GTK_SCROLLBOX(dialog->pd->scrollbox));
         return TRUE;
     }
 
@@ -1017,10 +1026,10 @@ button_scrollbox_color_set(GtkWidget *button,
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
 
     gtk_color_button_get_color(GTK_COLOR_BUTTON(button),
-                               &(dialog->wd->scrollbox_color));
-    gtk_scrollbox_set_color(GTK_SCROLLBOX(dialog->wd->scrollbox),
-                            dialog->wd->scrollbox_color);
-    dialog->wd->scrollbox_use_color = TRUE;
+                               &(dialog->pd->scrollbox_color));
+    gtk_scrollbox_set_color(GTK_SCROLLBOX(dialog->pd->scrollbox),
+                            dialog->pd->scrollbox_color);
+    dialog->pd->scrollbox_use_color = TRUE;
 }
 
 
@@ -1051,7 +1060,7 @@ update_scrollbox_labels(xfceweather_dialog *dialog)
     GValue value = { 0 };
     gint option;
 
-    dialog->wd->labels = labels_clear(dialog->wd->labels);
+    dialog->pd->labels = labels_clear(dialog->pd->labels);
     hasiter =
         gtk_tree_model_get_iter_first(GTK_TREE_MODEL
                                       (dialog->model_datatypes),
@@ -1060,13 +1069,13 @@ update_scrollbox_labels(xfceweather_dialog *dialog)
         gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model_datatypes),
                                  &iter, 1, &value);
         option = g_value_get_int(&value);
-        g_array_append_val(dialog->wd->labels, option);
+        g_array_append_val(dialog->pd->labels, option);
         g_value_unset(&value);
         hasiter =
             gtk_tree_model_iter_next(GTK_TREE_MODEL(dialog->model_datatypes),
                                      &iter);
     }
-    update_scrollbox(dialog->wd);
+    update_scrollbox(dialog->pd);
 }
 
 
@@ -1183,10 +1192,10 @@ check_scrollbox_animate_toggled(GtkWidget *button,
                                 gpointer user_data)
 {
     xfceweather_dialog *dialog = (xfceweather_dialog *) user_data;
-    dialog->wd->scrollbox_animate =
+    dialog->pd->scrollbox_animate =
         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
-    gtk_scrollbox_set_animate(GTK_SCROLLBOX(dialog->wd->scrollbox),
-                              dialog->wd->scrollbox_animate);
+    gtk_scrollbox_set_animate(GTK_SCROLLBOX(dialog->pd->scrollbox),
+                              dialog->pd->scrollbox_animate);
 }
 
 
@@ -1213,14 +1222,14 @@ create_scrollbox_page(xfceweather_dialog *dialog)
                        TRUE, TRUE, 0);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
                                  (dialog->check_scrollbox_show),
-                                 dialog->wd->show_scrollbox);
+                                 dialog->pd->show_scrollbox);
 
     /* values to show at once (multiple lines) */
     label = gtk_label_new_with_mnemonic(_("L_ines:"));
     gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
     gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
     ADD_SPIN(dialog->spin_scrollbox_lines, 1, MAX_SCROLLBOX_LINES, 1,
-             dialog->wd->scrollbox_lines, 0, sg_misc);
+             dialog->pd->scrollbox_lines, 0, sg_misc);
     SET_TOOLTIP
         (dialog->spin_scrollbox_lines,
          _("Decide how many values should be shown at once in the scrollbox. "
@@ -1242,11 +1251,11 @@ create_scrollbox_page(xfceweather_dialog *dialog)
            "theme's default."));
     gtk_box_pack_start(GTK_BOX(hbox), dialog->button_scrollbox_font,
                        TRUE, TRUE, 0);
-    if (dialog->wd->scrollbox_font)
+    if (dialog->pd->scrollbox_font)
         gtk_button_set_label(GTK_BUTTON(dialog->button_scrollbox_font),
-                             dialog->wd->scrollbox_font);
+                             dialog->pd->scrollbox_font);
     dialog->button_scrollbox_color =
-        gtk_color_button_new_with_color(&(dialog->wd->scrollbox_color));
+        gtk_color_button_new_with_color(&(dialog->pd->scrollbox_color));
     gtk_size_group_add_widget(sg_misc, dialog->button_scrollbox_color);
     SET_TOOLTIP
         (dialog->button_scrollbox_color,
@@ -1326,9 +1335,9 @@ create_scrollbox_page(xfceweather_dialog *dialog)
     gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, 0);
     gtk_box_pack_start(GTK_BOX(page), hbox, FALSE, FALSE, 0);
 
-    if (dialog->wd->labels->len > 0) {
-        for (i = 0; i < dialog->wd->labels->len; i++) {
-            type = g_array_index(dialog->wd->labels, data_types, i);
+    if (dialog->pd->labels->len > 0) {
+        for (i = 0; i < dialog->pd->labels->len; i++) {
+            type = g_array_index(dialog->pd->labels, data_types, i);
 
             if ((n = option_i(type)) != -1)
                 add_model_option(dialog->model_datatypes, n);
@@ -1339,7 +1348,7 @@ create_scrollbox_page(xfceweather_dialog *dialog)
         (_("Animate _transitions between labels"));
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
                                  (dialog->check_scrollbox_animate),
-                                 dialog->wd->scrollbox_animate);
+                                 dialog->pd->scrollbox_animate);
     SET_TOOLTIP(dialog->check_scrollbox_animate,
                 _("Scroll the current displayed value(s) out and the "
                   "new value(s) in instead of simply changing them. "
@@ -1419,14 +1428,14 @@ setup_notebook_signals(xfceweather_dialog *dialog)
 
 
 xfceweather_dialog *
-create_config_dialog(xfceweather_data *data,
+create_config_dialog(plugin_data *data,
                      GtkWidget *vbox)
 {
     xfceweather_dialog *dialog;
     GtkWidget *notebook;
 
     dialog = g_slice_new0(xfceweather_dialog);
-    dialog->wd = (xfceweather_data *) data;
+    dialog->pd = (plugin_data *) data;
     dialog->dialog = gtk_widget_get_toplevel(vbox);
 
     notebook = gtk_notebook_new();
@@ -1445,7 +1454,7 @@ create_config_dialog(xfceweather_data *data,
     setup_notebook_signals(dialog);
 
     /* automatically detect current location if it is yet unknown */
-    if (!(dialog->wd->lat && dialog->wd->lon))
+    if (!(dialog->pd->lat && dialog->pd->lon))
         start_auto_locate(dialog);
 
     gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
diff --git a/panel-plugin/weather-config.h b/panel-plugin/weather-config.h
index c95e626..e4919f9 100644
--- a/panel-plugin/weather-config.h
+++ b/panel-plugin/weather-config.h
@@ -28,7 +28,7 @@ typedef struct {
 
 typedef struct {
     GtkWidget *dialog;
-    xfceweather_data *wd;
+    plugin_data *pd;
     guint timer_id;
 
     /* location page */
@@ -67,7 +67,7 @@ typedef struct {
 } xfceweather_dialog;
 
 
-xfceweather_dialog *create_config_dialog(xfceweather_data *data,
+xfceweather_dialog *create_config_dialog(plugin_data *data,
                                          GtkWidget *vbox);
 
 G_END_DECLS
diff --git a/panel-plugin/weather-data.c b/panel-plugin/weather-data.c
index a30b062..7e50a2c 100644
--- a/panel-plugin/weather-data.c
+++ b/panel-plugin/weather-data.c
@@ -36,37 +36,31 @@
 
 #define ROUND_TO_INT(default_format) (round ? "%.0f" : default_format)
 
-#define LOCALE_DOUBLE(value, format)                \
-    (g_strdup_printf(format,                        \
-                     g_ascii_strtod(value, NULL)))
-
-#define INTERPOLATE_OR_COPY(var)                                        \
-    if (ipol)                                                           \
-        comb->location->var =                                           \
-            interpolate_gchar_value(start->location->var,               \
-                                    end->location->var,                 \
-                                    comb->start, comb->end,             \
-                                    comb->point);                       \
-    else                                                                \
+#define LOCALE_DOUBLE(value, format)                        \
+    (value                                                  \
+     ? g_strdup_printf(format, g_ascii_strtod(value, NULL)) \
+     : g_strdup(""))
+
+#define INTERPOLATE_OR_COPY(var, radian)                    \
+    if (ipol)                                               \
+        comb->location->var =                               \
+            interpolate_gchar_value(start->location->var,   \
+                                    end->location->var,     \
+                                    comb->start, comb->end, \
+                                    comb->point, radian);   \
+    else                                                    \
         comb->location->var = g_strdup(end->location->var);
 
 #define COMB_END_COPY(var)                              \
     comb->location->var = g_strdup(end->location->var);
 
 
-static gboolean
-has_timeslice(xml_weather *data,
-              const time_t start_t,
-              const time_t end_t)
-{
-    guint i = 0;
-
-    for (i = 0; i < data->num_timeslices; i++)
-        if (data->timeslice[i]->start == start_t &&
-            data->timeslice[i]->end == end_t)
-            return TRUE;
-    return FALSE;
-}
+/* struct to store results from searches for point data */
+typedef struct {
+    GArray *before;
+    time_t point;
+    GArray *after;
+} point_data_results;
 
 
 /* convert string to a double value, returning backup value on error */
@@ -81,6 +75,15 @@ string_to_double(const gchar *str,
 }
 
 
+/* check whether timeslice is interval or point data */
+gboolean
+timeslice_is_interval(xml_time *timeslice)
+{
+    return (timeslice->location->symbol != NULL ||
+            timeslice->location->precipitation_value != NULL);
+}
+
+
 gchar *
 get_data(const xml_time *timeslice,
          const units_config *units,
@@ -297,47 +300,6 @@ is_night_time(const xml_astro *astro)
 
 
 /*
- * Calculate start and end of a daytime interval using given dates.
- * We ought to take one of the intervals supplied by the XML feed,
- * which gives the most consistent data and does not force too many
- * searches to find something that fits. The following chosen
- * intervals were pretty reliable for several tested locations at the
- * time of this writing and gave reasonable results:
- *   Morning:   08:00-14:00
- *   Afternoon: 14:00-20:00
- *   Evening:   20:00-02:00
- *   Night:     02:00-08:00
- */
-static void
-get_daytime_interval(struct tm *start_tm,
-                     struct tm *end_tm,
-                     const daytime dt)
-{
-    start_tm->tm_min = end_tm->tm_min = 0;
-    start_tm->tm_sec = end_tm->tm_sec = 0;
-    start_tm->tm_isdst = end_tm->tm_isdst = -1;
-    switch (dt) {
-    case MORNING:
-        start_tm->tm_hour = 8;
-        end_tm->tm_hour = 14;
-        break;
-    case AFTERNOON:
-        start_tm->tm_hour = 14;
-        end_tm->tm_hour = 20;
-        break;
-    case EVENING:
-        start_tm->tm_hour = 20;
-        end_tm->tm_hour = 26;
-        break;
-    case NIGHT:
-        start_tm->tm_hour = 26;
-        end_tm->tm_hour = 32;
-        break;
-    }
-}
-
-
-/*
  * Return wind direction name (S, N, W,...) for wind degrees.
  */
 static gchar*
@@ -414,12 +376,13 @@ interpolate_gchar_value(gchar *value_start,
                         gchar *value_end,
                         time_t start_t,
                         time_t end_t,
-                        time_t between_t)
+                        time_t between_t,
+                        gboolean radian)
 {
     gchar value_result[10];
     gdouble val_start, val_end, val_result;
 
-    if (value_end == NULL)
+    if (G_UNLIKELY(value_end == NULL))
         return NULL;
 
     if (value_start == NULL)
@@ -428,8 +391,16 @@ interpolate_gchar_value(gchar *value_start,
     val_start = string_to_double(value_start, 0);
     val_end = string_to_double(value_end, 0);
 
+    if (radian)
+        if (val_end > val_start && val_end - val_start > 180)
+            val_start += 360;
+        else if (val_start > val_end && val_start - val_end > 180)
+            val_end += 360;
     val_result = interpolate_value(val_start, val_end,
                                    start_t, end_t, between_t);
+    if (radian && val_result >= 360)
+        val_result -= 360;
+
     weather_debug("Interpolated data: start=%f, end=%f, result=%f",
                   val_start, val_end, val_result);
     (void) g_ascii_formatd(value_result, 10, "%.1f", val_result);
@@ -440,7 +411,7 @@ interpolate_gchar_value(gchar *value_start,
 
 /* Create a new combined timeslice, with optionally interpolated data */
 static xml_time *
-make_combined_timeslice(xml_weather *data,
+make_combined_timeslice(xml_weather *wd,
                         const xml_time *interval,
                         const time_t *between_t)
 {
@@ -450,12 +421,10 @@ make_combined_timeslice(xml_weather *data,
     guint i;
 
     /* find point data at start of interval (may not be available) */
-    if (has_timeslice(data, interval->start, interval->start))
-        start = get_timeslice(data, interval->start, interval->start);
+    start = get_timeslice(wd, interval->start, interval->start, NULL);
 
     /* find point interval at end of interval */
-    if (has_timeslice(data, interval->end, interval->end))
-        end = get_timeslice(data, interval->end, interval->end);
+    end = get_timeslice(wd, interval->end, interval->end, NULL);
 
     if (start == NULL && end == NULL)
         return NULL;
@@ -491,25 +460,25 @@ make_combined_timeslice(xml_weather *data,
     COMB_END_COPY(latitude);
     COMB_END_COPY(longitude);
 
-    INTERPOLATE_OR_COPY(temperature_value);
+    INTERPOLATE_OR_COPY(temperature_value, FALSE);
     COMB_END_COPY(temperature_unit);
 
-    INTERPOLATE_OR_COPY(wind_dir_deg);
+    INTERPOLATE_OR_COPY(wind_dir_deg, TRUE);
     comb->location->wind_dir_name =
         g_strdup(wind_dir_name_by_deg(comb->location->wind_dir_deg, FALSE));
 
-    INTERPOLATE_OR_COPY(wind_speed_mps);
-    INTERPOLATE_OR_COPY(wind_speed_beaufort);
-    INTERPOLATE_OR_COPY(humidity_value);
+    INTERPOLATE_OR_COPY(wind_speed_mps, FALSE);
+    INTERPOLATE_OR_COPY(wind_speed_beaufort, FALSE);
+    INTERPOLATE_OR_COPY(humidity_value, FALSE);
     COMB_END_COPY(humidity_unit);
 
-    INTERPOLATE_OR_COPY(pressure_value);
+    INTERPOLATE_OR_COPY(pressure_value, FALSE);
     COMB_END_COPY(pressure_unit);
 
     for (i = 0; i < CLOUDS_PERC_NUM; i++)
-        INTERPOLATE_OR_COPY(clouds_percent[i]);
+        INTERPOLATE_OR_COPY(clouds_percent[i], FALSE);
 
-    INTERPOLATE_OR_COPY(fog_percent);
+    INTERPOLATE_OR_COPY(fog_percent, FALSE);
 
     /* it makes no sense to interpolate the following (interval) values */
     comb->location->precipitation_value =
@@ -524,13 +493,47 @@ make_combined_timeslice(xml_weather *data,
 }
 
 
+void
+merge_timeslice(xml_weather *wd,
+                const xml_time *timeslice)
+{
+    xml_time *old_ts, *new_ts;
+    time_t now_t = time(NULL);
+    guint i;
+
+    g_assert(wd != NULL);
+    if (G_UNLIKELY(wd == NULL))
+        return;
+
+    /* first check if it isn't too old */
+    if (difftime(now_t, timeslice->end) > DATA_EXPIRY_TIME) {
+        weather_debug("Not merging timeslice because it has expired.");
+        return;
+    }
+
+    /* Copy timeslice, as it will be deleted by the calling function */
+    new_ts = xml_time_copy(timeslice);
+
+    /* check if there is a timeslice with the same interval and
+       replace it with the current data */
+    old_ts = get_timeslice(wd, timeslice->start, timeslice->end, &i);
+    if (old_ts) {
+        xml_time_free(old_ts);
+        g_array_remove_index(wd->timeslices, i);
+        g_array_insert_val(wd->timeslices, i, new_ts);
+        weather_debug("Replaced existing timeslice at %d.", i);
+    } else {
+        g_array_prepend_val(wd->timeslices, new_ts);
+        //weather_debug("Prepended timeslice to the existing timeslices.");
+    }
+}
+
+
 /* Return current weather conditions, or NULL if not available. */
 xml_time *
-get_current_conditions(const xml_weather *data)
+get_current_conditions(const xml_weather *wd)
 {
-    if (data == NULL)
-        return NULL;
-    return data->current_conditions;
+    return wd ? wd->current_conditions : NULL;
 }
 
 
@@ -587,12 +590,13 @@ time_calc_day(const struct tm time_tm,
  * next_hours_limit hours into the future.
  */
 static xml_time *
-find_timeslice(xml_weather *data,
+find_timeslice(xml_weather *wd,
                struct tm start_tm,
                struct tm end_tm,
                const gint prev_hours_limit,
                const gint next_hours_limit)
 {
+    xml_time *timeslice;
     time_t start_t, end_t;
     gint hours = 0;
 
@@ -606,8 +610,8 @@ find_timeslice(xml_weather *data,
             start_t = time_calc_hour(start_tm, 0 - hours);
             end_t = time_calc_hour(end_tm, 0 - hours);
 
-            if (has_timeslice(data, start_t, end_t))
-                return get_timeslice(data, start_t, end_t);
+            if ((timeslice = get_timeslice(wd, start_t, end_t, NULL)))
+                return timeslice;
         }
 
         /* check later hours */
@@ -615,8 +619,8 @@ find_timeslice(xml_weather *data,
             start_t = time_calc_hour(start_tm, hours);
             end_t = time_calc_hour(end_tm, hours);
 
-            if (has_timeslice(data, start_t, end_t))
-                return get_timeslice(data, start_t, end_t);
+            if ((timeslice = get_timeslice(wd, start_t, end_t, NULL)))
+                return timeslice;
         }
         hours++;
     }
@@ -629,7 +633,7 @@ find_timeslice(xml_weather *data,
  * and end times
  */
 static xml_time *
-find_shortest_timeslice(xml_weather *data,
+find_shortest_timeslice(xml_weather *wd,
                         struct tm start_tm,
                         struct tm end_tm,
                         const gint prev_hours_limit,
@@ -654,7 +658,7 @@ find_shortest_timeslice(xml_weather *data,
     interval = (gint) (difftime(end_t, start_t) / 3600);
 
     while (interval <= interval_limit) {
-        interval_data = find_timeslice(data, start_tm, end_tm,
+        interval_data = find_timeslice(wd, start_tm, end_tm,
                                        prev_hours_limit, next_hours_limit);
         if (interval_data != NULL)
             return interval_data;
@@ -669,41 +673,227 @@ find_shortest_timeslice(xml_weather *data,
 }
 
 
-xml_time *
-make_current_conditions(xml_weather *data,
-                        time_t now_t)
+/*
+ * Compare two xml_time structs using their start and end times,
+ * returning the result as a qsort()-style comparison function (less
+ * than zero for first arg is less than second arg, zero for equal,
+ * greater zero if first arg is greater than second arg).
+ */
+gint
+xml_time_compare(gpointer a,
+                 gpointer b)
 {
-    xml_time *interval_data;
-    struct tm now_tm, start_tm, end_tm;
-    time_t end_t;
+    xml_time *ts1 = (xml_time *) a;
+    xml_time *ts2 = (xml_time *) b;
+    gdouble diff;
 
-    /* now search for the nearest and shortest interval data
-       available, using a maximum interval of 6 hours */
-    now_tm = *localtime(&now_t);
-    end_tm = start_tm = now_tm;
+    if (G_UNLIKELY(a == NULL && b == NULL))
+        return 0;
 
-    /* minimum interval is 1 hour */
-    end_t = time_calc_hour(end_tm, 1);
-    end_tm = *localtime(&end_t);
+    if (G_UNLIKELY(a == NULL))
+        return -1;
+
+    if (G_UNLIKELY(b == NULL))
+        return 1;
+
+    diff = difftime(ts2->start, ts1->start);
+    if (diff > 0)
+        return -1;
+    if (diff < 0)
+        return 1;
+
+    /* start time is equal, now it's easy to check end time ;-) */
+    return (gint) difftime(ts2->end, ts1->end);
+}
+
+
+static void
+point_data_results_free(point_data_results *pdr)
+{
+    g_assert(pdr != NULL);
+    if (G_UNLIKELY(pdr == NULL))
+        return;
+
+    g_assert(pdr->before != NULL);
+    g_array_free(pdr->before, FALSE);
+    g_assert(pdr->after != NULL);
+    g_array_free(pdr->after, FALSE);
+    g_slice_free(point_data_results, pdr);
+    return;
+}
+
+/*
+ * Given an array of point data, find two points for which
+ * corresponding interval data can be found so that the interval is as
+ * small as possible, returning NULL if such interval data doesn't
+ * exist.
+ */
+static xml_time *
+find_smallest_interval(xml_weather *wd,
+                       const point_data_results *pdr)
+{
+    GArray *before = pdr->before, *after = pdr->after;
+    xml_time *ts_before, *ts_after, *found;
+    gint i, j;
+
+    for (i = before->len - 1; i >= 0; i--) {
+        ts_before = g_array_index(before, xml_time *, i);
+        for (j = 0; j < after->len; j++) {
+            ts_after = g_array_index(after, xml_time *, j);
+            found = get_timeslice(wd, ts_before->start, ts_after->end, NULL);
+            if (found)
+                return found;
+        }
+    }
+    return NULL;
+}
+
+
+/*
+ * Given an array of point data, find two points for which
+ * corresponding interval data can be found so that the interval is as
+ * big as possible, returning NULL if such interval data doesn't
+ * exist.
+ */
+static xml_time *
+find_largest_interval(xml_weather *wd,
+                      const point_data_results *pdr)
+{
+    GArray *before = pdr->before, *after = pdr->after;
+    xml_time *ts_before = NULL, *ts_after = NULL, *found = NULL;
+    gint i, j;
+
+    for (i = before->len - 1; i >= 0; i--) {
+        ts_before = g_array_index(before, xml_time *, i);
+        g_assert(ts_before != NULL);
+        for (j = after->len - 1; j >= 0; j--) {
+            ts_after = g_array_index(after, xml_time *, j);
+            found = get_timeslice(wd, ts_before->start, ts_after->end, NULL);
+            if (found) {
+                weather_debug("Found biggest interval:");
+                weather_dump(weather_dump_timeslice, found);
+                return found;
+            }
+        }
+    }
+    weather_debug("Could not find interval.");
+    return NULL;
+}
+
+
+/* find point data within certain limits around a point in time */
+static point_data_results *
+find_point_data(const xml_weather *wd,
+                const time_t point_t,
+                const gdouble min_diff,
+                const gdouble max_diff)
+{
+    point_data_results *found = NULL;
+    xml_time *timeslice;
+    guint i;
+    gdouble diff;
+
+    found = g_slice_new0(point_data_results);
+    found->before = g_array_new(FALSE, TRUE, sizeof(xml_time *));
+    found->after = g_array_new(FALSE, TRUE, sizeof(xml_time *));
+
+    weather_debug("Checking %d timeslices for point data.",
+                  wd->timeslices->len);
+    for (i = 0; i < wd->timeslices->len; i++) {
+        timeslice = g_array_index(wd->timeslices, xml_time *, i);
+        /* look only for point data, not intervals */
+        if (G_UNLIKELY(timeslice == NULL) || timeslice_is_interval(timeslice))
+            continue;
+
+        /* add point data if within limits */
+        diff = difftime(timeslice->end, point_t);
+        if (diff < 0) {   /* before point_t */
+            diff *= -1;
+            if (diff < min_diff || diff > max_diff)
+                continue;
+            g_array_append_val(found->before, timeslice);
+            weather_dump(weather_dump_timeslice, timeslice);
+        } else {          /* after point_t */
+            if (diff < min_diff || diff > max_diff)
+                continue;
+            g_array_append_val(found->after, timeslice);
+            weather_dump(weather_dump_timeslice, timeslice);
+        }
+    }
+    g_array_sort(found->before, (GCompareFunc) xml_time_compare);
+    g_array_sort(found->after, (GCompareFunc) xml_time_compare);
+    found->point = point_t;
+    weather_debug("Found %d timeslices with point data, "
+                  "%d before and %d after point_t.",
+                  (found->before->len + found->after->len),
+                  found->before->len, found->after->len);
+    return found;
+}
+
+
+xml_time *
+make_current_conditions(xml_weather *wd,
+                        time_t now_t)
+{
+    point_data_results *found = NULL;
+    xml_time *interval = NULL;
+    struct tm point_tm = *localtime(&now_t);
+    time_t point_t = now_t;
+    gint i = 0;
+
+    g_assert(wd != NULL);
+    if (G_UNLIKELY(wd == NULL))
+        return NULL;
 
-    /* We want to keep the hour deviation as small as possible,
-       so let's try an interval with ±1 hour deviation first */
-    interval_data = find_shortest_timeslice(data, start_tm, end_tm, -1, 1, 6);
-    if (interval_data == NULL) {
-        /* in case we were unsuccessful we might need to enlarge the
-           search radius */
-        interval_data = find_shortest_timeslice(data, start_tm, end_tm,
-                                                -3, 3, 6);
-        if (interval_data == NULL)
-            /* and maybe it's necessary to try even harder... */
-            interval_data = find_shortest_timeslice(data, start_tm, end_tm,
-                                                    -3, 6, 6);
+    /* there may not be a timeslice available for the current
+       interval, so look max three hours ahead */
+    while (i < 3 && interval == NULL) {
+        point_t = time_calc_hour(point_tm, i);
+        found = find_point_data(wd, point_t, 1, 4 * 3600);
+        interval = find_smallest_interval(wd, found);
+        point_data_results_free(found);
+        point_tm = *localtime(&point_t);
+        i++;
     }
-    if (interval_data == NULL)
+    weather_dump(weather_dump_timeslice, interval);
+    if (interval == NULL)
         return NULL;
 
-    /* create combined timeslice with interpolated point and interval data */
-    return make_combined_timeslice(data, interval_data, &now_t);
+    return make_combined_timeslice(wd, interval, &now_t);
+}
+
+
+static time_t
+get_daytime(int day,
+            daytime dt)
+{
+    struct tm point_tm;
+    time_t point_t;
+
+    /* initialize times to the current day */
+    time(&point_t);
+    point_tm = *localtime(&point_t);
+
+    /* calculate daytime for the requested day */
+    point_tm.tm_mday += day;
+    point_tm.tm_min = point_tm.tm_sec = 0;
+    point_tm.tm_isdst = -1;
+    switch (dt) {
+    case MORNING:
+        point_tm.tm_hour = 9;
+        break;
+    case AFTERNOON:
+        point_tm.tm_hour = 15;
+        break;
+    case EVENING:
+        point_tm.tm_hour = 21;
+        break;
+    case NIGHT:
+        point_tm.tm_hour = 27;
+        break;
+    }
+    point_t = mktime(&point_tm);
+    return point_t;
 }
 
 
@@ -711,40 +901,25 @@ make_current_conditions(xml_weather *data,
  * Get forecast data for a given daytime for the day (today + day).
  */
 xml_time *
-make_forecast_data(xml_weather *data,
-                   const int day,
-                   const daytime dt)
+make_forecast_data(xml_weather *wd,
+                   int day,
+                   daytime dt)
 {
-    xml_time *interval_data = NULL;
-    struct tm start_tm, end_tm;
-    time_t now_t, start_t, end_t;
-    gint interval;
-
-    /* initialize times to the current day */
-    time(&now_t);
-    start_tm = *localtime(&now_t);
-    end_tm = *localtime(&now_t);
+    point_data_results *found = NULL;
+    xml_time *interval = NULL;
+    time_t point_t;
 
-    /* calculate daytime interval start and end times for the requested day */
-    start_tm.tm_mday += day;
-    end_tm.tm_mday += day;
-    get_daytime_interval(&start_tm, &end_tm, dt);
-    start_t = mktime(&start_tm);
-    end_t = mktime(&end_tm);
+    g_assert(wd != NULL);
+    if (G_UNLIKELY(wd == NULL))
+        return NULL;
 
-    /* next find biggest possible (limited by daytime) interval data
-       using a maximum deviation of ±3 hours */
-    while ((interval = (gint) (difftime(end_t, start_t) / 3600)) > 0) {
-        interval_data = find_timeslice(data, start_tm, end_tm, -3, 3);
-        if (interval_data != NULL)
-            break;
-        end_t = time_calc_hour(end_tm, -1);
-        end_tm = *localtime(&end_t);
-    }
-    if (interval_data == NULL)
+    point_t = get_daytime(day, dt);
+    found = find_point_data(wd, point_t, 1, 5 * 3600);
+    interval = find_largest_interval(wd, found);
+    point_data_results_free(found);
+    weather_dump(weather_dump_timeslice, interval);
+    if (interval == NULL)
         return NULL;
 
-    /* create combined timeslice with non-interpolated point
-       and interval data */
-    return make_combined_timeslice(data, interval_data, NULL);
+    return make_combined_timeslice(wd, interval, &point_t);
 }
diff --git a/panel-plugin/weather-data.h b/panel-plugin/weather-data.h
index 3f96793..12fbb6e 100644
--- a/panel-plugin/weather-data.h
+++ b/panel-plugin/weather-data.h
@@ -89,6 +89,8 @@ typedef struct {
 gdouble string_to_double(const gchar *str,
                          gdouble backup);
 
+gboolean timeslice_is_interval(xml_time *timeslice);
+
 gchar *get_data(const xml_time *timeslice,
                 const units_config *units,
                 data_types type,
@@ -113,12 +115,18 @@ time_t time_calc_hour(struct tm time_tm,
 time_t time_calc_day(struct tm time_tm,
                      gint days);
 
-xml_time *get_current_conditions(const xml_weather *data);
+gint xml_time_compare(gpointer a,
+                      gpointer b);
+
+void merge_timeslice(xml_weather *wd,
+                     const xml_time *timeslice);
+
+xml_time *get_current_conditions(const xml_weather *wd);
 
-xml_time *make_current_conditions(xml_weather *data,
+xml_time *make_current_conditions(xml_weather *wd,
                                   time_t now_t);
 
-xml_time *make_forecast_data(xml_weather *data,
+xml_time *make_forecast_data(xml_weather *wd,
                              int day,
                              daytime dt);
 
diff --git a/panel-plugin/weather-debug.c b/panel-plugin/weather-debug.c
index f3fc823..e879f8b 100644
--- a/panel-plugin/weather-debug.c
+++ b/panel-plugin/weather-debug.c
@@ -340,31 +340,59 @@ weather_dump_units_config(const units_config *units)
 
 
 gchar *
-weather_dump_weatherdata(const xml_weather *weatherdata)
+weather_dump_timeslice(const xml_time *timeslice)
 {
     GString *out;
     gchar *start, *end, *loc, *result;
     gboolean is_interval;
+
+    if (G_UNLIKELY(timeslice == NULL))
+        return g_strdup("No timeslice data.");
+
+    out = g_string_sized_new(512);
+    start = weather_debug_strftime_t(timeslice->start);
+    end = weather_debug_strftime_t(timeslice->end);
+    is_interval = (gboolean) strcmp(start, end);
+    loc = weather_dump_location((timeslice) ? timeslice->location : NULL,
+                                is_interval);
+    g_string_append_printf(out, "[%s %s %s] %s\n", start,
+                           is_interval ? "-" : "=", end, loc);
+    g_free(start);
+    g_free(end);
+    g_free(loc);
+
+    /* Free GString only and return its character data */
+    result = out->str;
+    g_string_free(out, FALSE);
+    return result;
+}
+
+
+gchar *
+weather_dump_weatherdata(const xml_weather *wd)
+{
+    GString *out;
+    xml_time *timeslice;
+    gchar *result, *tmp;
     guint i;
 
+    if (G_UNLIKELY(wd == NULL))
+        return g_strdup("No weather data.");
+
+    if (G_UNLIKELY(wd->timeslices == NULL))
+        return g_strdup("Weather data: No timeslices available.");
+
     out = g_string_sized_new(20480);
     g_string_assign(out, "Timeslices (local time): ");
-    g_string_append_printf(out, "%d timeslices available (%d max, %d free).\n",
-                           weatherdata->num_timeslices, MAX_TIMESLICE,
-                           MAX_TIMESLICE - weatherdata->num_timeslices);
-    for (i = 0; i < weatherdata->num_timeslices; i++) {
-        start = weather_debug_strftime_t(weatherdata->timeslice[i]->start);
-        end = weather_debug_strftime_t(weatherdata->timeslice[i]->end);
-        is_interval = (gboolean) strcmp(start, end);
-        loc = weather_dump_location(weatherdata->timeslice[i]->location,
-                                    is_interval);
-        g_string_append_printf(out, "  #%3d: [%s %s %s] %s\n",
-                               i + 1, start, is_interval ? "-" : "=",
-                               end, loc);
-        g_free(start);
-        g_free(end);
-        g_free(loc);
+    g_string_append_printf(out, "%d timeslices available.\n",
+                           wd->timeslices->len);
+    for (i = 0; i < wd->timeslices->len; i++) {
+        timeslice = g_array_index(wd->timeslices, xml_time *, i);
+        tmp = weather_dump_timeslice(timeslice);
+        g_string_append_printf(out, "  #%3d: %s", i + 1, tmp);
+        g_free(tmp);
     }
+
     /* Remove trailing newline */
     if (out->str[out->len - 1] == '\n')
         out->str[--out->len] = '\0';
@@ -377,7 +405,7 @@ weather_dump_weatherdata(const xml_weather *weatherdata)
 
 
 gchar *
-weather_dump_plugindata(const xfceweather_data *data)
+weather_dump_plugindata(const plugin_data *data)
 {
     GString *out;
     GtkOrientation orientation, panel_orientation;
diff --git a/panel-plugin/weather-debug.h b/panel-plugin/weather-debug.h
index 2e49ea4..3034b76 100644
--- a/panel-plugin/weather-debug.h
+++ b/panel-plugin/weather-debug.h
@@ -72,9 +72,11 @@ gchar *weather_dump_astrodata(const xml_astro *astrodata);
 
 gchar *weather_dump_units_config(const units_config *units);
 
-gchar *weather_dump_weatherdata(const xml_weather *weatherdata);
+gchar *weather_dump_timeslice(const xml_time *timeslice);
 
-gchar *weather_dump_plugindata(const xfceweather_data *data);
+gchar *weather_dump_weatherdata(const xml_weather *wd);
+
+gchar *weather_dump_plugindata(const plugin_data *data);
 
 G_END_DECLS
 
diff --git a/panel-plugin/weather-icon.c b/panel-plugin/weather-icon.c
index bf3ff61..6422e12 100644
--- a/panel-plugin/weather-icon.c
+++ b/panel-plugin/weather-icon.c
@@ -227,7 +227,7 @@ find_themes_in_dir(const gchar *path)
     weather_debug("Looking for icon themes in %s.", path);
     dir = g_dir_open(path, 0, NULL);
     if (dir) {
-        themes = g_array_new(FALSE, TRUE, sizeof(icon_theme*));
+        themes = g_array_new(FALSE, TRUE, sizeof(icon_theme *));
 
         while (dirname = g_dir_read_name(dir)) {
             themedir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
diff --git a/panel-plugin/weather-parsers.c b/panel-plugin/weather-parsers.c
index e9c1bf9..89b09d5 100644
--- a/panel-plugin/weather-parsers.c
+++ b/panel-plugin/weather-parsers.c
@@ -28,13 +28,12 @@
 #define _XOPEN_SOURCE
 #define _XOPEN_SOURCE_EXTENDED 1
 #include "weather-parsers.h"
-#include <libxfce4panel/libxfce4panel.h>
+#include "weather-debug.h"
+
 #include <time.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include "weather-debug.h"
-
 
 #define DATA(node)                                                  \
     ((gchar *) xmlNodeListGetString(node->doc, node->children, 1))
@@ -46,6 +45,9 @@
     (xmlStrEqual(node->name, (const xmlChar *) type))
 
 
+extern gboolean debug_mode;
+
+
 /*
  * This is a portable replacement for the deprecated timegm(),
  * copied from the man page and modified to use GLIB functions.
@@ -70,36 +72,39 @@ my_timegm(struct tm *tm)
 
 
 xml_time *
-get_timeslice(xml_weather *data,
+get_timeslice(xml_weather *wd,
               const time_t start_t,
-              const time_t end_t)
+              const time_t end_t,
+              guint *index)
 {
+    xml_time *timeslice;
     guint i;
 
-    for (i = 0; i < data->num_timeslices; i++) {
-        if (data->timeslice[i]->start == start_t &&
-            data->timeslice[i]->end == end_t)
-            return data->timeslice[i];
-    }
-    if (data->num_timeslices == MAX_TIMESLICE - 1)
+    g_assert(wd != NULL);
+    if (G_UNLIKELY(wd == NULL))
         return NULL;
 
-    data->timeslice[data->num_timeslices] = g_slice_new0(xml_time);
-    data->timeslice[data->num_timeslices]->start = start_t;
-    data->timeslice[data->num_timeslices]->end = end_t;
-    data->num_timeslices++;
-
-    return data->timeslice[data->num_timeslices - 1];
+    for (i = 0; i < wd->timeslices->len; i++) {
+        timeslice = g_array_index(wd->timeslices, xml_time *, i);
+        if (timeslice &&
+            timeslice->start == start_t && timeslice->end == end_t) {
+            if (index != NULL)
+                *index = i;
+            return timeslice;
+        }
+    }
+    return NULL;
 }
 
 
-static time_t
-parse_xml_timestring(const gchar *ts,
-                     gchar *format) {
+time_t
+parse_timestring(const gchar *ts,
+                 gchar *format) {
     time_t t;
     struct tm tm;
 
     memset(&t, 0, sizeof(time_t));
+    g_assert(ts != NULL);
     if (G_UNLIKELY(ts == NULL))
         return t;
 
@@ -202,9 +207,45 @@ parse_location(xmlNode *cur_node,
 }
 
 
+xml_weather *
+make_weather_data(void)
+{
+    xml_weather *wd;
+
+    wd = g_slice_new0(xml_weather);
+    if (G_UNLIKELY(wd == NULL))
+        return NULL;
+    wd->timeslices = g_array_sized_new(FALSE, TRUE,
+                                       sizeof(xml_time *), 200);
+    if (G_UNLIKELY(wd->timeslices == NULL)) {
+        g_slice_free(xml_weather, wd);
+        return NULL;
+    }
+    return wd;
+}
+
+
+xml_time *
+make_timeslice(void)
+{
+    xml_time *timeslice;
+
+    timeslice = g_slice_new0(xml_time);
+    if (G_UNLIKELY(timeslice == NULL))
+        return NULL;
+
+    timeslice->location = g_slice_new0(xml_location);
+    if (G_UNLIKELY(timeslice->location == NULL)) {
+        g_slice_free(xml_time, timeslice);
+        return NULL;
+    }
+    return timeslice;
+}
+
+
 static void
 parse_time(xmlNode *cur_node,
-           xml_weather *data)
+           xml_weather *wd)
 {
     gchar *datatype, *from, *to;
     time_t start_t, end_t;
@@ -219,47 +260,50 @@ parse_time(xmlNode *cur_node,
     xmlFree(datatype);
 
     from = PROP(cur_node, "from");
-    start_t = parse_xml_timestring(from, NULL);
+    start_t = parse_timestring(from, NULL);
     xmlFree(from);
 
     to = PROP(cur_node, "to");
-    end_t = parse_xml_timestring(to, NULL);
+    end_t = parse_timestring(to, NULL);
     xmlFree(to);
 
     if (G_UNLIKELY(!start_t || !end_t))
         return;
 
-    timeslice = get_timeslice(data, start_t, end_t);
-
-    if (G_UNLIKELY(!timeslice)) {
-        g_warning("No timeslice found or created. "
-                  "Perhaps maximum of %d slices reached?", MAX_TIMESLICE);
-        return;
+    /* look for existing timeslice or add a new one */
+    timeslice = get_timeslice(wd, start_t, end_t, NULL);
+    if (! timeslice) {
+        timeslice = make_timeslice();
+        if (G_UNLIKELY(!timeslice))
+            return;
+        timeslice->start = start_t;
+        timeslice->end = end_t;
+        g_array_append_val(wd->timeslices, timeslice);
     }
+
     for (child_node = cur_node->children; child_node;
          child_node = child_node->next)
-        if (G_LIKELY(NODE_IS_TYPE(child_node, "location"))) {
-            if (timeslice->location == NULL)
-                timeslice->location = g_slice_new0(xml_location);
+        if (G_LIKELY(NODE_IS_TYPE(child_node, "location")))
             parse_location(child_node, timeslice->location);
-        }
 }
 
 
-xml_weather *
-parse_weather(xmlNode *cur_node)
+/*
+ * Parse XML weather data and merge it with current data.
+ */
+gboolean
+parse_weather(xmlNode *cur_node,
+              xml_weather *wd)
 {
-    xml_weather *ret;
     xmlNode *child_node;
 
-    if (G_UNLIKELY(!NODE_IS_TYPE(cur_node, "weatherdata"))) {
-        return NULL;
-    }
+    g_assert(wd != NULL);
+    if (G_UNLIKELY(wd == NULL))
+        return FALSE;
 
-    if ((ret = g_slice_new0(xml_weather)) == NULL)
-        return NULL;
+    if (G_UNLIKELY(cur_node == NULL || !NODE_IS_TYPE(cur_node, "weatherdata")))
+        return FALSE;
 
-    ret->num_timeslices = 0;
     for (cur_node = cur_node->children; cur_node; cur_node = cur_node->next) {
         if (cur_node->type != XML_ELEMENT_NODE)
             continue;
@@ -274,10 +318,10 @@ parse_weather(xmlNode *cur_node)
             for (child_node = cur_node->children; child_node;
                  child_node = child_node->next)
                 if (NODE_IS_TYPE(child_node, "time"))
-                    parse_time(child_node, ret);
+                    parse_time(child_node, wd);
         }
     }
-    return ret;
+    return TRUE;
 }
 
 
@@ -311,11 +355,11 @@ parse_astro_location(xmlNode *cur_node,
             xmlFree(never_sets);
 
             sunrise = PROP(child_node, "rise");
-            astro->sunrise = parse_xml_timestring(sunrise, NULL);
+            astro->sunrise = parse_timestring(sunrise, NULL);
             xmlFree(sunrise);
 
             sunset = PROP(child_node, "set");
-            astro->sunset = parse_xml_timestring(sunset, NULL);
+            astro->sunset = parse_timestring(sunset, NULL);
             xmlFree(sunset);
         }
 
@@ -339,11 +383,11 @@ parse_astro_location(xmlNode *cur_node,
             xmlFree(never_sets);
 
             moonrise = PROP(child_node, "rise");
-            astro->moonrise = parse_xml_timestring(moonrise, NULL);
+            astro->moonrise = parse_timestring(moonrise, NULL);
             xmlFree(moonrise);
 
             moonset = PROP(child_node, "set");
-            astro->moonset = parse_xml_timestring(moonset, NULL);
+            astro->moonset = parse_timestring(moonset, NULL);
             xmlFree(moonset);
 
             astro->moon_phase = PROP(child_node, "phase");
@@ -362,7 +406,8 @@ parse_astro(xmlNode *cur_node)
     xmlNode *child_node, *time_node = NULL;
     xml_astro *astro;
 
-    if (cur_node == NULL || !NODE_IS_TYPE(cur_node, "astrodata"))
+    g_assert(cur_node != NULL);
+    if (G_UNLIKELY(cur_node == NULL || !NODE_IS_TYPE(cur_node, "astrodata")))
         return NULL;
 
     astro = g_slice_new0(xml_astro);
@@ -423,10 +468,7 @@ parse_place(xmlNode *cur_node)
     xml_place *place;
 
     g_assert(cur_node != NULL);
-    if (G_UNLIKELY(cur_node == NULL))
-        return NULL;
-
-    if (!NODE_IS_TYPE(cur_node, "place"))
+    if (G_UNLIKELY(cur_node == NULL || !NODE_IS_TYPE(cur_node, "place")))
         return NULL;
 
     place = g_slice_new0(xml_place);
@@ -445,10 +487,7 @@ parse_altitude(xmlNode *cur_node)
     xml_altitude *alt;
 
     g_assert(cur_node != NULL);
-    if (G_UNLIKELY(cur_node == NULL))
-        return NULL;
-
-    if (!NODE_IS_TYPE(cur_node, "geonames"))
+    if (G_UNLIKELY(cur_node == NULL) || !NODE_IS_TYPE(cur_node, "geonames"))
         return NULL;
 
     alt = g_slice_new0(xml_altitude);
@@ -468,10 +507,7 @@ parse_timezone(xmlNode *cur_node)
     xml_timezone *tz;
 
     g_assert(cur_node != NULL);
-    if (G_UNLIKELY(cur_node == NULL))
-        return NULL;
-
-    if (!NODE_IS_TYPE(cur_node, "timezone"))
+    if (G_UNLIKELY(cur_node == NULL) || !NODE_IS_TYPE(cur_node, "timezone"))
         return NULL;
 
     tz = g_slice_new0(xml_timezone);
@@ -520,6 +556,10 @@ parse_xml_document(SoupMessage *msg,
     xmlNode *root_node;
     gpointer user_data = NULL;
 
+    g_assert(msg != NULL);
+    if (G_UNLIKELY(msg == NULL))
+        return NULL;
+
     doc = get_xml_document(msg);
     if (G_LIKELY(doc)) {
         root_node = xmlDocGetRootElement(doc);
@@ -562,6 +602,66 @@ xml_location_free(xml_location *loc)
 }
 
 
+/*
+ * Deep copy xml_time struct.
+ */
+xml_time *
+xml_time_copy(const xml_time *src)
+{
+    xml_time *dst;
+    xml_location *loc;
+    gint i;
+
+    if (src == NULL)
+        return NULL;
+
+    dst = g_slice_new0(xml_time);
+    if (dst == NULL)
+        return NULL;
+
+    loc = g_slice_new0(xml_location);
+    if (loc == NULL)
+        return dst;
+
+    dst->start = src->start;
+    dst->end = src->end;
+
+    loc->altitude = g_strdup(src->location->altitude);
+    loc->latitude = g_strdup(src->location->latitude);
+    loc->longitude = g_strdup(src->location->longitude);
+
+    loc->temperature_value = g_strdup(src->location->temperature_value);
+    loc->temperature_unit = g_strdup(src->location->temperature_unit);
+
+    loc->wind_dir_deg = g_strdup(src->location->wind_dir_deg);
+    loc->wind_dir_name = g_strdup(src->location->wind_dir_name);
+    loc->wind_speed_mps = g_strdup(src->location->wind_speed_mps);
+    loc->wind_speed_beaufort = g_strdup(src->location->wind_speed_beaufort);
+
+    loc->humidity_value = g_strdup(src->location->humidity_value);
+    loc->humidity_unit = g_strdup(src->location->humidity_unit);
+
+    loc->pressure_value = g_strdup(src->location->pressure_value);
+    loc->pressure_unit = g_strdup(src->location->pressure_unit);
+
+    for (i = 0; i < CLOUDS_PERC_NUM; i++)
+        loc->clouds_percent[i] = g_strdup(src->location->clouds_percent[i]);
+
+    loc->fog_percent = g_strdup(src->location->fog_percent);
+
+    loc->precipitation_value =
+        g_strdup(src->location->precipitation_value);
+    loc->precipitation_unit = g_strdup(src->location->precipitation_unit);
+
+    loc->symbol_id = src->location->symbol_id;
+    loc->symbol = g_strdup(src->location->symbol);
+
+    dst->location = loc;
+
+    return dst;
+}
+
+
 void
 xml_time_free(xml_time *timeslice)
 {
@@ -574,21 +674,56 @@ xml_time_free(xml_time *timeslice)
 
 
 void
-xml_weather_free(xml_weather *data)
+xml_weather_free(xml_weather *wd)
 {
+    xml_time *timeslice;
     guint i;
 
-    g_assert(data != NULL);
-    if (G_UNLIKELY(data == NULL))
+    g_assert(wd != NULL);
+    if (G_UNLIKELY(wd == NULL))
         return;
-    weather_debug("Freeing %u timeslices.", data->num_timeslices);
-    for (i = 0; i < data->num_timeslices; i++)
-        xml_time_free(data->timeslice[i]);
-    if (G_LIKELY(data->current_conditions)) {
+    if (G_LIKELY(wd->timeslices)) {
+        weather_debug("Freeing %u timeslices.", wd->timeslices->len);
+        for (i = 0; i < wd->timeslices->len; i++) {
+            timeslice = g_array_index(wd->timeslices, xml_time *, i);
+            xml_time_free(timeslice);
+        }
+        g_array_free(wd->timeslices, FALSE);
+    }
+    if (G_LIKELY(wd->current_conditions)) {
         weather_debug("Freeing current conditions.");
-        xml_time_free(data->current_conditions);
+        xml_time_free(wd->current_conditions);
+    }
+    g_slice_free(xml_weather, wd);
+}
+
+
+void
+xml_weather_clean(xml_weather *wd)
+{
+    xml_time *timeslice;
+    time_t now_t = time(NULL);
+    guint i;
+
+    if (G_UNLIKELY(wd == NULL || wd->timeslices == NULL))
+        return;
+    for (i = 0; i < wd->timeslices->len; i++) {
+        timeslice = g_array_index(wd->timeslices, xml_time *, i);
+        if (G_UNLIKELY(timeslice == NULL))
+            continue;
+        if (difftime(now_t, timeslice->end) > DATA_EXPIRY_TIME) {
+            if (debug_mode) {
+                gchar *start, *end;
+                start = weather_debug_strftime_t(timeslice->start);
+                end = weather_debug_strftime_t(timeslice->end);
+                weather_debug("Removing expired timeslice [%s - %s].");
+                g_free(start);
+                g_free(end);
+            }
+            xml_time_free(timeslice);
+            g_array_remove_index(wd->timeslices, i--);
+        }
     }
-    g_slice_free(xml_weather, data);
 }
 
 
diff --git a/panel-plugin/weather-parsers.h b/panel-plugin/weather-parsers.h
index 86166ea..53b23d8 100644
--- a/panel-plugin/weather-parsers.h
+++ b/panel-plugin/weather-parsers.h
@@ -24,9 +24,9 @@
 #include <libxml/parser.h>
 #include <libsoup/soup.h>
 
-G_BEGIN_DECLS
+#define DATA_EXPIRY_TIME (24 * 3600)
 
-#define MAX_TIMESLICE 500
+G_BEGIN_DECLS
 
 enum {
     CLOUDS_PERC_LOW = 0,
@@ -75,8 +75,7 @@ typedef struct {
 } xml_time;
 
 typedef struct {
-    xml_time *timeslice[MAX_TIMESLICE];
-    guint num_timeslices;
+    GArray *timeslices;
     xml_time *current_conditions;
 } xml_weather;
 
@@ -122,7 +121,15 @@ typedef struct {
 } xml_timezone;
 
 
-xml_weather *parse_weather(xmlNode *cur_node);
+xml_weather *make_weather_data(void);
+
+xml_time *make_timeslice(void);
+
+time_t parse_timestring(const gchar *ts,
+                        gchar *format);
+
+gboolean parse_weather(xmlNode *cur_node,
+                       xml_weather *wd);
 
 xml_astro *parse_astro(xmlNode *cur_node);
 
@@ -134,18 +141,23 @@ xml_altitude *parse_altitude(xmlNode *cur_node);
 
 xml_timezone *parse_timezone(xmlNode *cur_node);
 
-xml_time *get_timeslice(xml_weather *data,
+xml_time *get_timeslice(xml_weather *wd,
                         const time_t start_t,
-                        const time_t end_t);
+                        const time_t end_t,
+                        guint *index);
 
 xmlDoc *get_xml_document(SoupMessage *msg);
 
 gpointer parse_xml_document(SoupMessage *msg,
                             XmlParseFunc parse_func);
 
+xml_time *xml_time_copy(const xml_time *src);
+
 void xml_time_free(xml_time *timeslice);
 
-void xml_weather_free(xml_weather *data);
+void xml_weather_free(xml_weather *wd);
+
+void xml_weather_clean(xml_weather *wd);
 
 void xml_astro_free(xml_astro *astro);
 
diff --git a/panel-plugin/weather-summary.c b/panel-plugin/weather-summary.c
index 785c2ac..637c537 100644
--- a/panel-plugin/weather-summary.c
+++ b/panel-plugin/weather-summary.c
@@ -213,15 +213,13 @@ view_size_allocate_cb(GtkWidget *widget,
 static gchar *
 get_logo_path(void)
 {
-    gchar *dir = g_strconcat(g_get_user_cache_dir(), G_DIR_SEPARATOR_S,
-                             "xfce4", G_DIR_SEPARATOR_S, "weather-plugin",
-                             NULL);
-
-    g_mkdir_with_parents(dir, 0755);
-    g_free(dir);
-    return g_strconcat(g_get_user_cache_dir(), G_DIR_SEPARATOR_S,
-                       "xfce4", G_DIR_SEPARATOR_S, "weather-plugin",
-                       G_DIR_SEPARATOR_S, "weather_logo.gif", NULL);
+    gchar *cache_dir, *logo_path;
+
+    cache_dir = get_cache_directory();
+    logo_path = g_strconcat(cache_dir, G_DIR_SEPARATOR_S,
+                            "weather_logo.gif", NULL);
+    g_free(cache_dir);
+    return logo_path;
 }
 
 
@@ -253,7 +251,7 @@ logo_fetched(SoupSession *session,
 
 
 static GtkWidget *
-weather_summary_get_logo(xfceweather_data *data)
+weather_summary_get_logo(plugin_data *data)
 {
     GtkWidget *image = gtk_image_new();
     GdkPixbuf *pixbuf = NULL;
@@ -274,7 +272,7 @@ weather_summary_get_logo(xfceweather_data *data)
 
 
 static GtkWidget *
-create_summary_tab(xfceweather_data *data)
+create_summary_tab(plugin_data *data)
 {
     GtkTextBuffer *buffer;
     GtkTextIter iter;
@@ -555,7 +553,7 @@ add_forecast_header(const gchar *text,
 
 
 static GtkWidget *
-add_forecast_cell(xfceweather_data *data,
+add_forecast_cell(plugin_data *data,
                   gint day,
                   gint daytime)
 {
@@ -632,7 +630,7 @@ add_forecast_cell(xfceweather_data *data,
 
 
 static GtkWidget *
-make_forecast(xfceweather_data *data)
+make_forecast(plugin_data *data)
 {
     GtkWidget *table, *ebox, *box, *align;
     GtkWidget *forecast_box;
@@ -704,7 +702,7 @@ make_forecast(xfceweather_data *data)
 
 
 static GtkWidget *
-create_forecast_tab(xfceweather_data *data)
+create_forecast_tab(plugin_data *data)
 {
     GtkWidget *ebox, *align, *hbox, *scrolled, *table;
     GdkWindow *window;
@@ -788,7 +786,7 @@ summary_dialog_response(const GtkWidget *dlg,
 
 
 GtkWidget *
-create_summary_window (xfceweather_data *data)
+create_summary_window(plugin_data *data)
 {
     GtkWidget *window, *notebook, *vbox, *hbox, *label;
     gchar *title, *symbol;
diff --git a/panel-plugin/weather-summary.h b/panel-plugin/weather-summary.h
index 756eea3..585ba90 100644
--- a/panel-plugin/weather-summary.h
+++ b/panel-plugin/weather-summary.h
@@ -21,7 +21,7 @@
 
 G_BEGIN_DECLS
 
-GtkWidget *create_summary_window(xfceweather_data *data);
+GtkWidget *create_summary_window(plugin_data *data);
 
 void summary_details_free(summary_details *sum);
 
diff --git a/panel-plugin/weather.c b/panel-plugin/weather.c
index e04d484..bd829ee 100644
--- a/panel-plugin/weather.c
+++ b/panel-plugin/weather.c
@@ -38,10 +38,12 @@
 #include "weather-debug.h"
 
 #define XFCEWEATHER_ROOT "weather"
-#define UPDATE_INTERVAL 15
-#define DATA_MAX_AGE (3 * 3600)
-#define BORDER 8
+#define UPDATE_INTERVAL (15)
+#define DATA_MAX_AGE (20 * 60)
+#define CACHE_FILE_MAX_AGE (48 * 3600)
+#define BORDER (8)
 #define CONNECTION_TIMEOUT (10)        /* connection timeout in seconds */
+#define DATA_RETRY_WAIT (180)          /* download retry wait time in seconds */
 
 #define DATA_AND_UNIT(var, item)                                    \
     value = get_data(conditions, data->units, item, data->round);   \
@@ -52,10 +54,27 @@
                           unit);                                    \
     g_free(value);
 
+#define CACHE_APPEND(str, val)                  \
+    if (val)                                    \
+        g_string_append_printf(out, str, val);
+
+#define CACHE_FREE_VARS()                       \
+    g_free(locname);                            \
+    g_free(lat);                                \
+    g_free(lon);                                \
+    if (keyfile)                                \
+        g_key_file_free(keyfile);
+
+#define CACHE_READ_STRING(var, key)                             \
+    if (g_key_file_has_key(keyfile, group, key, NULL))          \
+        var = g_key_file_get_string(keyfile, group, key, NULL);
 
 
 gboolean debug_mode = FALSE;
 
+static void
+write_cache_file(plugin_data *data);
+
 
 void
 weather_http_queue_request(SoupSession *session,
@@ -71,7 +90,7 @@ weather_http_queue_request(SoupSession *session,
 
 
 static gchar *
-make_label(const xfceweather_data *data,
+make_label(const plugin_data *data,
            data_types type)
 {
     xml_time *conditions;
@@ -161,8 +180,23 @@ make_label(const xfceweather_data *data,
 }
 
 
+/*
+ * Return the weather plugin cache directory, creating it if
+ * necessary. The string returned does not contain a trailing slash.
+ */
+gchar *
+get_cache_directory(void)
+{
+    gchar *dir = g_strconcat(g_get_user_cache_dir(), G_DIR_SEPARATOR_S,
+                             "xfce4", G_DIR_SEPARATOR_S, "weather",
+                             NULL);
+    g_mkdir_with_parents(dir, 0755);
+    return dir;
+}
+
+
 void
-update_icon(xfceweather_data *data)
+update_icon(plugin_data *data)
 {
     GdkPixbuf *icon = NULL;
     xml_time *conditions;
@@ -190,7 +224,7 @@ update_icon(xfceweather_data *data)
 
 
 void
-scrollbox_set_visible(xfceweather_data *data)
+scrollbox_set_visible(plugin_data *data)
 {
     if (data->show_scrollbox && data->labels->len > 0)
         gtk_widget_show_all(GTK_WIDGET(data->vbox_center_scrollbox));
@@ -200,9 +234,8 @@ scrollbox_set_visible(xfceweather_data *data)
 
 
 void
-update_scrollbox(xfceweather_data *data)
+update_scrollbox(plugin_data *data)
 {
-    xml_time *conditions;
     GString *out;
     gchar *single = NULL;
     data_types type;
@@ -212,7 +245,7 @@ update_scrollbox(xfceweather_data *data)
     gtk_scrollbox_set_animate(GTK_SCROLLBOX(data->scrollbox),
                               data->scrollbox_animate);
 
-    if (data->weatherdata) {
+    if (data->weatherdata && data->weatherdata->current_conditions) {
         while (i < data->labels->len) {
             j = 0;
             out = g_string_sized_new(128);
@@ -226,7 +259,8 @@ update_scrollbox(xfceweather_data *data)
                 g_free(single);
                 j++;
             }
-            gtk_scrollbox_set_label(GTK_SCROLLBOX(data->scrollbox), -1, out->str);
+            gtk_scrollbox_set_label(GTK_SCROLLBOX(data->scrollbox),
+                                    -1, out->str);
             g_string_free(out, TRUE);
             i = i + j;
         }
@@ -247,7 +281,7 @@ update_scrollbox(xfceweather_data *data)
 
 
 static void
-update_current_conditions(xfceweather_data *data)
+update_current_conditions(plugin_data *data)
 {
     struct tm now_tm;
 
@@ -261,15 +295,19 @@ update_current_conditions(xfceweather_data *data)
         xml_time_free(data->weatherdata->current_conditions);
         data->weatherdata->current_conditions = NULL;
     }
-
-    data->last_conditions_update = time(NULL);
+    /* use exact 5 minute intervals for calculation */
+    time(&data->last_conditions_update);
     now_tm = *localtime(&data->last_conditions_update);
+    if (now_tm.tm_min % 5 < 5)
+        now_tm.tm_min -= (now_tm.tm_min % 5);
+    if (now_tm.tm_min < 0)
+        now_tm.tm_min = 0;
     now_tm.tm_sec = 0;
     data->last_conditions_update = mktime(&now_tm);
+
     data->weatherdata->current_conditions =
         make_current_conditions(data->weatherdata,
                                 data->last_conditions_update);
-
     data->night_time = is_night_time(data->astrodata);
     update_icon(data);
     update_scrollbox(data);
@@ -277,12 +315,26 @@ update_current_conditions(xfceweather_data *data)
 }
 
 
+static time_t
+calc_conn_retry_time(gint regular_interval) {
+    time_t now_t = time(NULL);
+    struct tm now_tm;
+
+    now_tm = *localtime(&now_t);
+    now_t = time_calc(now_tm, 0, 0, 0, 0, 0,
+                      0 - regular_interval + DATA_RETRY_WAIT);
+    weather_debug("Calculated time to delay next retry to %d seconds, is %d.",
+                  DATA_RETRY_WAIT, now_t);
+    return now_t;
+}
+
+
 static void
 cb_astro_update(SoupSession *session,
                 SoupMessage *msg,
                 gpointer user_data)
 {
-    xfceweather_data *data = user_data;
+    plugin_data *data = user_data;
     xml_astro *astro;
 
     if ((astro =
@@ -291,6 +343,10 @@ cb_astro_update(SoupSession *session,
             xml_astro_free(data->astrodata);
         data->astrodata = astro;
         data->last_astro_update = time(NULL);
+    } else {
+        /* download or parsing failed, set last_astro_update so that
+           downloading will be retried after DATA_RETRY_WAIT time */
+        data->last_astro_update = calc_conn_retry_time(DATA_MAX_AGE);
     }
     weather_dump(weather_dump_astrodata, data->astrodata);
 }
@@ -301,27 +357,37 @@ cb_weather_update(SoupSession *session,
                   SoupMessage *msg,
                   gpointer user_data)
 {
-    xfceweather_data *data = user_data;
-    xml_weather *weather = NULL;
-
-    if ((weather = (xml_weather *)
-         parse_xml_document(msg, (XmlParseFunc) parse_weather))) {
-        if (G_LIKELY(data->weatherdata)) {
-            weather_debug("Freeing weather data.");
-            xml_weather_free(data->weatherdata);
+    plugin_data *data = user_data;
+    xmlDoc *doc;
+    xmlNode *root_node;
+
+    weather_debug("Processing downloaded weather data.");
+    doc = get_xml_document(msg);
+    if (G_LIKELY(doc)) {
+        root_node = xmlDocGetRootElement(doc);
+        if (G_LIKELY(root_node)) {
+            if (parse_weather(root_node, data->weatherdata))
+                data->last_data_update = time(NULL);
+            else
+                data->last_data_update = calc_conn_retry_time(DATA_MAX_AGE);
         }
-        data->weatherdata = weather;
-        data->last_data_update = time(NULL);
+        xmlFreeDoc(doc);
+    } else {
+        /* download or parsing failed, set last_data_update so that
+           downloading will be retried after DATA_RETRY_WAIT time */
+        data->last_data_update = calc_conn_retry_time(DATA_MAX_AGE);
     }
+
+    xml_weather_clean(data->weatherdata);
     weather_debug("Updating current conditions.");
     update_current_conditions(data);
-
+    write_cache_file(data);
     weather_dump(weather_dump_weatherdata, data->weatherdata);
 }
 
 
 static gboolean
-need_astro_update(const xfceweather_data *data)
+need_astro_update(const plugin_data *data)
 {
     time_t now_t;
     struct tm now_tm, last_tm;
@@ -340,7 +406,7 @@ need_astro_update(const xfceweather_data *data)
 
 
 static gboolean
-need_data_update(const xfceweather_data *data)
+need_data_update(const plugin_data *data)
 {
     time_t now_t;
     gint diff;
@@ -358,7 +424,7 @@ need_data_update(const xfceweather_data *data)
 
 
 static gboolean
-need_conditions_update(const xfceweather_data *data)
+need_conditions_update(const plugin_data *data)
 {
     time_t now_t;
     struct tm now_tm;
@@ -374,7 +440,7 @@ need_conditions_update(const xfceweather_data *data)
 
 
 static gboolean
-update_weatherdata(xfceweather_data *data)
+update_weatherdata(plugin_data *data)
 {
     gchar *url;
     gboolean night_time;
@@ -463,7 +529,7 @@ labels_clear(GArray *array)
 
 static void
 xfceweather_read_config(XfcePanelPlugin *plugin,
-                        xfceweather_data *data)
+                        plugin_data *data)
 {
     XfceRc *rc;
     const gchar *value;
@@ -509,6 +575,9 @@ xfceweather_read_config(XfcePanelPlugin *plugin,
 
     data->timezone = xfce_rc_read_int_entry(rc, "timezone", 0);
 
+    data->cache_file_max_age =
+        xfce_rc_read_int_entry(rc, "cache_file_max_age", CACHE_FILE_MAX_AGE);
+
     if (data->units)
         g_slice_free(units_config, data->units);
     data->units = g_slice_new0(units_config);
@@ -585,7 +654,7 @@ xfceweather_read_config(XfcePanelPlugin *plugin,
 
 static void
 xfceweather_write_config(XfcePanelPlugin *plugin,
-                         xfceweather_data *data)
+                         plugin_data *data)
 {
     gchar label[10];
     guint i;
@@ -617,6 +686,9 @@ xfceweather_write_config(XfcePanelPlugin *plugin,
 
     xfce_rc_write_int_entry(rc, "timezone", data->timezone);
 
+    xfce_rc_write_int_entry(rc, "cache_file_max_age",
+                            data->cache_file_max_age);
+
     xfce_rc_write_int_entry(rc, "units_temperature", data->units->temperature);
     xfce_rc_write_int_entry(rc, "units_pressure", data->units->pressure);
     xfce_rc_write_int_entry(rc, "units_windspeed", data->units->windspeed);
@@ -664,22 +736,295 @@ xfceweather_write_config(XfcePanelPlugin *plugin,
 }
 
 
+/*
+ * Generate file name for the weather data cache file.
+ */
+static gchar *
+make_cache_filename(plugin_data *data)
+{
+    gchar *cache_dir, *file;
+
+    if (G_UNLIKELY(data->lat == NULL || data->lon == NULL))
+        return NULL;
+
+    cache_dir = get_cache_directory();
+    file = g_strdup_printf("%s%sweatherdata_%s_%s_%d",
+                           cache_dir, G_DIR_SEPARATOR_S,
+                           data->lat, data->lon, data->msl);
+    g_free(cache_dir);
+    return file;
+}
+
+
+/*
+ * Convert localtime to gmtime and format it to a string
+ * that can be parsed later by parse_timestring.
+ */
+static gchar *
+cache_file_strftime_t(const time_t t)
+{
+    struct tm *tm;
+    gchar *res;
+    gchar str[21];
+    size_t size;
+
+    tm = gmtime(&t);
+    size = strftime(str, 21, "%Y-%m-%dT%H:%M:%SZ", tm);
+    return (size ? g_strdup(str) : g_strdup(""));
+}
+
+
+static void
+write_cache_file(plugin_data *data)
+{
+    GString *out;
+    xml_weather *wd = data->weatherdata;
+    xml_time *timeslice;
+    xml_location *loc;
+    gchar *file, *start, *end, *point, *now;
+    time_t now_t = time(NULL);
+    guint i, j;
+
+    file = make_cache_filename(data);
+    if (G_UNLIKELY(file == NULL))
+        return;
+
+    out = g_string_sized_new(20480);
+    g_string_assign(out, "# xfce4-weather-plugin cache file\n\n[info]\n");
+    CACHE_APPEND("location_name=%s\n", data->location_name);
+    CACHE_APPEND("lat=%s\n", data->lat);
+    CACHE_APPEND("lon=%s\n", data->lon);
+    g_string_append_printf(out, "msl=%d\ntimezone=%d\ntimeslices=%d\n",
+                           data->msl, data->timezone, wd->timeslices->len);
+    now = cache_file_strftime_t(now_t);
+    CACHE_APPEND("cache_date=%s\n\n", now);
+    g_free(now);
+
+    for (i = 0; i < wd->timeslices->len; i++) {
+        timeslice = g_array_index(wd->timeslices, xml_time *, i);
+        if (G_UNLIKELY(timeslice == NULL || timeslice->location == NULL))
+            continue;
+        loc = timeslice->location;
+        start = cache_file_strftime_t(timeslice->start);
+        end = cache_file_strftime_t(timeslice->end);
+        point = cache_file_strftime_t(timeslice->point);
+        g_string_append_printf(out, "[timeslice%d]\n", i);
+        CACHE_APPEND("start=%s\n", start);
+        CACHE_APPEND("end=%s\n", end);
+        CACHE_APPEND("point=%s\n", point);
+        CACHE_APPEND("altitude=%s\n", loc->altitude);
+        CACHE_APPEND("latitude=%s\n", loc->latitude);
+        CACHE_APPEND("longitude=%s\n", loc->longitude);
+        CACHE_APPEND("temperature_value=%s\n", loc->temperature_value);
+        CACHE_APPEND("temperature_unit=%s\n", loc->temperature_unit);
+        CACHE_APPEND("wind_dir_deg=%s\n", loc->wind_dir_deg);
+        CACHE_APPEND("wind_dir_name=%s\n", loc->wind_dir_name);
+        CACHE_APPEND("wind_speed_mps=%s\n", loc->wind_speed_mps);
+        CACHE_APPEND("wind_speed_beaufort=%s\n", loc->wind_speed_beaufort);
+        CACHE_APPEND("humidity_value=%s\n", loc->humidity_value);
+        CACHE_APPEND("humidity_unit=%s\n", loc->humidity_unit);
+        CACHE_APPEND("pressure_value=%s\n", loc->pressure_value);
+        CACHE_APPEND("pressure_unit=%s\n", loc->pressure_unit);
+        g_free(start);
+        g_free(end);
+        g_free(point);
+        for (j = 0; j < CLOUDS_PERC_NUM; j++)
+            g_string_append_printf(out, "clouds_percent[%d]=%s\n", j,
+                                   loc->clouds_percent[j]);
+        CACHE_APPEND("fog_percent=%s\n", loc->fog_percent);
+        CACHE_APPEND("precipitation_value=%s\n", loc->precipitation_value);
+        CACHE_APPEND("precipitation_unit=%s\n", loc->precipitation_unit);
+        if (loc->symbol)
+            g_string_append_printf(out, "symbol_id=%d\nsymbol=%s\n",
+                                   loc->symbol_id, loc->symbol);
+        g_string_append(out, "\n");
+    }
+
+    if (!g_file_set_contents(file, out->str, -1, NULL))
+        g_warning("Error writing cache file %s!", file);
+    else
+        weather_debug("Cache file %s has been written.", file);
+
+    g_string_free(out, TRUE);
+    g_free(file);
+}
+
+
+static void
+read_cache_file(plugin_data *data)
+{
+    GKeyFile *keyfile;
+    GError **err;
+    xml_weather *wd;
+    xml_time *timeslice = NULL;
+    xml_location *loc = NULL;
+    time_t now_t = time(NULL), cache_date_t;
+    gchar *file, *locname = NULL, *lat = NULL, *lon = NULL, *group = NULL;
+    gchar *timestring;
+    gint msl, timezone, num_timeslices, i, j;
+
+    g_assert(data != NULL);
+    if (G_UNLIKELY(data == NULL))
+        return;
+    wd = data->weatherdata;
+
+    if (G_UNLIKELY(data->lat == NULL || data->lon == NULL))
+        return;
+
+    file = make_cache_filename(data);
+    if (G_UNLIKELY(file == NULL))
+        return;
+
+    keyfile = g_key_file_new();
+    if (!g_key_file_load_from_file(keyfile, file, G_KEY_FILE_NONE, NULL)) {
+        weather_debug("Could not read cache file %s.", file);
+        g_free(file);
+        return;
+    }
+    weather_debug("Reading cache file %s.", file);
+    g_free(file);
+
+    group = "info";
+    if (!g_key_file_has_group(keyfile, group)) {
+        CACHE_FREE_VARS();
+        return;
+    }
+
+    /* check all needed values are present and match the current parameters */
+    locname = g_key_file_get_string(keyfile, group, "location_name", NULL);
+    lat = g_key_file_get_string(keyfile, group, "lat", NULL);
+    lon = g_key_file_get_string(keyfile, group, "lon", NULL);
+    if (locname == NULL || lat == NULL || lon == NULL) {
+        CACHE_FREE_VARS();
+        weather_debug("Required values are missing in the cache file, "
+                      "reading cache file aborted.");
+        return;
+    }
+    msl = g_key_file_get_integer(keyfile, group, "msl", err);
+    if (!err)
+        timezone = g_key_file_get_integer(keyfile, group, "timezone", err);
+    if (!err)
+        num_timeslices = g_key_file_get_integer(keyfile, group,
+                                                "timeslices", err);
+    if (err || strcmp(lat, data->lat) || strcmp(lon, data->lon) ||
+        msl != data->msl || timezone != data->timezone || num_timeslices < 1) {
+        CACHE_FREE_VARS();
+        weather_debug("The required values are not present in the cache file "
+                      "or do not match the current plugin data. Reading "
+                      "cache file aborted.");
+        return;
+    }
+    /* read cache creation date and check if cache file is not too old */
+    CACHE_READ_STRING(timestring, "cache_date");
+    cache_date_t = parse_timestring(timestring, NULL);
+    g_free(timestring);
+    if (difftime(now_t, cache_date_t) > data->cache_file_max_age) {
+        weather_debug("Cache file is too old and will not be used.");
+        CACHE_FREE_VARS();
+        return;
+    }
+    group = NULL;
+
+    /* parse available timeslices */
+    for (i = 0; i < num_timeslices; i++) {
+        group = g_strdup_printf("timeslice%d", i);
+        if (!g_key_file_has_group(keyfile, group)) {
+            weather_debug("Group %s not found, continuing with next.", group);
+            g_free(group);
+            continue;
+        }
+
+        timeslice = make_timeslice();
+        if (G_UNLIKELY(timeslice == NULL)) {
+            g_free(group);
+            continue;
+        }
+
+        /* parse time strings (start, end, point) */
+        CACHE_READ_STRING(timestring, "start");
+        timeslice->start = parse_timestring(timestring, NULL);
+        g_free(timestring);
+        CACHE_READ_STRING(timestring, "end");
+        timeslice->end = parse_timestring(timestring, NULL);
+        g_free(timestring);
+        CACHE_READ_STRING(timestring, "point");
+        timeslice->point = parse_timestring(timestring, NULL);
+        g_free(timestring);
+
+        /* parse location data */
+        loc = timeslice->location;
+        CACHE_READ_STRING(loc->altitude, "altitude");
+        CACHE_READ_STRING(loc->latitude, "latitude");
+        CACHE_READ_STRING(loc->longitude, "longitude");
+        CACHE_READ_STRING(loc->temperature_value, "temperature_value");
+        CACHE_READ_STRING(loc->temperature_unit, "temperature_unit");
+        CACHE_READ_STRING(loc->wind_dir_deg, "wind_dir_deg");
+        CACHE_READ_STRING(loc->wind_speed_mps, "wind_speed_mps");
+        CACHE_READ_STRING(loc->wind_speed_beaufort, "wind_speed_beaufort");
+        CACHE_READ_STRING(loc->humidity_value, "humidity_value");
+        CACHE_READ_STRING(loc->humidity_unit, "humidity_unit");
+        CACHE_READ_STRING(loc->pressure_value, "pressure_value");
+        CACHE_READ_STRING(loc->pressure_unit, "pressure_unit");
+
+        for (j = 0; j < CLOUDS_PERC_NUM; j++) {
+            gchar *key = g_strdup_printf("clouds_percent[%d]", j);
+            if (g_key_file_has_key(keyfile, group, key, NULL))
+                loc->clouds_percent[j] =
+                    g_key_file_get_string(keyfile, group, key, NULL);
+            g_free(key);
+        }
+
+        CACHE_READ_STRING(loc->fog_percent, "fog_percent");
+        CACHE_READ_STRING(loc->precipitation_value, "precipitation_value");
+        CACHE_READ_STRING(loc->precipitation_unit, "precipitation_unit");
+        CACHE_READ_STRING(loc->symbol, "symbol");
+        if (loc->symbol &&
+            g_key_file_has_key(keyfile, group, "symbol_id", NULL))
+            loc->symbol_id =
+                g_key_file_get_integer(keyfile, group, "symbol_id", NULL);
+
+        merge_timeslice(wd, timeslice);
+        xml_time_free(timeslice);
+    }
+    CACHE_FREE_VARS();
+    weather_debug("Reading cache file complete.");
+}
+
+
 void
-update_weatherdata_with_reset(xfceweather_data *data)
+update_weatherdata_with_reset(plugin_data *data, gboolean clear)
 {
-    if (data->updatetimeout)
+    weather_debug("Update weatherdata with reset.");
+    g_assert(data != NULL);
+    if (G_UNLIKELY(data == NULL))
+        return;
+
+    if (data->updatetimeout) {
         g_source_remove(data->updatetimeout);
+        data->updatetimeout = 0;
+    }
 
     memset(&data->last_data_update, 0, sizeof(data->last_data_update));
     memset(&data->last_astro_update, 0, sizeof(data->last_astro_update));
     memset(&data->last_conditions_update, 0,
            sizeof(data->last_conditions_update));
+
+    /* clear existing weather data, needed for location changes */
+    if (clear && data->weatherdata) {
+        xml_weather_free(data->weatherdata);
+        data->weatherdata = make_weather_data();
+
+        /* make use of previously saved data */
+        read_cache_file(data);
+    }
+
     update_weatherdata(data);
 
     data->updatetimeout =
         g_timeout_add_seconds(UPDATE_INTERVAL,
                               (GSourceFunc) update_weatherdata,
                               data);
+    weather_debug("Updated weatherdata with reset.");
 }
 
 
@@ -687,9 +1032,10 @@ static void
 close_summary(GtkWidget *widget,
               gpointer *user_data)
 {
-    xfceweather_data *data = (xfceweather_data *) user_data;
+    plugin_data *data = (plugin_data *) user_data;
 
-    summary_details_free(data->summary_details);
+    if (data->summary_details)
+        summary_details_free(data->summary_details);
     data->summary_details = NULL;
     data->summary_window = NULL;
 }
@@ -699,7 +1045,7 @@ void
 forecast_click(GtkWidget *widget,
                gpointer user_data)
 {
-    xfceweather_data *data = (xfceweather_data *) user_data;
+    plugin_data *data = (plugin_data *) user_data;
 
     if (data->summary_window != NULL)
         gtk_widget_destroy(data->summary_window);
@@ -717,12 +1063,12 @@ cb_click(GtkWidget *widget,
          GdkEventButton *event,
          gpointer user_data)
 {
-    xfceweather_data *data = (xfceweather_data *) user_data;
+    plugin_data *data = (plugin_data *) user_data;
 
     if (event->button == 1)
         forecast_click(widget, user_data);
     else if (event->button == 2)
-        update_weatherdata_with_reset(data);
+        update_weatherdata_with_reset(data, FALSE);
 
     return FALSE;
 }
@@ -733,7 +1079,7 @@ cb_scroll(GtkWidget *widget,
           GdkEventScroll *event,
           gpointer user_data)
 {
-    xfceweather_data *data = (xfceweather_data *) user_data;
+    plugin_data *data = (plugin_data *) user_data;
 
     if (event->direction == GDK_SCROLL_UP ||
         event->direction == GDK_SCROLL_DOWN)
@@ -747,9 +1093,9 @@ static void
 mi_click(GtkWidget *widget,
          gpointer user_data)
 {
-    xfceweather_data *data = (xfceweather_data *) user_data;
+    plugin_data *data = (plugin_data *) user_data;
 
-    update_weatherdata_with_reset(data);
+    update_weatherdata_with_reset(data, FALSE);
 }
 
 
@@ -758,7 +1104,7 @@ xfceweather_dialog_response(GtkWidget *dlg,
                             gint response,
                             xfceweather_dialog *dialog)
 {
-    xfceweather_data *data = (xfceweather_data *) dialog->wd;
+    plugin_data *data = (plugin_data *) dialog->pd;
     icon_theme *theme;
     gboolean result;
     guint i;
@@ -776,7 +1122,7 @@ xfceweather_dialog_response(GtkWidget *dlg,
         gtk_widget_destroy(dlg);
         gtk_list_store_clear(dialog->model_datatypes);
         for (i = 0; i < dialog->icon_themes->len; i++) {
-            theme = g_array_index(dialog->icon_themes, icon_theme*, i);
+            theme = g_array_index(dialog->icon_themes, icon_theme *, i);
             icon_theme_free(theme);
             g_array_free(dialog->icon_themes, TRUE);
         }
@@ -793,7 +1139,7 @@ xfceweather_dialog_response(GtkWidget *dlg,
 
 static void
 xfceweather_create_options(XfcePanelPlugin *plugin,
-                           xfceweather_data *data)
+                           plugin_data *data)
 {
     GtkWidget *dlg, *vbox;
     xfceweather_dialog *dialog;
@@ -825,7 +1171,7 @@ xfceweather_create_options(XfcePanelPlugin *plugin,
 
 
 static gchar *
-weather_get_tooltip_text(const xfceweather_data *data)
+weather_get_tooltip_text(const plugin_data *data)
 {
     xml_time *conditions;
     struct tm *point_tm, *start_tm, *end_tm, *sunrise_tm, *sunset_tm;
@@ -965,7 +1311,7 @@ weather_get_tooltip_cb(GtkWidget *widget,
                        gint y,
                        gboolean keyboard_mode,
                        GtkTooltip *tooltip,
-                       xfceweather_data *data)
+                       plugin_data *data)
 {
     GdkPixbuf *icon;
     xml_time *conditions;
@@ -1000,10 +1346,10 @@ weather_get_tooltip_cb(GtkWidget *widget,
 }
 
 
-static xfceweather_data *
+static plugin_data *
 xfceweather_create_control(XfcePanelPlugin *plugin)
 {
-    xfceweather_data *data = g_slice_new0(xfceweather_data);
+    plugin_data *data = g_slice_new0(plugin_data);
     SoupMessage *msg;
     SoupURI *soup_proxy_uri;
     const gchar *proxy_uri;
@@ -1014,7 +1360,8 @@ xfceweather_create_control(XfcePanelPlugin *plugin)
     /* Initialize with sane default values */
     data->plugin = plugin;
     data->units = g_slice_new0(units_config);
-    data->weatherdata = NULL;
+    data->weatherdata = make_weather_data();
+    data->cache_file_max_age = CACHE_FILE_MAX_AGE;
     data->show_scrollbox = TRUE;
     data->scrollbox_lines = 1;
     data->scrollbox_animate = TRUE;
@@ -1121,7 +1468,7 @@ xfceweather_create_control(XfcePanelPlugin *plugin)
 
 static void
 xfceweather_free(XfcePanelPlugin *plugin,
-                 xfceweather_data *data)
+                 plugin_data *data)
 {
     weather_debug("Freeing plugin data.");
     g_assert(data != NULL);
@@ -1154,7 +1501,7 @@ xfceweather_free(XfcePanelPlugin *plugin,
     /* free icon theme */
     icon_theme_free(data->icon_theme);
 
-    g_slice_free(xfceweather_data, data);
+    g_slice_free(plugin_data, data);
     data = NULL;
 }
 
@@ -1162,7 +1509,7 @@ xfceweather_free(XfcePanelPlugin *plugin,
 static gboolean
 xfceweather_set_size(XfcePanelPlugin *panel,
                      gint size,
-                     xfceweather_data *data)
+                     plugin_data *data)
 {
     data->panel_size = size;
 #if LIBXFCE4PANEL_CHECK_VERSION(4,9,0)
@@ -1184,7 +1531,7 @@ xfceweather_set_size(XfcePanelPlugin *panel,
 static gboolean
 xfceweather_set_mode(XfcePanelPlugin *panel,
                      XfcePanelPluginMode mode,
-                     xfceweather_data *data)
+                     plugin_data *data)
 {
     GtkWidget *parent = gtk_widget_get_parent(data->vbox_center_scrollbox);
 
@@ -1227,7 +1574,7 @@ xfceweather_set_mode(XfcePanelPlugin *panel,
 static gboolean
 xfceweather_set_orientation(XfcePanelPlugin *panel,
                             GtkOrientation orientation,
-                            xfceweather_data *data)
+                            plugin_data *data)
 {
     GtkWidget *parent = gtk_widget_get_parent(data->vbox_center_scrollbox);
 
@@ -1261,7 +1608,7 @@ xfceweather_set_orientation(XfcePanelPlugin *panel,
 
 static void
 xfceweather_show_about(XfcePanelPlugin *plugin,
-                       xfceweather_data *data)
+                       plugin_data *data)
 {
     GdkPixbuf *icon;
     const gchar *auth[] = {
@@ -1294,7 +1641,7 @@ xfceweather_show_about(XfcePanelPlugin *plugin,
 static void
 weather_construct(XfcePanelPlugin *plugin)
 {
-    xfceweather_data *data;
+    plugin_data *data;
     const gchar *panel_debug_env;
 
     /* Enable debug level logging if PANEL_DEBUG contains G_LOG_DOMAIN */
@@ -1307,6 +1654,7 @@ weather_construct(XfcePanelPlugin *plugin)
     xfce_textdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8");
     data = xfceweather_create_control(plugin);
     xfceweather_read_config(plugin, data);
+    read_cache_file(data);
     scrollbox_set_visible(data);
     gtk_scrollbox_set_fontname(GTK_SCROLLBOX(data->scrollbox),
                                data->scrollbox_font);
diff --git a/panel-plugin/weather.h b/panel-plugin/weather.h
index 87ce68e..3a1d8a2 100644
--- a/panel-plugin/weather.h
+++ b/panel-plugin/weather.h
@@ -87,6 +87,7 @@ typedef struct {
     gchar *lon;
     gint msl;
     gint timezone;
+    gint cache_file_max_age;
     gboolean night_time;
 
     units_config *units;
@@ -96,7 +97,7 @@ typedef struct {
     forecast_layouts forecast_layout;
     gint forecast_days;
     gboolean round;
-} xfceweather_data;
+} plugin_data;
 
 
 extern gboolean debug_mode;
@@ -106,18 +107,21 @@ void weather_http_queue_request(SoupSession *session,
                                 SoupSessionCallback callback_func,
                                 gpointer user_data);
 
-void scrollbox_set_visible(xfceweather_data *data);
+void scrollbox_set_visible(plugin_data *data);
 
 void forecast_click(GtkWidget *widget,
                     gpointer user_data);
 
-void update_icon(xfceweather_data *data);
+gchar *get_cache_directory(void);
 
-void update_scrollbox(xfceweather_data *data);
+void update_icon(plugin_data *data);
 
-void update_weatherdata_with_reset(xfceweather_data *data);
+void update_scrollbox(plugin_data *data);
 
-GArray* labels_clear(GArray *array);
+void update_weatherdata_with_reset(plugin_data *data,
+                                   gboolean clear);
+
+GArray *labels_clear(GArray *array);
 
 G_END_DECLS
 


More information about the Xfce4-commits mailing list