From: gnuite Date: Sat, 12 Jan 2008 22:46:01 +0000 (+0000) Subject: * Added an in-memory map cache to improve pan performance (thanks to Tim X-Git-Tag: fremantle/3.0+alpha0~188 X-Git-Url: http://git.itanic.dy.fi/?p=maemo-mapper;a=commitdiff_plain;h=502932fe9a1654d7d2e57bb6d796e7c665eb3077 * Added an in-memory map cache to improve pan performance (thanks to Tim Terriberry for the patch). * Fixed bug with infinitely repeating auto-route-update error messages. * Added option to completely disable all announcements. git-svn-id: svn+ssh://garage/var/lib/gforge/svnroot/maemo-mapper/trunk@144 6c538b50-5814-0410-93ad-8bdf4c0149d1 --- diff --git a/src/data.c b/src/data.c index aa34b8f..27c9f80 100644 --- a/src/data.c +++ b/src/data.c @@ -182,6 +182,7 @@ gint _draw_width = 5; gint _rotate_sens = 5; gint _ac_min_speed = 2; RotateDir _rotate_dir = ROTATE_DIR_UP; +gboolean _enable_announce = TRUE; gint _announce_notice_ratio = 8; gboolean _enable_voice = TRUE; GSList *_loc_list; diff --git a/src/data.h b/src/data.h index 92ffbcf..da3e984 100644 --- a/src/data.h +++ b/src/data.h @@ -161,6 +161,7 @@ extern gint _draw_width; extern gint _rotate_sens; extern gint _ac_min_speed; extern RotateDir _rotate_dir; +extern gboolean _enable_announce; extern gint _announce_notice_ratio; extern gboolean _enable_voice; extern GSList *_loc_list; diff --git a/src/defines.h b/src/defines.h index 01caeae..6f209ae 100644 --- a/src/defines.h +++ b/src/defines.h @@ -179,68 +179,6 @@ #define INITIAL_DOWNLOAD_RETRIES (3) -#define GCONF_KEY_PREFIX "/apps/maemo/maemo-mapper" -#define GCONF_KEY_GPS_RCVR_TYPE GCONF_KEY_PREFIX"/gps_rcvr_type" -#define GCONF_KEY_GPS_BT_MAC GCONF_KEY_PREFIX"/receiver_mac" -#define GCONF_KEY_GPS_GPSD_HOST GCONF_KEY_PREFIX"/gps_gpsd_host" -#define GCONF_KEY_GPS_GPSD_PORT GCONF_KEY_PREFIX"/gps_gpsd_port" -#define GCONF_KEY_GPS_FILE_PATH GCONF_KEY_PREFIX"/gps_file_path" -#define GCONF_KEY_AUTO_DOWNLOAD GCONF_KEY_PREFIX"/auto_download" -#define GCONF_KEY_AUTO_DOWNLOAD_PRECACHE \ - GCONF_KEY_PREFIX"/auto_download_precache" -#define GCONF_KEY_CENTER_SENSITIVITY GCONF_KEY_PREFIX"/center_sensitivity" -#define GCONF_KEY_ANNOUNCE_NOTICE GCONF_KEY_PREFIX"/announce_notice" -#define GCONF_KEY_ROTATE_SENSITIVITY GCONF_KEY_PREFIX"/rotate_sensitivity" -#define GCONF_KEY_AC_MIN_SPEED GCONF_KEY_PREFIX"/autocenter_min_speed" -#define GCONF_KEY_ROTATE_DIR GCONF_KEY_PREFIX"/rotate_direction" -#define GCONF_KEY_DRAW_WIDTH GCONF_KEY_PREFIX"/draw_width" -#define GCONF_KEY_ENABLE_VOICE GCONF_KEY_PREFIX"/enable_voice" -#define GCONF_KEY_VOICE_SPEED GCONF_KEY_PREFIX"/voice_speed" -#define GCONF_KEY_VOICE_PITCH GCONF_KEY_PREFIX"/voice_pitch" -#define GCONF_KEY_FULLSCREEN GCONF_KEY_PREFIX"/fullscreen" -#define GCONF_KEY_UNITS GCONF_KEY_PREFIX"/units" -#define GCONF_KEY_SPEED_LIMIT_ON GCONF_KEY_PREFIX"/speed_limit_on" -#define GCONF_KEY_SPEED_LIMIT GCONF_KEY_PREFIX"/speed_limit" -#define GCONF_KEY_SPEED_LOCATION GCONF_KEY_PREFIX"/speed_location" -#define GCONF_KEY_UNBLANK_SIZE GCONF_KEY_PREFIX"/unblank_option" -#define GCONF_KEY_INFO_FONT_SIZE GCONF_KEY_PREFIX"/info_font_size" - -#define GCONF_KEY_POI_DB GCONF_KEY_PREFIX"/poi_db" -#define GCONF_KEY_POI_ZOOM GCONF_KEY_PREFIX"/poi_zoom" - -#define GCONF_KEY_AUTOCENTER_MODE GCONF_KEY_PREFIX"/autocenter_mode" -#define GCONF_KEY_AUTOCENTER_ROTATE GCONF_KEY_PREFIX"/autocenter_rotate" -#define GCONF_KEY_LEAD_AMOUNT GCONF_KEY_PREFIX"/lead_amount" -#define GCONF_KEY_LEAD_IS_FIXED GCONF_KEY_PREFIX"/lead_is_fixed" -#define GCONF_KEY_LAST_LAT GCONF_KEY_PREFIX"/last_latitude" -#define GCONF_KEY_LAST_LON GCONF_KEY_PREFIX"/last_longitude" -#define GCONF_KEY_LAST_ALT GCONF_KEY_PREFIX"/last_altitude" -#define GCONF_KEY_LAST_SPEED GCONF_KEY_PREFIX"/last_speed" -#define GCONF_KEY_LAST_HEADING GCONF_KEY_PREFIX"/last_heading" -#define GCONF_KEY_LAST_TIME GCONF_KEY_PREFIX"/last_timestamp" -#define GCONF_KEY_CENTER_LAT GCONF_KEY_PREFIX"/center_latitude" -#define GCONF_KEY_CENTER_LON GCONF_KEY_PREFIX"/center_longitude" -#define GCONF_KEY_CENTER_ANGLE GCONF_KEY_PREFIX"/center_angle" -#define GCONF_KEY_ZOOM GCONF_KEY_PREFIX"/zoom" -#define GCONF_KEY_ROUTEDIR GCONF_KEY_PREFIX"/route_directory" -#define GCONF_KEY_TRACKFILE GCONF_KEY_PREFIX"/track_file" -#define GCONF_KEY_SHOWZOOMLEVEL GCONF_KEY_PREFIX"/show_zoomlevel" -#define GCONF_KEY_SHOWSCALE GCONF_KEY_PREFIX"/show_scale" -#define GCONF_KEY_SHOWCOMPROSE GCONF_KEY_PREFIX"/show_comprose" -#define GCONF_KEY_SHOWTRACKS GCONF_KEY_PREFIX"/show_tracks" -#define GCONF_KEY_SHOWROUTES GCONF_KEY_PREFIX"/show_routes" -#define GCONF_KEY_SHOWVELVEC GCONF_KEY_PREFIX"/show_velocity_vector" -#define GCONF_KEY_SHOWPOIS GCONF_KEY_PREFIX"/show_poi" -#define GCONF_KEY_ENABLE_GPS GCONF_KEY_PREFIX"/enable_gps" -#define GCONF_KEY_ROUTE_LOCATIONS GCONF_KEY_PREFIX"/route_locations" -#define GCONF_KEY_REPOSITORIES GCONF_KEY_PREFIX"/repositories" -#define GCONF_KEY_CURRREPO GCONF_KEY_PREFIX"/curr_repo" -#define GCONF_KEY_GPS_INFO GCONF_KEY_PREFIX"/gps_info" -#define GCONF_KEY_ROUTE_DL_URL GCONF_KEY_PREFIX"/route_dl_url" -#define GCONF_KEY_ROUTE_DL_RADIUS GCONF_KEY_PREFIX"/route_dl_radius" -#define GCONF_KEY_POI_DL_URL GCONF_KEY_PREFIX"/poi_dl_url" -#define GCONF_KEY_DEG_FORMAT GCONF_KEY_PREFIX"/deg_format" - #define CONFIG_DIR_NAME "~/.maemo-mapper/" #define CONFIG_PATH_DB_FILE "paths.db" diff --git a/src/main.c b/src/main.c index 93ed9c2..efeed6e 100644 --- a/src/main.c +++ b/src/main.c @@ -74,6 +74,10 @@ static gboolean _conic_conn_failed = FALSE; static GMutex *_conic_connection_mutex = NULL; static GCond *_conic_connection_cond = NULL; +/* Dynamically-sized in-memory map cache. */ +static size_t _map_cache_size = (32*1024*1024); +static gboolean _map_cache_enabled = TRUE; + static void conic_conn_event(ConIcConnection *connection, ConIcConnectionEvent *event) { @@ -192,6 +196,7 @@ maemo_mapper_destroy() g_mutex_unlock(_mapdb_mutex); #endif } + map_cache_destroy(); gps_destroy(TRUE); @@ -231,16 +236,6 @@ maemo_mapper_init(gint argc, gchar **argv) INFO_FONT_ENUM_TEXT[INFO_FONT_XLARGE] = "x-large"; INFO_FONT_ENUM_TEXT[INFO_FONT_XXLARGE] = "xx-large"; - CUSTOM_KEY_GCONF[CUSTOM_KEY_UP] = GCONF_KEY_PREFIX"/key_up"; - CUSTOM_KEY_GCONF[CUSTOM_KEY_DOWN] = GCONF_KEY_PREFIX"/key_down"; - CUSTOM_KEY_GCONF[CUSTOM_KEY_LEFT] = GCONF_KEY_PREFIX"/key_left"; - CUSTOM_KEY_GCONF[CUSTOM_KEY_RIGHT] = GCONF_KEY_PREFIX"/key_right"; - CUSTOM_KEY_GCONF[CUSTOM_KEY_SELECT] = GCONF_KEY_PREFIX"/key_select"; - CUSTOM_KEY_GCONF[CUSTOM_KEY_INCREASE] = GCONF_KEY_PREFIX"/key_increase"; - CUSTOM_KEY_GCONF[CUSTOM_KEY_DECREASE] = GCONF_KEY_PREFIX"/key_decrease"; - CUSTOM_KEY_GCONF[CUSTOM_KEY_FULLSCREEN]= GCONF_KEY_PREFIX"/key_fullscreen"; - CUSTOM_KEY_GCONF[CUSTOM_KEY_ESC] = GCONF_KEY_PREFIX"/key_esc"; - CUSTOM_KEY_ICON[CUSTOM_KEY_UP] = HWK_BUTTON_UP; CUSTOM_KEY_ICON[CUSTOM_KEY_LEFT] = HWK_BUTTON_LEFT; CUSTOM_KEY_ICON[CUSTOM_KEY_DOWN] = HWK_BUTTON_DOWN; @@ -305,20 +300,6 @@ maemo_mapper_init(gint argc, gchar **argv) CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_RESET_BLUETOOTH] = _("Reset Bluetooth"); - COLORABLE_GCONF[COLORABLE_MARK] = GCONF_KEY_PREFIX"/color_mark"; - COLORABLE_GCONF[COLORABLE_MARK_VELOCITY] - = GCONF_KEY_PREFIX"/color_mark_velocity"; - COLORABLE_GCONF[COLORABLE_MARK_OLD] = GCONF_KEY_PREFIX"/color_mark_old"; - COLORABLE_GCONF[COLORABLE_TRACK] = GCONF_KEY_PREFIX"/color_track"; - COLORABLE_GCONF[COLORABLE_TRACK_MARK] =GCONF_KEY_PREFIX"/color_track_mark"; - COLORABLE_GCONF[COLORABLE_TRACK_BREAK] - = GCONF_KEY_PREFIX"/color_track_break"; - COLORABLE_GCONF[COLORABLE_ROUTE] = GCONF_KEY_PREFIX"/color_route"; - COLORABLE_GCONF[COLORABLE_ROUTE_WAY] = GCONF_KEY_PREFIX"/color_route_way"; - COLORABLE_GCONF[COLORABLE_ROUTE_BREAK] - = GCONF_KEY_PREFIX"/color_route_break"; - COLORABLE_GCONF[COLORABLE_POI] = GCONF_KEY_PREFIX"/color_poi"; - DEG_FORMAT_ENUM_TEXT[DDPDDDDD] = "-dd.ddddd°"; DEG_FORMAT_ENUM_TEXT[DD_MMPMMM] = "-dd°mm.mmm'"; DEG_FORMAT_ENUM_TEXT[DD_MM_SSPS] = "-dd°mm'ss.s\""; @@ -352,6 +333,7 @@ maemo_mapper_init(gint argc, gchar **argv) _conic_connection_cond = g_cond_new(); settings_init(); + map_cache_init(_map_cache_size); /* Initialize _program. */ _program = HILDON_PROGRAM(hildon_program_get_instance()); @@ -543,15 +525,33 @@ osso_cb_hw_state_idle(osso_hw_state_t *state) state->save_unsaved_data_ind, state->shutdown_ind, state->memory_low_ind, state->sig_device_mode_ind); + if(state->shutdown_ind) + { + maemo_mapper_destroy(); + exit(1); + } + if(state->save_unsaved_data_ind) { settings_save(); _must_save_data = TRUE; } - else if(state->shutdown_ind) + + if(state->memory_low_ind) { - maemo_mapper_destroy(); - exit(1); + // Disable the map cache and set the next max cache size to + // slightly less than the current cache size. + _map_cache_size = map_cache_resize(0) * 0.8; + _map_cache_enabled = FALSE; + } + else + { + if(!_map_cache_enabled) + { + // Restore the map cache. + map_cache_resize(_map_cache_size); + _map_cache_enabled = TRUE; + } } g_free(state); diff --git a/src/maps.c b/src/maps.c index 5ee5c54..9d0457a 100644 --- a/src/maps.c +++ b/src/maps.c @@ -109,74 +109,62 @@ struct _MapmanInfo { GtkWidget *chk_zoom_levels[MAX_ZOOM + 1]; }; +typedef struct _MapCacheKey MapCacheKey; +struct _MapCacheKey { + RepoData *repo; + gint zoom; + gint tilex; + gint tiley; +}; -gboolean -mapdb_exists(RepoData *repo, gint zoom, gint tilex, gint tiley) -{ - gboolean exists; - vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__, - repo->name, zoom, tilex, tiley); - - g_mutex_lock(_mapdb_mutex); +typedef struct _MapCacheEntry MapCacheEntry; +struct _MapCacheEntry { + MapCacheKey key; + int list; + guint size; + guint data_sz; + gchar *data; + GdkPixbuf *pixbuf; + MapCacheEntry *next; + MapCacheEntry *prev; +}; - if(!repo->db) - { - /* There is no cache. Return FALSE. */ - g_mutex_unlock(_mapdb_mutex); - vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__); - return FALSE; - } +typedef struct _MapCacheList MapCacheList; +struct _MapCacheList { + MapCacheEntry *head; + MapCacheEntry *tail; + size_t size; + size_t data_sz; +}; -#ifdef MAPDB_SQLITE - /* Attempt to retrieve map from database. */ - if(SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 1, zoom) - && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 2, tilex) - && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 3, tiley) - && SQLITE_ROW == sqlite3_step(repo->stmt_map_exists) - && sqlite3_column_int(repo->stmt_map_exists, 0) > 0) - { - exists = TRUE; - } - else - { - exists = FALSE; - } - sqlite3_reset(repo->stmt_map_exists); -#else - { - datum d; - gint32 key[] = { - GINT32_TO_BE(zoom), - GINT32_TO_BE(tilex), - GINT32_TO_BE(tiley) - }; - d.dptr = (gchar*)&key; - d.dsize = sizeof(key); - exists = gdbm_exists(repo->db, d); - } -#endif +typedef struct _MapCache MapCache; +struct _MapCache { + MapCacheList lists[4]; + size_t cache_size; + size_t p; + size_t thits; + size_t bhits; + size_t misses; + GHashTable *entries; +}; - g_mutex_unlock(_mapdb_mutex); +static MapCache _map_cache; - vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, exists); - return exists; -} -GdkPixbuf* -mapdb_get(RepoData *repo, gint zoom, gint tilex, gint tiley) +static guint +mapdb_get_data(RepoData *repo, gint zoom, gint tilex, gint tiley, gchar **data) { - GdkPixbuf *pixbuf = NULL; + guint size; vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__, repo->name, zoom, tilex, tiley); - - g_mutex_lock(_mapdb_mutex); + *data = NULL; + size = 0; if(!repo->db) { /* There is no cache. Return NULL. */ - g_mutex_unlock(_mapdb_mutex); - vprintf("%s(): return NULL\n", __PRETTY_FUNCTION__); - return NULL; + vprintf("%s(): return %u\n", __PRETTY_FUNCTION__,size); + return size; } #ifdef MAPDB_SQLITE @@ -187,7 +175,7 @@ mapdb_get(RepoData *repo, gint zoom, gint tilex, gint tiley) && SQLITE_ROW == sqlite3_step(repo->stmt_map_select)) { const gchar *bytes = NULL; - gint size = sqlite3_column_bytes(repo->stmt_map_select, 0); + size = sqlite3_column_bytes(repo->stmt_map_select, 0); /* "Pixbufs" of size less than or equal to MAX_PIXBUF_DUP_SIZE are * actually keys into the dups table. */ @@ -218,6 +206,7 @@ mapdb_get(RepoData *repo, gint zoom, gint tilex, gint tiley) /* We have no bytes to return to the caller. */ bytes = NULL; + size = 0; } /* Don't reset the statement yet - we need the blob. */ } @@ -227,13 +216,8 @@ mapdb_get(RepoData *repo, gint zoom, gint tilex, gint tiley) } if(bytes) { - GError *error = NULL; - GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); - gdk_pixbuf_loader_write(loader, bytes, size, NULL); - gdk_pixbuf_loader_close(loader, &error); - if(!error) - pixbuf = g_object_ref(gdk_pixbuf_loader_get_pixbuf(loader)); - g_object_unref(loader); + *data = g_slice_alloc(size); + memcpy(*data, bytes, size); } if(size <= MAX_PIXBUF_DUP_SIZE) sqlite3_reset(repo->stmt_dup_select); @@ -252,20 +236,398 @@ mapdb_get(RepoData *repo, gint zoom, gint tilex, gint tiley) d = gdbm_fetch(repo->db, d); if(d.dptr) { - GError *error = NULL; - GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); - gdk_pixbuf_loader_write(loader, d.dptr, d.dsize, NULL); - g_free(d.dptr); - gdk_pixbuf_loader_close(loader, &error); - if(!error) - pixbuf = g_object_ref(gdk_pixbuf_loader_get_pixbuf(loader)); + size = d.dsize; + *data = g_slice_alloc(size); + memcpy(*data, d.dptr, size); + free(d.dptr); + } + } +#endif + + vprintf("%s(): return %u\n", __PRETTY_FUNCTION__, size); + return size; +} + +static void map_cache_list_remove(MapCacheList *_list, MapCacheEntry *_entry) +{ + _list->size -= _entry->size; + _list->data_sz -= _entry->data_sz; + *(_entry->prev != NULL?&_entry->prev->next:&_list->head) = _entry->next; + *(_entry->next != NULL?&_entry->next->prev:&_list->tail) = _entry->prev; +} + +static void map_cache_list_prepend(MapCacheList *_list, int _li, + MapCacheEntry *_entry) +{ + _entry->prev = NULL; + _entry->next = _list[_li].head; + *(_list[_li].head != NULL?&_list[_li].head->prev:&_list[_li].tail) = _entry; + _list[_li].head = _entry; + _list[_li].size += _entry->size; + _list[_li].data_sz += _entry->data_sz; + _entry->list = _li; +} + +static guint map_cache_key_hash(gconstpointer _key){ + const MapCacheKey *key; + key = (const MapCacheKey *)_key; + return g_direct_hash(key->repo)+g_int_hash(&key->zoom)+ + g_int_hash(&key->tilex)+g_int_hash(&key->tiley); +} + +static gboolean map_cache_key_equal(gconstpointer _v1, gconstpointer _v2){ + const MapCacheKey *key1; + const MapCacheKey *key2; + key1 = (const MapCacheKey *)_v1; + key2 = (const MapCacheKey *)_v2; + return key1->tilex == key2->tilex && key1->tiley == key2->tiley && + key1->zoom == key2->zoom && key1->repo == key2->repo; +} + +static void map_cache_entry_make_pixbuf(MapCacheEntry *_entry){ + if (_entry->data != NULL) + { + GError *error; + GdkPixbufLoader *loader; + error = NULL; + loader = gdk_pixbuf_loader_new(); + gdk_pixbuf_loader_write(loader, _entry->data, _entry->data_sz, NULL); + gdk_pixbuf_loader_close(loader, &error); + if(!error) + { + _entry->pixbuf = g_object_ref(gdk_pixbuf_loader_get_pixbuf(loader)); + _entry->size = _entry->data_sz+ + gdk_pixbuf_get_rowstride(_entry->pixbuf)* + gdk_pixbuf_get_height(_entry->pixbuf); g_object_unref(loader); + return; + } + g_object_unref(loader); + g_slice_free1(_entry->data_sz, _entry->data); + _entry->data = NULL; + _entry->data_sz = 0; + } + _entry->pixbuf = NULL; + _entry->size = _entry->data_sz; +} + +static void map_cache_entry_free_pixbuf(MapCacheEntry *_entry){ + if(_entry->pixbuf!=NULL) + { + g_object_unref(_entry->pixbuf); + _entry->pixbuf = NULL; + } +} + +static void map_cache_entry_free(MapCacheEntry *_entry){ + if(_entry->list >= 0) + map_cache_list_remove(_map_cache.lists+_entry->list, _entry); + map_cache_entry_free_pixbuf(_entry); + g_slice_free1(_entry->data_sz, _entry->data); + g_slice_free(MapCacheEntry, _entry); +} + +static gboolean +map_cache_replace(size_t _size, gboolean _b2) +{ + gboolean ret; + size_t total_size; + total_size = _map_cache.lists[0].size+_map_cache.lists[1].data_sz + +_map_cache.lists[2].size+_map_cache.lists[3].data_sz; + ret = FALSE; + while(total_size+_size > _map_cache.cache_size) + { + MapCacheEntry *entry; + int list; + if(_map_cache.lists[0].tail != NULL && + (_map_cache.lists[0].size > _map_cache.p || + (_b2 && _map_cache.lists[0].size == _map_cache.p))) + list = 0; + else + list = 2; + entry = _map_cache.lists[list].tail; + if(entry == NULL) + break; + map_cache_list_remove(_map_cache.lists+list, entry); + map_cache_list_prepend(_map_cache.lists, list+1, entry); + total_size -= entry->size - entry->data_sz; + ret = TRUE; + _b2 = FALSE; + } + return ret; +} + +static void +map_cache_evict(size_t _size) +{ + size_t total_size; + size_t max_size; + total_size = _map_cache.lists[0].size+_map_cache.lists[1].size + +_map_cache.lists[2].size+_map_cache.lists[3].size; + max_size = _map_cache.cache_size<<1; + for(;;) + { + if(_map_cache.lists[0].size+_map_cache.lists[1].size+_size > + _map_cache.cache_size) + { + if(_map_cache.lists[1].tail != NULL) + { + g_hash_table_remove(_map_cache.entries, + &_map_cache.lists[1].tail->key); + map_cache_replace(_size, FALSE); + } + else if(_map_cache.lists[0].tail != NULL) + { + g_hash_table_remove(_map_cache.entries, + &_map_cache.lists[0].tail->key); + } + else break; + } + else if(total_size+_size > _map_cache.cache_size) + { + if(total_size+_size > max_size && + _map_cache.lists[3].tail != NULL) + { + g_hash_table_remove(_map_cache.entries, + &_map_cache.lists[3].tail->key); + map_cache_replace(_size, FALSE); + } + else if(!map_cache_replace(_size, FALSE)) + break; + } + else break; + total_size = _map_cache.lists[0].size+_map_cache.lists[1].size + +_map_cache.lists[2].size+_map_cache.lists[3].size; + } +} + +static GdkPixbuf * +map_cache_get(RepoData *repo, gint zoom, gint tilex, gint tiley) +{ + MapCacheKey key; + MapCacheEntry *entry; + key.repo = repo; + key.zoom = zoom; + key.tilex = tilex; + key.tiley = tiley; + entry = (MapCacheEntry *)g_hash_table_lookup(_map_cache.entries, &key); + if(entry != NULL) + { + map_cache_list_remove(_map_cache.lists+entry->list, entry); + if(entry->pixbuf == NULL) + { + size_t bsize; + size_t dp; + map_cache_entry_make_pixbuf(entry); + bsize = _map_cache.lists[entry->list].size+entry->size; + if(bsize < 1) + bsize = 1; + dp = _map_cache.lists[entry->list^2].size/bsize; + if(dp < 1) + dp = 1; + if(entry->list == 1) + { + _map_cache.p += dp; + if(_map_cache.p > _map_cache.cache_size) + _map_cache.p = _map_cache.cache_size; + map_cache_replace(entry->size, FALSE); + } + else + { + if(dp > _map_cache.p) + _map_cache.p = 0; + else + _map_cache.p -= dp; + map_cache_replace(entry->size, TRUE); + } + _map_cache.bhits++; + } + else + _map_cache.thits++; + map_cache_list_prepend(_map_cache.lists, 2, entry); + } + else + { + gchar *data; + guint data_sz; + data_sz = mapdb_get_data(repo, zoom, tilex, tiley, &data); + entry = g_slice_new(MapCacheEntry); + *&entry->key = *&key; + entry->data = data; + entry->data_sz = data_sz; + map_cache_entry_make_pixbuf(entry); + map_cache_evict(entry->size); + map_cache_list_prepend(_map_cache.lists, 0, entry); + g_hash_table_insert(_map_cache.entries, &entry->key, entry); + _map_cache.misses++; + } + if(entry->pixbuf != NULL) + g_object_ref(entry->pixbuf); + return entry->pixbuf; +} + +static void +map_cache_update(RepoData *repo, gint zoom, gint tilex, gint tiley, + gchar *data,guint size) +{ + MapCacheKey key; + MapCacheEntry *entry; + key.repo = repo; + key.zoom = zoom; + key.tilex = tilex; + key.tiley = tiley; + entry = (MapCacheEntry *)g_hash_table_lookup(_map_cache.entries, &key); + if(entry != NULL) + { + g_slice_free1(entry->data_sz, entry->data); + entry->data = g_slice_alloc(size); + memcpy(entry->data, data, size); + entry->data_sz = size; + if(entry->pixbuf != NULL) + { + map_cache_entry_free_pixbuf(entry); + map_cache_list_remove(_map_cache.lists+entry->list, entry); + map_cache_list_prepend(_map_cache.lists, entry->list+1, entry); + } + } +} + +static void +map_cache_remove(RepoData *repo, gint zoom, gint tilex, gint tiley) +{ + MapCacheKey key; + key.repo = repo; + key.zoom = zoom; + key.tilex = tilex; + key.tiley = tiley; + g_hash_table_remove(_map_cache.entries, &key); +} + +void +map_cache_init(size_t cache_size) +{ + g_mutex_lock(_mapdb_mutex); + if(_map_cache.entries == NULL) + _map_cache.entries = g_hash_table_new_full(map_cache_key_hash, + map_cache_key_equal, NULL, (GDestroyNotify)map_cache_entry_free); + _map_cache.cache_size = cache_size; + if(_map_cache.p > cache_size) + _map_cache.p = cache_size; + map_cache_evict(0); + g_mutex_unlock(_mapdb_mutex); +} + +size_t +map_cache_resize(size_t cache_size) +{ + size_t total_size; + g_mutex_lock(_mapdb_mutex); + _map_cache.cache_size = cache_size; + total_size = _map_cache.lists[0].size+_map_cache.lists[1].data_sz + +_map_cache.lists[2].size+_map_cache.lists[3].data_sz; + g_mutex_unlock(_mapdb_mutex); + return total_size; +} + +void +map_cache_destroy(void) +{ + g_mutex_lock(_mapdb_mutex); + if(_map_cache.entries != NULL) + { + g_hash_table_destroy(_map_cache.entries); + _map_cache.entries = NULL; + printf("thits: %u (%0.2f%%) bhits: %u (%0.2f%%) " + "misses: %u (%0.2f%%)\n", + _map_cache.thits, 100*_map_cache.thits/(double)( + _map_cache.thits+_map_cache.bhits+_map_cache.misses), + _map_cache.bhits, 100*_map_cache.bhits/(double)( + _map_cache.thits+_map_cache.bhits+_map_cache.misses), + _map_cache.misses, 100*_map_cache.misses/(double)( + _map_cache.thits+_map_cache.bhits+_map_cache.misses)); + } + g_mutex_unlock(_mapdb_mutex); +} + +gboolean +mapdb_exists(RepoData *repo, gint zoom, gint tilex, gint tiley) +{ + gboolean exists; + vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__, + repo->name, zoom, tilex, tiley); + + g_mutex_lock(_mapdb_mutex); + + if(!repo->db) + { + /* There is no cache. Return FALSE. */ + g_mutex_unlock(_mapdb_mutex); + vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__); + return FALSE; + } + + /* Search the cache first. */ + { + MapCacheKey key; + MapCacheEntry *entry; + key.repo = repo; + key.zoom = zoom; + key.tilex = tilex; + key.tiley = tiley; + entry = (MapCacheEntry *)g_hash_table_lookup(_map_cache.entries, &key); + if(entry != NULL) + { + gboolean ret; + ret = entry->data != NULL; + g_mutex_unlock(_mapdb_mutex); + return ret; } } + +#ifdef MAPDB_SQLITE + /* Attempt to retrieve map from database. */ + if(SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 1, zoom) + && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 2, tilex) + && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 3, tiley) + && SQLITE_ROW == sqlite3_step(repo->stmt_map_exists) + && sqlite3_column_int(repo->stmt_map_exists, 0) > 0) + { + exists = TRUE; + } + else + { + exists = FALSE; + } + sqlite3_reset(repo->stmt_map_exists); +#else + { + datum d; + gint32 key[] = { + GINT32_TO_BE(zoom), + GINT32_TO_BE(tilex), + GINT32_TO_BE(tiley) + }; + d.dptr = (gchar*)&key; + d.dsize = sizeof(key); + exists = gdbm_exists(repo->db, d); + } #endif g_mutex_unlock(_mapdb_mutex); + vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, exists); + return exists; +} + +GdkPixbuf* +mapdb_get(RepoData *repo, gint zoom, gint tilex, gint tiley) +{ + GdkPixbuf *pixbuf; + vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__, + repo->name, zoom, tilex, tiley); + g_mutex_lock(_mapdb_mutex); + pixbuf = map_cache_get(repo, zoom, tilex, tiley); + g_mutex_unlock(_mapdb_mutex); vprintf("%s(): return %p\n", __PRETTY_FUNCTION__, pixbuf); return pixbuf; } @@ -322,6 +684,7 @@ mapdb_update(gboolean exists, RepoData *repo, repo->name, zoom, tilex, tiley); g_mutex_lock(_mapdb_mutex); + map_cache_update(repo, zoom, tilex, tiley, bytes, size); if(!repo->db) { @@ -451,6 +814,7 @@ mapdb_delete(RepoData *repo, gint zoom, gint tilex, gint tiley) repo->name, zoom, tilex, tiley); g_mutex_lock(_mapdb_mutex); + map_cache_remove(repo, zoom, tilex, tiley); if(!repo->db) { diff --git a/src/maps.h b/src/maps.h index 09f4cbe..1452e36 100644 --- a/src/maps.h +++ b/src/maps.h @@ -24,6 +24,10 @@ #ifndef MAEMO_MAPPER_MAPS_H #define MAEMO_MAPPER_MAPS_H +void map_cache_init(size_t cache_size); +size_t map_cache_resize(size_t cache_size); +void map_cache_destroy(void); + gboolean mapdb_exists(RepoData *repo, gint zoom, gint tilex, gint tiley); GdkPixbuf* mapdb_get(RepoData *repo, gint zoom, gint tilex, gint tiley); diff --git a/src/path.c b/src/path.c index 67edeae..5c8aa0e 100644 --- a/src/path.c +++ b/src/path.c @@ -709,8 +709,9 @@ auto_route_dl_idle() g_ascii_dtostr(lonstr, 32, _gps.lon); snprintf(latlonstr, sizeof(latlonstr), "%s, %s", latstr, lonstr); - route_download_and_setup(_window, _autoroute_data.source_url, latlonstr, - _autoroute_data.dest, _autoroute_data.avoid_highways,0); + if(!route_download_and_setup(_window, _autoroute_data.source_url, latlonstr, + _autoroute_data.dest, _autoroute_data.avoid_highways,0)) + cancel_autoroute(); _autoroute_data.in_progress = FALSE; @@ -919,8 +920,9 @@ track_add(time_t time, gboolean newly_fixed) } /* Check if we should announce upcoming waypoints. */ - if(_initial_distance_waypoint || _next_way_dist_squared - < (announce_thres_unsquared * announce_thres_unsquared)) + if(_enable_announce + && (_initial_distance_waypoint || _next_way_dist_squared + < (announce_thres_unsquared * announce_thres_unsquared))) { if(show_directions) { diff --git a/src/settings.c b/src/settings.c index 5bac720..917dd71 100644 --- a/src/settings.c +++ b/src/settings.c @@ -64,6 +64,70 @@ #include "settings.h" #include "util.h" +#define GCONF_KEY_PREFIX "/apps/maemo/maemo-mapper" +#define GCONF_KEY_GPS_RCVR_TYPE GCONF_KEY_PREFIX"/gps_rcvr_type" +#define GCONF_KEY_GPS_BT_MAC GCONF_KEY_PREFIX"/receiver_mac" +#define GCONF_KEY_GPS_GPSD_HOST GCONF_KEY_PREFIX"/gps_gpsd_host" +#define GCONF_KEY_GPS_GPSD_PORT GCONF_KEY_PREFIX"/gps_gpsd_port" +#define GCONF_KEY_GPS_FILE_PATH GCONF_KEY_PREFIX"/gps_file_path" +#define GCONF_KEY_AUTO_DOWNLOAD GCONF_KEY_PREFIX"/auto_download" +#define GCONF_KEY_AUTO_DOWNLOAD_PRECACHE \ + GCONF_KEY_PREFIX"/auto_download_precache" +#define GCONF_KEY_CENTER_SENSITIVITY GCONF_KEY_PREFIX"/center_sensitivity" +#define GCONF_KEY_ENABLE_ANNOUNCE GCONF_KEY_PREFIX"/enable_announce" +#define GCONF_KEY_ANNOUNCE_NOTICE GCONF_KEY_PREFIX"/announce_notice" +#define GCONF_KEY_ROTATE_SENSITIVITY GCONF_KEY_PREFIX"/rotate_sensitivity" +#define GCONF_KEY_AC_MIN_SPEED GCONF_KEY_PREFIX"/autocenter_min_speed" +#define GCONF_KEY_ROTATE_DIR GCONF_KEY_PREFIX"/rotate_direction" +#define GCONF_KEY_DRAW_WIDTH GCONF_KEY_PREFIX"/draw_width" +#define GCONF_KEY_ENABLE_VOICE GCONF_KEY_PREFIX"/enable_voice" +#define GCONF_KEY_VOICE_SPEED GCONF_KEY_PREFIX"/voice_speed" +#define GCONF_KEY_VOICE_PITCH GCONF_KEY_PREFIX"/voice_pitch" +#define GCONF_KEY_FULLSCREEN GCONF_KEY_PREFIX"/fullscreen" +#define GCONF_KEY_UNITS GCONF_KEY_PREFIX"/units" +#define GCONF_KEY_SPEED_LIMIT_ON GCONF_KEY_PREFIX"/speed_limit_on" +#define GCONF_KEY_SPEED_LIMIT GCONF_KEY_PREFIX"/speed_limit" +#define GCONF_KEY_SPEED_LOCATION GCONF_KEY_PREFIX"/speed_location" +#define GCONF_KEY_UNBLANK_SIZE GCONF_KEY_PREFIX"/unblank_option" +#define GCONF_KEY_INFO_FONT_SIZE GCONF_KEY_PREFIX"/info_font_size" + +#define GCONF_KEY_POI_DB GCONF_KEY_PREFIX"/poi_db" +#define GCONF_KEY_POI_ZOOM GCONF_KEY_PREFIX"/poi_zoom" + +#define GCONF_KEY_AUTOCENTER_MODE GCONF_KEY_PREFIX"/autocenter_mode" +#define GCONF_KEY_AUTOCENTER_ROTATE GCONF_KEY_PREFIX"/autocenter_rotate" +#define GCONF_KEY_LEAD_AMOUNT GCONF_KEY_PREFIX"/lead_amount" +#define GCONF_KEY_LEAD_IS_FIXED GCONF_KEY_PREFIX"/lead_is_fixed" +#define GCONF_KEY_LAST_LAT GCONF_KEY_PREFIX"/last_latitude" +#define GCONF_KEY_LAST_LON GCONF_KEY_PREFIX"/last_longitude" +#define GCONF_KEY_LAST_ALT GCONF_KEY_PREFIX"/last_altitude" +#define GCONF_KEY_LAST_SPEED GCONF_KEY_PREFIX"/last_speed" +#define GCONF_KEY_LAST_HEADING GCONF_KEY_PREFIX"/last_heading" +#define GCONF_KEY_LAST_TIME GCONF_KEY_PREFIX"/last_timestamp" +#define GCONF_KEY_CENTER_LAT GCONF_KEY_PREFIX"/center_latitude" +#define GCONF_KEY_CENTER_LON GCONF_KEY_PREFIX"/center_longitude" +#define GCONF_KEY_CENTER_ANGLE GCONF_KEY_PREFIX"/center_angle" +#define GCONF_KEY_ZOOM GCONF_KEY_PREFIX"/zoom" +#define GCONF_KEY_ROUTEDIR GCONF_KEY_PREFIX"/route_directory" +#define GCONF_KEY_TRACKFILE GCONF_KEY_PREFIX"/track_file" +#define GCONF_KEY_SHOWZOOMLEVEL GCONF_KEY_PREFIX"/show_zoomlevel" +#define GCONF_KEY_SHOWSCALE GCONF_KEY_PREFIX"/show_scale" +#define GCONF_KEY_SHOWCOMPROSE GCONF_KEY_PREFIX"/show_comprose" +#define GCONF_KEY_SHOWTRACKS GCONF_KEY_PREFIX"/show_tracks" +#define GCONF_KEY_SHOWROUTES GCONF_KEY_PREFIX"/show_routes" +#define GCONF_KEY_SHOWVELVEC GCONF_KEY_PREFIX"/show_velocity_vector" +#define GCONF_KEY_SHOWPOIS GCONF_KEY_PREFIX"/show_poi" +#define GCONF_KEY_ENABLE_GPS GCONF_KEY_PREFIX"/enable_gps" +#define GCONF_KEY_ROUTE_LOCATIONS GCONF_KEY_PREFIX"/route_locations" +#define GCONF_KEY_REPOSITORIES GCONF_KEY_PREFIX"/repositories" +#define GCONF_KEY_CURRREPO GCONF_KEY_PREFIX"/curr_repo" +#define GCONF_KEY_GPS_INFO GCONF_KEY_PREFIX"/gps_info" +#define GCONF_KEY_ROUTE_DL_URL GCONF_KEY_PREFIX"/route_dl_url" +#define GCONF_KEY_ROUTE_DL_RADIUS GCONF_KEY_PREFIX"/route_dl_radius" +#define GCONF_KEY_POI_DL_URL GCONF_KEY_PREFIX"/poi_dl_url" +#define GCONF_KEY_DEG_FORMAT GCONF_KEY_PREFIX"/deg_format" + + typedef struct _ScanInfo ScanInfo; struct _ScanInfo { GtkWidget *settings_dialog; @@ -182,6 +246,10 @@ settings_save() gconf_client_set_int(gconf_client, GCONF_KEY_DRAW_WIDTH, _draw_width, NULL); + /* Save Announce Flag. */ + gconf_client_set_bool(gconf_client, + GCONF_KEY_ENABLE_ANNOUNCE, _enable_announce, NULL); + /* Save Announce Advance Notice Ratio. */ gconf_client_set_int(gconf_client, GCONF_KEY_ANNOUNCE_NOTICE, _announce_notice_ratio, NULL); @@ -1044,6 +1112,7 @@ settings_dialog() static GtkWidget *num_ac_min_speed = NULL; static GtkWidget *num_announce_notice = NULL; static GtkWidget *chk_enable_voice = NULL; + static GtkWidget *chk_enable_announce = NULL; static GtkWidget *num_draw_width = NULL; static GtkWidget *cmb_units = NULL; static GtkWidget *cmb_degformat = NULL; @@ -1247,14 +1316,22 @@ settings_dialog() table = gtk_table_new(2, 3, FALSE), label = gtk_label_new(_("Announce"))); + /* Enable Waypoint Announcements. */ + gtk_table_attach(GTK_TABLE(table), + chk_enable_announce = gtk_check_button_new_with_label( + _("Enable Waypoint Announcements")), + 0, 2, 0, 1, GTK_FILL, 0, 2, 4); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk_enable_announce), + _enable_announce); + /* Announcement Advance Notice. */ gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Advance Notice")), - 0, 1, 0, 1, GTK_FILL, 0, 2, 4); + 0, 1, 1, 2, GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), num_announce_notice = hildon_controlbar_new(), - 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4); + 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4); hildon_controlbar_set_range( HILDON_CONTROLBAR(num_announce_notice), 1, 20); force_min_visible_bars(HILDON_CONTROLBAR(num_announce_notice), 1); @@ -1263,7 +1340,7 @@ settings_dialog() gtk_table_attach(GTK_TABLE(table), chk_enable_voice = gtk_check_button_new_with_label( _("Enable Voice Synthesis (requires flite)")), - 0, 2, 1, 2, GTK_FILL, 0, 2, 4); + 0, 2, 2, 3, GTK_FILL, 0, 2, 4); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk_enable_voice), _enable_voice); @@ -1649,6 +1726,9 @@ settings_dialog() _announce_notice_ratio = hildon_controlbar_get_value( HILDON_CONTROLBAR(num_announce_notice)); + _enable_announce = gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(chk_enable_announce)); + _enable_voice = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(chk_enable_voice)); @@ -1776,6 +1856,31 @@ settings_init() gchar *str; printf("%s()\n", __PRETTY_FUNCTION__); + /* Initialize some constants. */ + CUSTOM_KEY_GCONF[CUSTOM_KEY_UP] = GCONF_KEY_PREFIX"/key_up"; + CUSTOM_KEY_GCONF[CUSTOM_KEY_DOWN] = GCONF_KEY_PREFIX"/key_down"; + CUSTOM_KEY_GCONF[CUSTOM_KEY_LEFT] = GCONF_KEY_PREFIX"/key_left"; + CUSTOM_KEY_GCONF[CUSTOM_KEY_RIGHT] = GCONF_KEY_PREFIX"/key_right"; + CUSTOM_KEY_GCONF[CUSTOM_KEY_SELECT] = GCONF_KEY_PREFIX"/key_select"; + CUSTOM_KEY_GCONF[CUSTOM_KEY_INCREASE] = GCONF_KEY_PREFIX"/key_increase"; + CUSTOM_KEY_GCONF[CUSTOM_KEY_DECREASE] = GCONF_KEY_PREFIX"/key_decrease"; + CUSTOM_KEY_GCONF[CUSTOM_KEY_FULLSCREEN]= GCONF_KEY_PREFIX"/key_fullscreen"; + CUSTOM_KEY_GCONF[CUSTOM_KEY_ESC] = GCONF_KEY_PREFIX"/key_esc"; + + COLORABLE_GCONF[COLORABLE_MARK] = GCONF_KEY_PREFIX"/color_mark"; + COLORABLE_GCONF[COLORABLE_MARK_VELOCITY] + = GCONF_KEY_PREFIX"/color_mark_velocity"; + COLORABLE_GCONF[COLORABLE_MARK_OLD] = GCONF_KEY_PREFIX"/color_mark_old"; + COLORABLE_GCONF[COLORABLE_TRACK] = GCONF_KEY_PREFIX"/color_track"; + COLORABLE_GCONF[COLORABLE_TRACK_MARK] =GCONF_KEY_PREFIX"/color_track_mark"; + COLORABLE_GCONF[COLORABLE_TRACK_BREAK] + = GCONF_KEY_PREFIX"/color_track_break"; + COLORABLE_GCONF[COLORABLE_ROUTE] = GCONF_KEY_PREFIX"/color_route"; + COLORABLE_GCONF[COLORABLE_ROUTE_WAY] = GCONF_KEY_PREFIX"/color_route_way"; + COLORABLE_GCONF[COLORABLE_ROUTE_BREAK] + = GCONF_KEY_PREFIX"/color_route_break"; + COLORABLE_GCONF[COLORABLE_POI] = GCONF_KEY_PREFIX"/color_poi"; + if(!gconf_client) { popup_error(_window, _("Failed to initialize GConf. Quitting.")); @@ -1877,6 +1982,16 @@ settings_init() if(!_draw_width) _draw_width = 5; + /* Get Enable Announcements flag. Default is TRUE. */ + value = gconf_client_get(gconf_client, GCONF_KEY_ENABLE_ANNOUNCE, NULL); + if(value) + { + _enable_announce = gconf_value_get_bool(value); + gconf_value_free(value); + } + else + _enable_announce = TRUE; + /* Get Announce Advance Notice - Default is 30. */ value = gconf_client_get(gconf_client, GCONF_KEY_ANNOUNCE_NOTICE, NULL); if(value)