]> err.no Git - mapper/commitdiff
MapWidget: Start to move and re-implement tile downloading
authorKaj-Michael Lang <milang@tal.org>
Wed, 20 Aug 2008 11:52:02 +0000 (14:52 +0300)
committerKaj-Michael Lang <milang@tal.org>
Wed, 20 Aug 2008 11:52:02 +0000 (14:52 +0300)
libs/libgtkmap/Makefile.am
libs/libgtkmap/tilerepo.c
libs/libgtkmap/tilerepo.h

index 31988f155e00bec9a1c96583116ae3061e531e89..42e8c7406857f2480bece41be6540e73d98ca48d 100644 (file)
@@ -30,8 +30,8 @@ libgtkmap_la_SOURCES = gtkmap.c gtkmap.h \
        path.c path.h position.c position.h \
        tilerepo.c tilerepo.h \
        $(TOPDIR)/latlon.c $(TOPDIR)/image-cache.c
-libgtkmap_la_CFLAGS = $(GLIBGTK_CFLAGS) $(GNOME_VFS_CFLAGS) $(LIBXML2_CFLAGS) $(GTKGLEXT_CFLAGS) $(defines) 
-libgtkmap_la_LIBADD = $(GLIBGTK_LIBS) $(GNOME_VFS_LIBS) $(LIBXML2_LIBS) $(GTKGLEXT_LIBS)
+libgtkmap_la_CFLAGS = $(GLIBGTK_CFLAGS) $(GNOME_VFS_CFLAGS) $(LIBXML2_CFLAGS) $(GTKGLEXT_CFLAGS) $(LIBCURL_CFLAGS) $(defines) 
+libgtkmap_la_LIBADD = $(GLIBGTK_LIBS) $(GNOME_VFS_LIBS) $(LIBXML2_LIBS) $(GTKGLEXT_LIBS) $(LIBCURL_LIBS)
 libgtkmap_la_LDFLAGS = -lm -no-undefined
 
 map_widget_test_SOURCES = map-widget-test.c
index 236b0ee6d5c1f68f51566cbb57f4ef78ee93f4a7..0a2ed9a47501db80f180ca3e7c0dc2b7f7ea6972 100644 (file)
@@ -42,6 +42,17 @@ enum {
        PROP_CACHE_DIR,
 };
 
+typedef struct _ProgressUpdateInfo ProgressUpdateInfo;
+struct _ProgressUpdateInfo {
+       gchar *src_str;
+       gchar *dest_str;
+       TileRepo *repo;
+       guint tilex, tiley, zoom;       /* for refresh. */
+       gint retries;           /* if equal to zero, it means we're DELETING maps. */
+       guint priority;
+       FILE *file;
+};
+
 #if 0
 #define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TILE_REPO_TYPE, TileRepoPrivate))
 #endif
@@ -65,8 +76,21 @@ TileRepo *tr=TILE_REPO(object);
 
 switch (prop_id) {
        case PROP_NAME:
+               if (tr->name)
+                       g_free(tr->name);
+               tr->name=g_value_dup_string(value);
+       break;
        case PROP_URL:
+               if (tr->url)
+                       g_free(tr->url);
+               tr->url=g_value_dup_string(value);
+               tile_repo_set_type(tr);
+       break;
        case PROP_CACHE_DIR:
+               if (tr->cache_dir)
+                       g_free(tr->cache_dir);
+               tr->cache_dir=g_value_dup_string(value);
+       break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
@@ -80,8 +104,14 @@ TileRepo *tr=TILE_REPO(object);
 
 switch (prop_id) {
        case PROP_NAME:
+               g_value_set_string(value, tr->name);
+       break;
        case PROP_URL:
+               g_value_set_string(value, tr->url);
+       break;
        case PROP_CACHE_DIR:
+               g_value_set_string(value, tr->cache_dir);
+       break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
@@ -99,6 +129,48 @@ object_class->set_property=tile_repo_set_property;
 object_class->get_property=tile_repo_get_property;
 }
 
+static gboolean 
+get_next_pui(gpointer key, gpointer value, ProgressUpdateInfo **data)
+{
+*data = key;
+return TRUE;
+}
+
+static gint
+download_comparefunc(const ProgressUpdateInfo *a, const ProgressUpdateInfo *b, gpointer user_data)
+{
+gint diff = (a->priority - b->priority);
+if (diff)
+       return diff;
+diff = (a->tilex - b->tilex);
+if (diff)
+       return diff;
+diff = (a->tiley - b->tiley);
+if (diff)
+       return diff;
+diff = (a->zoom - b->zoom);
+if (diff)
+       return diff;
+diff = (a->repo - b->repo);
+if (diff)
+       return diff;
+/* Otherwise, deletes are "greatest" (least priority). */
+if (!a->retries)
+       return (b->retries ? -1 : 0);
+else if (!b->retries)
+       return (a->retries ? 1 : 0);
+/* Do updates after non-updates (because they'll both be done anyway). */
+return (a->retries - b->retries);
+}
+
+static void 
+progress_update_info_free(ProgressUpdateInfo *pui)
+{
+g_free(pui->src_str);
+g_free(pui->dest_str);
+g_slice_free(ProgressUpdateInfo, pui);
+}
+
 /**
  * tile_repo_new:
  *
@@ -125,6 +197,17 @@ tr->cache_dir=NULL;
 tr->dl_zoom_steps=1;
 tr->double_size=0;
 tr->nextable=FALSE;
+
+tr->download.cond=g_cond_new();
+tr->download.mutex=g_mutex_new();
+tr->download.curl_easy_queue=g_queue_new();
+tr->download.pui_tree=g_tree_new_full((GCompareDataFunc)download_comparefunc, NULL, (GDestroyNotify) progress_update_info_free, NULL);
+tr->download.downloading_tree=g_tree_new_full((GCompareDataFunc)download_comparefunc, NULL, (GDestroyNotify) progress_update_info_free, NULL);
+tr->download.pui_by_easy=g_hash_table_new(g_direct_hash, g_direct_equal);
+tr->download.curl_multi=curl_multi_init();
+#ifdef CURL_PIPELINE
+curl_multi_setopt(tr->download.curl_multi, CURLMOPT_PIPELINING, 1);
+#endif
 }
 
 /**
@@ -149,8 +232,6 @@ TileRepo *tr;
 tr=tile_repo_new();
 g_return_val_if_fail(tr, NULL);
 
-g_debug("REPOSTR: %s", str);
-
 /* Parse name. */
 token=strsep(&str, "\n\t");
 if (token)
@@ -205,6 +286,11 @@ return g_strdup_printf("%s\t%s\t%s\t%d\t%d\t%d\t%d",
        tr->double_size, tr->nextable);
 }
 
+static void
+download_stop(TileRepo *tr)
+{
+}
+
 /**
  * tile_repo_free:
  * @tr
@@ -224,6 +310,30 @@ if (tr->cache_dir)
 if (tr->icache)
        image_cache_free(tr->icache);
 
+if (tr->download.curl_multi) {
+       gint num_transfers;
+
+       /* Finish up all downloads. */
+       while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(tr->download.curl_multi, &num_transfers) || num_transfers)
+               g_debug("NT: %d", num_transfers);
+
+       /* Stop all transfers and cleanup */
+       download_stop(tr);
+
+       curl_multi_cleanup(tr->download.curl_multi);
+}
+
+if (tr->download.curl_sid)
+    g_source_remove(tr->download.curl_sid);
+if (tr->download.pui_tree)
+       g_tree_destroy(tr->download.pui_tree);
+if (tr->download.downloading_tree)
+       g_tree_destroy(tr->download.downloading_tree);
+if (tr->download.pui_by_easy)
+       g_hash_table_destroy(tr->download.pui_by_easy);
+if (tr->download.curl_easy_queue)
+       g_queue_free(tr->download.curl_easy_queue);
+
 g_object_unref(tr);
 }
 
@@ -260,6 +370,60 @@ if (g_mkdir_with_parents(tr->cache_dir, 0755))
 return g_file_test(tr->cache_dir, G_FILE_TEST_EXISTS);
 }
 
+static void
+convert_coords_to_quadtree_string(gint x, gint y, gint zoomlevel, gchar *buffer, const gchar initial, const gchar * const quadrant)
+{
+gchar *ptr = buffer;
+gint n;
+
+if (initial)
+       *ptr++ = initial;
+
+for (n = 16 - zoomlevel; n >= 0; n--) {
+       gint xbit = (x >> n) & 1;
+       gint ybit = (y >> n) & 1;
+       *ptr++ = quadrant[xbit + 2 * ybit];
+}
+*ptr++ = '\0';
+}
+
+
+/**
+ * til
+ * Construct the URL that we should fetch, based on the current URI format.
+ * This method works differently depending on if a "%s" string is present in
+ * the URI format, since that would indicate a quadtree-based map coordinate
+ * system.
+ */
+static gchar *
+tile_repo_construct_url(TileRepo *tr, guint tilex, guint tiley, guint zoom)
+{
+switch (tr->type) {
+case REPOTYPE_XYZ:
+       return g_strdup_printf(tr->url, tilex, tiley, zoom);
+case REPOTYPE_XYZ_INV:
+       return g_strdup_printf(tr->url, 17 - zoom, tilex, tiley);
+case REPOTYPE_QUAD_QRST: {
+               gchar location[32];
+               convert_coords_to_quadtree_string(tilex, tiley, zoom, location, 't', "qrts");
+               return g_strdup_printf(tr->url, location);
+       }
+case REPOTYPE_QUAD_ZERO: {
+               /* This is a zero-based quadtree URI. */
+               gchar location[32];
+               convert_coords_to_quadtree_string(tilex, tiley, zoom, location, '\0', "0123");
+               return g_strdup_printf(tr->url, location);
+       }
+#ifdef MAP_DOWNLOAD_WMD
+case REPOTYPE_WMS:
+       return map_convert_wms_to_wms(tilex, tiley, zoom, tr->url);
+#endif
+default:
+       return NULL;
+}
+return "";
+}
+
 GdkPixbuf *
 tile_repo_load(TileRepo *tr, guint tilex, guint tiley, gint zoom, gint zoff, gboolean fast_fail)
 {
index ec4e5c4d4fc07cd7469f2d8b3235c3ede62f4657..aa3fc29f5ebeec5869a092881dda506d3a399b87 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <glib.h>
 #include <gtk/gtk.h>
+#include <curl/multi.h>
 
 #include "image-cache.h"
 
@@ -46,6 +47,22 @@ typedef enum {
        REPOTYPE_WMS            /* "service=wms" */
 } RepoType;
 
+typedef struct _TileDownload TileDownload;
+struct _TileDownload {
+       CURLM *curl_multi;
+
+       guint num_downloads;
+       guint curr_download;
+       guint curl_sid;
+
+       GCond* cond;
+       GMutex* mutex;
+       GQueue *curl_easy_queue;
+       GTree *pui_tree;
+       GTree *downloading_tree;
+       GHashTable *pui_by_easy;
+};
+
 typedef struct _TileRepo TileRepo;
 struct _TileRepo {
        GObject parent;
@@ -61,6 +78,7 @@ struct _TileRepo {
        gboolean nextable;
        ImageCache *icache;
        RepoType type;
+       TileDownload download;
        GtkWidget *menu_item;
 };