]> git.itanic.dy.fi Git - maemo-mapper/commitdiff
* Fixed crash when loading two track files as route files. (closes #117)
authorgnuite <gnuite@gmail.com>
Sun, 29 Oct 2006 01:53:17 +0000 (01:53 +0000)
committergnuite <gnuite@gmail.com>
Sun, 29 Oct 2006 01:53:17 +0000 (01:53 +0000)
 * Fixed crash when config is empty.
 * Fixed broken "Download-by-Route" functionality.

git-svn-id: svn+ssh://garage/var/lib/gforge/svnroot/maemo-mapper/trunk@46 6c538b50-5814-0410-93ad-8bdf4c0149d1

src/maemo-mapper.c

index 4d68f2fc0bb4ef4a110eb77f492f00576ffd3cda..416b4d214d9ac9f539c0869d2b84f81b069b7237 100644 (file)
 #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_RADIUS GCONF_KEY_PREFIX"/route_dl_radius"
+
 #define GCONF_KEY_DISCONNECT_ON_COVER "/system/osso/connectivity/IAP/disconnect_on_cover"
 
+#define CONFIG_DIR_NAME "~/.maemo-mapper/"
+#define CONFIG_FILE_ROUTE "route.gpx"
+#define CONFIG_FILE_TRACK "track.gpx"
 
 #define XML_DATE_FORMAT "%FT%T"
 
     } \
 }
 
+#define MACRO_TRACK_INCREMENT_TAIL(track) { \
+    if(++(track).tail == (track).cap) \
+        track_resize(&(track), (track).cap - (track).head + ARRAY_CHUNK_SIZE); \
+}
+
+#define MACRO_ROUTE_INCREMENT_TAIL(route) { \
+    if(++(route).tail == (route).cap) \
+        route_resize(&(route), (route).cap - (route).head + ARRAY_CHUNK_SIZE); \
+}
+
+#define MACRO_ROUTE_INCREMENT_WTAIL(route) { \
+    if(++(route).wtail == (route).wcap) \
+        route_wresize(&(route), \
+                (route).wcap - (route).whead + ARRAY_CHUNK_SIZE); \
+}
+
 #define TRACKS_MASK 0x00000001
 #define ROUTES_MASK 0x00000002
 
@@ -834,6 +855,7 @@ static CenterMode _center_mode = CENTER_LEAD;
 static gboolean _fullscreen = FALSE;
 static gboolean _enable_gps = FALSE;
 static gboolean _gps_info = FALSE;
+static guint _route_dl_radius = 4;
 static gint _show_tracks = 0;
 static gboolean _show_velvec = TRUE;
 static gboolean _auto_download = FALSE;
@@ -850,6 +872,8 @@ static GtkListStore *_loc_model;
 static UnitType _units = UNITS_KM;
 static EscapeKeyAction _escape_key = ESCAPE_KEY_TOGGLE_TRACKS;
 
+static gchar *_config_dir_uri;
+
 static GList *_repo_list = NULL;
 static RepoData *_curr_repo = NULL;
 
@@ -1013,4737 +1037,4953 @@ auto_route_dl_idle();
  * ABOVE: CALLBACK DECLARATIONS *********************************************
  ****************************************************************************/
 
+/**
+ * Pop up a modal dialog box with simple error information in it.
+ */
+static void
+popup_error(GtkWidget *window, const gchar *error)
+{
+    GtkWidget *dialog;
+    printf("%s(\"%s\")\n", __PRETTY_FUNCTION__, error);
 
+    dialog = hildon_note_new_information(GTK_WINDOW(window), error);
 
-/****************************************************************************
- * BELOW: ROUTINES **********************************************************
- ****************************************************************************/
+    gtk_dialog_run(GTK_DIALOG(dialog));
+    gtk_widget_destroy(dialog);
 
-static gboolean
-gps_display_details(void)
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
+
+static void
+track_resize(Track *track, guint size)
 {
-    gchar *buffer, strtime[15];
     printf("%s()\n", __PRETTY_FUNCTION__);
 
-    if(_gps.fix < 2)
+    if(track->head + size != track->cap)
     {
-        /* no fix no fun */
-        gtk_label_set_label(GTK_LABEL(_sdi_lat), " --- ");
-        gtk_label_set_label(GTK_LABEL(_sdi_lon), " --- ");
-        gtk_label_set_label(GTK_LABEL(_sdi_spd), " --- ");
-        gtk_label_set_label(GTK_LABEL(_sdi_alt), " --- ");
-        gtk_label_set_label(GTK_LABEL(_sdi_hea), " --- ");
-        gtk_label_set_label(GTK_LABEL(_sdi_tim), " --:--:-- ");
+        TrackPoint *old_head = track->head;
+        track->head = g_renew(TrackPoint, old_head, size);
+        track->cap = track->head + size;
+        if(track->head != old_head)
+            track->tail = track->head + (track->tail - old_head);
     }
-    else
-    {
-        gfloat speed = _gps.speed * UNITS_CONVERT[_units];
 
-        /* latitude */
-        gtk_label_set_label(GTK_LABEL(_sdi_lat), _gps.slatitude);
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
-        /* longitude */
-        gtk_label_set_label(GTK_LABEL(_sdi_lon), _gps.slongitude);
+static void
+route_resize(Route *route, guint size)
+{
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-        /* speed */
-        switch(_units)
+    if(route->head + size != route->cap)
+    {
+        Point *old_head = route->head;
+        WayPoint *curr;
+        route->head = g_renew(Point, old_head, size);
+        route->cap = route->head + size;
+        if(route->head != old_head)
         {
-            case UNITS_MI:
-                buffer = g_strdup_printf("%.1f mph", speed);
-                break;
-            case UNITS_NM:
-                buffer = g_strdup_printf("%.1f kn", speed);
-                break;
-            default:
-                buffer = g_strdup_printf("%.1f km/h", speed);
-                break;
-        }
-        gtk_label_set_label(GTK_LABEL(_sdi_spd), buffer);
-        g_free(buffer);
+            route->tail = route->head + (route->tail - old_head);
 
-        /* altitude */
-        switch(_units)
-        {
-            case UNITS_MI:
-            case UNITS_NM:
-                buffer = g_strdup_printf("%d ft",
-                        (guint)(_gps.altitude * 3.2808399f));
-                break;
-            default:
-                buffer = g_strdup_printf("%d m", _gps.altitude);
-                break;
+            /* Adjust all of the waypoints. */
+            for(curr = route->whead - 1; curr++ != route->wtail; )
+                curr->point = route->head + (curr->point - old_head);
         }
-        gtk_label_set_label(GTK_LABEL(_sdi_alt), buffer);
-        g_free(buffer);
-
-        /* heading */
-        buffer = g_strdup_printf("%0.0f\u00b0", _gps.heading);
-        gtk_label_set_label(GTK_LABEL(_sdi_hea), buffer);
-        g_free(buffer);
-
-        /* local time */
-        strftime(strtime, 15, "%X", &_gps.timeloc);
-        gtk_label_set_label(GTK_LABEL(_sdi_tim), strtime);
     }
 
-    /* Sat in view */
-    buffer = g_strdup_printf("%d", _gps.satinview);
-    gtk_label_set_label(GTK_LABEL(_sdi_vie), buffer);
-    g_free(buffer);
-
-    /* Sat in use */
-    buffer = g_strdup_printf("%d", _gps.satinuse);
-    gtk_label_set_label(GTK_LABEL(_sdi_use), buffer);
-    g_free(buffer);
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
-    /* fix */
-    switch(_gps.fix)
-    {
-        case 2:
-        case 3: buffer = g_strdup_printf("%dD fix", _gps.fix); break;
-        default: buffer = g_strdup_printf("nofix"); break;
-    }
-    gtk_label_set_label(GTK_LABEL(_sdi_fix), buffer);
-    g_free(buffer);
+static void
+route_wresize(Route *route, guint wsize)
+{
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    if(_gps.fix == 1)
-        buffer = g_strdup("none");
-    else
+    if(route->whead + wsize != route->wcap)
     {
-        switch (_gps.fixquality)
-        {
-            case 1 : buffer = g_strdup_printf(_("SPS")); break;
-            case 2 : buffer = g_strdup_printf(_("DGPS")); break;
-            case 3 : buffer = g_strdup_printf(_("PPS")); break;
-            case 4 : buffer = g_strdup_printf(_("Real Time Kinematic")); break;
-            case 5 : buffer = g_strdup_printf(_("Float RTK")); break;
-            case 6 : buffer = g_strdup_printf(_("Estimated")); break;
-            case 7 : buffer = g_strdup_printf(_("Manual)")); break;
-            case 8 : buffer = g_strdup_printf(_("Simulation")); break;
-            default : buffer = g_strdup_printf(_("none")); break;
-        }
+        WayPoint *old_whead = route->whead;
+        route->whead = g_renew(WayPoint, old_whead, wsize);
+        route->wtail = route->whead + (route->wtail - old_whead);
+        route->wcap = route->whead + wsize;
     }
-    gtk_label_set_label(GTK_LABEL(_sdi_fqu), buffer);
-    g_free(buffer);
 
-    /* max speed */
-    {
-        gfloat maxspeed = _gps.maxspeed * UNITS_CONVERT[_units];
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
-        /* speed */
-        switch(_units)
-        {
-            case UNITS_MI:
-                buffer = g_strdup_printf("%.1f mph", maxspeed);
-                break;
-            case UNITS_NM:
-                buffer = g_strdup_printf("%.1f kn", maxspeed);
-                break;
-            default:
-                buffer = g_strdup_printf("%.1f km/h", maxspeed);
-                break;
-        }
-        gtk_label_set_label(GTK_LABEL(_sdi_msp), buffer);
-        g_free(buffer);
-    }
 
-    /* refresh sat panel */
-    gtk_widget_queue_draw_area(GTK_WIDGET(_sat_details_panel),
-        0, 0,
-        _sat_details_panel->allocation.width,
-        _sat_details_panel->allocation.height);
+/****************************************************************************
+ * BELOW: FILE-HANDLING ROUTINES *********************************************
+ ****************************************************************************/
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-    return TRUE;
+#define WRITE_STRING(string) { \
+    GnomeVFSResult vfs_result; \
+    GnomeVFSFileSize size; \
+    if(GNOME_VFS_OK != (vfs_result = gnome_vfs_write( \
+                    handle, (string), strlen((string)), &size))) \
+    { \
+        gchar buffer[1024]; \
+        sprintf(buffer, "%s:\n%s\n%s", _("Error while writing to file"), \
+                        _("File is incomplete."), \
+                gnome_vfs_result_to_string(vfs_result)); \
+        popup_error(_window, buffer); \
+        return FALSE; \
+    } \
 }
 
-static void
-gps_display_data(void)
+static gboolean
+write_track_gpx(GnomeVFSHandle *handle)
 {
-    gchar *buffer, strtime[15];
+    TrackPoint *curr;
+    gboolean trkseg_break = FALSE;
     printf("%s()\n", __PRETTY_FUNCTION__);
 
-    if(_gps.fix < 2)
-    {
-        /* no fix no fun */
-        gtk_label_set_label(GTK_LABEL(_text_lat), " --- ");
-        gtk_label_set_label(GTK_LABEL(_text_lon), " --- ");
-        gtk_label_set_label(GTK_LABEL(_text_speed), " --- ");
-        gtk_label_set_label(GTK_LABEL(_text_alt), " --- ");
-        gtk_label_set_label(GTK_LABEL(_text_time), " --:--:-- ");
-    }
-    else
-    {
-        gfloat speed = _gps.speed * UNITS_CONVERT[_units];
-
-        /* latitude */
-        gtk_label_set_label(GTK_LABEL(_text_lat), _gps.slatitude);
-
-        /* longitude */
-        gtk_label_set_label(GTK_LABEL(_text_lon), _gps.slongitude);
+    /* Find first non-zero point. */
+    for(curr = _track.head-1; curr++ != _track.tail; )
+        if(curr->point.unity)
+            break;
 
-        /* speed */
-        switch(_units)
-        {
-            case UNITS_MI:
-                buffer = g_strdup_printf("Spd: %.1f mph", speed);
-                break;
-            case UNITS_NM:
-                buffer = g_strdup_printf("Spd: %.1f kn", speed);
-                break;
-            default:
-                buffer = g_strdup_printf("Spd: %.1f km/h", speed);
-                break;
-        }
-        gtk_label_set_label(GTK_LABEL(_text_speed), buffer);
-        g_free(buffer);
+    /* Write the header. */
+    WRITE_STRING(XML_TRKSEG_HEADER);
 
-        /* altitude */
-        switch(_units)
+    /* Curr points to first non-zero point. */
+    for(curr--; curr++ != _track.tail; )
+    {
+        gfloat lat, lon;
+        if(curr->point.unity)
         {
-            case UNITS_MI:
-            case UNITS_NM:
-                buffer = g_strdup_printf("Alt: %d ft",
-                        (guint)(_gps.altitude * 3.2808399f));
-                break;
-            default:
-                buffer = g_strdup_printf("Alt: %d m", _gps.altitude);
-        }
-        gtk_label_set_label(GTK_LABEL(_text_alt), buffer);
-        g_free(buffer);
+            gchar buffer[80];
+            gchar strlat[80], strlon[80];
+            if(trkseg_break)
+            {
+                /* First trkpt of the segment - write trkseg header. */
+                WRITE_STRING("    </trkseg>\n"
+                /* Write trkseg header. */
+                             "    <trkseg>\n");
+                trkseg_break = FALSE;
+            }
+            unit2latlon(curr->point.unitx, curr->point.unity, lat, lon);
+            g_ascii_formatd(strlat, 80, "%.06f", lat);
+            g_ascii_formatd(strlon, 80, "%.06f", lon);
+            sprintf(buffer, "      <trkpt lat=\"%s\" lon=\"%s\"",
+                    strlat, strlon);
+            WRITE_STRING(buffer);
 
-        /* local time */
-        strftime(strtime, 15, "%X", &_gps.timeloc);
-        gtk_label_set_label(GTK_LABEL(_text_time), strtime);
+            /* write the time */
+            if(curr->time)
+            {
+                WRITE_STRING(">\n        <time>");
+                {
+                    struct tm time;
+                    localtime_r(&curr->time, &time);
+                    strftime(buffer, 80, XML_DATE_FORMAT, &time);
+                    WRITE_STRING(buffer);
+                    WRITE_STRING(XML_TZONE);
+                }
+                WRITE_STRING("</time>\n"
+                         "      </trkpt>\n");
+            }
+            else
+                WRITE_STRING("/>\n");
+        }
+        else
+            trkseg_break = TRUE;
     }
 
-    /* refresh sat panel */
-    gtk_widget_queue_draw_area(GTK_WIDGET(_sat_panel),
-        0, 0,
-        _sat_panel->allocation.width,
-        _sat_panel->allocation.height);
-
-    /* refresh heading panel*/
-    gtk_widget_queue_draw_area(GTK_WIDGET(_heading_panel),
-        0, 0,
-        _heading_panel->allocation.width,
-        _heading_panel->allocation.height);
+    /* Write the footer. */
+    WRITE_STRING(XML_TRKSEG_FOOTER);
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-    return;
+    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
+    return TRUE;
 }
 
-static void
-gps_hide_text(void)
+static gboolean
+write_route_gpx(GnomeVFSHandle *handle)
 {
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    Point *curr;
+    WayPoint *wcurr;
+    gboolean trkseg_break = FALSE;
 
-    /* Clear gps data */
-    _gps.fix = 1;
-    _gps.satinuse = 0;
-    _gps.satinview = 0;
+    /* Find first non-zero point. */
+    if(_route.head)
+        for(curr = _route.head-1, wcurr = _route.whead; curr++ != _route.tail; )
+        {
+            if(curr->unity)
+                break;
+            else if(wcurr && curr == wcurr->point)
+                wcurr++;
+        }
 
-    if(_gps_info)
-        gps_display_data();
+    /* Write the header. */
+    WRITE_STRING(XML_TRKSEG_HEADER);
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+    /* Curr points to first non-zero point. */
+    if(_route.head)
+        for(curr--; curr++ != _route.tail; )
+        {
+            gfloat lat, lon;
+            if(curr->unity)
+            {
+                gchar buffer[80];
+                gchar strlat[80], strlon[80];
+                if(trkseg_break)
+                {
+                    /* First trkpt of the segment - write trkseg header. */
+                    WRITE_STRING("    </trkseg>\n"
+                                 "    <trkseg>\n");
+                    trkseg_break = FALSE;
+                }
+                unit2latlon(curr->unitx, curr->unity, lat, lon);
+                g_ascii_formatd(strlat, 80, "%.06f", lat);
+                g_ascii_formatd(strlon, 80, "%.06f", lon);
+                sprintf(buffer, "      <trkpt lat=\"%s\" lon=\"%s\"",
+                        strlat, strlon);
+                if(wcurr && curr == wcurr->point)
+                    sprintf(buffer + strlen(buffer),
+                            "><desc>%s</desc></trkpt>\n", wcurr++->desc);
+                else
+                    strcat(buffer, "/>\n");
+                WRITE_STRING(buffer);
+            }
+            else
+                trkseg_break = TRUE;
+        }
+
+    /* Write the footer. */
+    WRITE_STRING(XML_TRKSEG_FOOTER);
+
+    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
+    return TRUE;
 }
 
+/**
+ * Handle a start tag in the parsing of a GPX file.
+ */
+#define MACRO_SET_UNKNOWN() { \
+    data->prev_state = data->state; \
+    data->state = UNKNOWN; \
+    data->unknown_depth = 1; \
+}
 static void
-gps_show_info(void)
+gpx_start_element(SaxData *data, const xmlChar *name, const xmlChar **attrs)
 {
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    vprintf("%s(%s)\n", __PRETTY_FUNCTION__, name);
 
-    if(_gps_info && _enable_gps)
-        gtk_widget_show_all(GTK_WIDGET(_gps_widget));
-    else
+    switch(data->state)
     {
-        gps_hide_text();
-        gtk_widget_hide_all(GTK_WIDGET(_gps_widget));
+        case ERROR:
+            break;
+        case START:
+            if(!strcmp((gchar*)name, "gpx"))
+                data->state = INSIDE_GPX;
+            else
+                MACRO_SET_UNKNOWN();
+            break;
+        case INSIDE_GPX:
+            if(!strcmp((gchar*)name, "trk"))
+                data->state = INSIDE_PATH;
+            else
+                MACRO_SET_UNKNOWN();
+            break;
+        case INSIDE_PATH:
+            if(!strcmp((gchar*)name, "trkseg"))
+            {
+                data->state = INSIDE_PATH_SEGMENT;
+                data->at_least_one_trkpt = FALSE;
+            }
+            else
+                MACRO_SET_UNKNOWN();
+            break;
+        case INSIDE_PATH_SEGMENT:
+            if(!strcmp((gchar*)name, "trkpt"))
+            {
+                const xmlChar **curr_attr;
+                gchar *error_check;
+                gfloat lat = 0.f, lon = 0.f;
+                gboolean has_lat, has_lon;
+                has_lat = FALSE;
+                has_lon = FALSE;
+                for(curr_attr = attrs; *curr_attr != NULL; )
+                {
+                    const gchar *attr_name = *curr_attr++;
+                    const gchar *attr_val = *curr_attr++;
+                    if(!strcmp(attr_name, "lat"))
+                    {
+                        lat = g_ascii_strtod(attr_val, &error_check);
+                        if(error_check != attr_val)
+                            has_lat = TRUE;
+                    }
+                    else if(!strcmp(attr_name, "lon"))
+                    {
+                        lon = g_ascii_strtod(attr_val, &error_check);
+                        if(error_check != attr_val)
+                            has_lon = TRUE;
+                    }
+                }
+                if(has_lat && has_lon)
+                {
+                    if(data->path.path_type == TRACK)
+                    {
+                        MACRO_TRACK_INCREMENT_TAIL(data->path.path.track);
+                        latlon2unit(lat, lon,
+                                data->path.path.track.tail->point.unitx,
+                                data->path.path.track.tail->point.unity);
+                        data->path.path.track.tail->time = 0;
+                    }
+                    else
+                    {
+                        MACRO_ROUTE_INCREMENT_TAIL(data->path.path.route);
+                        latlon2unit(lat, lon,
+                                data->path.path.route.tail->unitx,
+                                data->path.path.route.tail->unity);
+                    }
+                    data->state = INSIDE_PATH_POINT;
+                }
+                else
+                    data->state = ERROR;
+            }
+            else
+                MACRO_SET_UNKNOWN();
+            break;
+        case INSIDE_PATH_POINT:
+            /* only parse time for tracks */
+            if(data->path.path_type == TRACK
+                    && !strcmp((gchar*)name, "time"))
+                data->state = INSIDE_PATH_POINT_TIME;
+
+            /* only parse description for routes */
+            else if(data->path.path_type == ROUTE
+                    && !strcmp((gchar*)name, "desc"))
+                data->state = INSIDE_PATH_POINT_DESC;
+
+            else
+                MACRO_SET_UNKNOWN();
+            break;
+        case UNKNOWN:
+            data->unknown_depth++;
+            break;
+        default:
+            ;
     }
 
     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
 }
 
+/**
+ * Handle an end tag in the parsing of a GPX file.
+ */
 static void
-draw_sat_info(GtkWidget *widget, guint x0, guint y0,
-        guint width, guint height, gboolean showsnr)
+gpx_end_element(SaxData *data, const xmlChar *name)
 {
-    PangoContext *context = NULL;
-    PangoLayout *layout = NULL;
-    PangoFontDescription *fontdesc = NULL;
-    GdkColor color;
-    GdkGC *gc1, *gc2, *gc;
-    guint step, i, j, snr_height, bymargin, xoffset, yoffset;
-    guint x, y, x1, y1;
-    gchar *tmp = NULL;
-
-    xoffset = x0;
-    yoffset = y0;
-    /* Bootom margin - 12% */
-    bymargin = height * 0.88f;
-
-    /* Bottom line */
-    gdk_draw_line(widget->window,
-        widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
-        xoffset + 5, yoffset + bymargin,
-        xoffset + width - 10 - 2, yoffset + bymargin);
-    gdk_draw_line(widget->window,
-        widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
-        xoffset + 5, yoffset + bymargin - 1,
-        xoffset + width - 10 - 2, yoffset + bymargin - 1);
-
-    context = gtk_widget_get_pango_context(widget);
-    layout = pango_layout_new(context);
-    fontdesc =  pango_font_description_new();
-
-    pango_font_description_set_family(fontdesc,"Sans Serif");
+    vprintf("%s(%s)\n", __PRETTY_FUNCTION__, name);
 
-    if(_gps.satinview > 0 )
+    switch(data->state)
     {
-        pango_font_description_set_size(fontdesc, 8*PANGO_SCALE);
-
-        pango_layout_set_font_description (layout, fontdesc);
-        pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
-
-        /* Left margin - 5pix, Right margin - 5pix */
-        step = (width - 10) / _gps.satinview;
-
-        color.red = 0;
-        color.green = 0;
-        color.blue = 0;
-        gc1 = gdk_gc_new (widget->window);
-        gdk_gc_set_rgb_fg_color (gc1, &color);
-
-        color.red = 0;
-        color.green = 0;
-        color.blue = 0xffff;
-        gc2 = gdk_gc_new (widget->window);
-        gdk_gc_set_rgb_fg_color (gc2, &color);
-
-        for(i = 0; i < _gps.satinview; i++)
-        {
-            /* Sat used or not */
-            gc = gc1;
-            for(j = 0; j < _gps.satinuse ; j++)
+        case ERROR:
+            break;
+        case START:
+            data->state = ERROR;
+            break;
+        case INSIDE_GPX:
+            if(!strcmp((gchar*)name, "gpx"))
+                data->state = FINISH;
+            else
+                data->state = ERROR;
+            break;
+        case INSIDE_PATH:
+            if(!strcmp((gchar*)name, "trk"))
+                data->state = INSIDE_GPX;
+            else
+                data->state = ERROR;
+            break;
+        case INSIDE_PATH_SEGMENT:
+            if(!strcmp((gchar*)name, "trkseg"))
             {
-                if(_gps.satforfix[j] == _gps_sat[i].prn)
+                if(data->at_least_one_trkpt)
                 {
-                    gc = gc2;
-                    break;
+                    if(data->path.path_type == TRACK)
+                    {
+                        MACRO_TRACK_INCREMENT_TAIL(data->path.path.track);
+                        *data->path.path.track.tail = _track_null;
+                    }
+                    else
+                    {
+                        MACRO_ROUTE_INCREMENT_TAIL(data->path.path.route);
+                        *data->path.path.route.tail = _pos_null;
+                    }
                 }
+                data->state = INSIDE_PATH;
+            }
+            else
+                data->state = ERROR;
+            break;
+        case INSIDE_PATH_POINT:
+            if(!strcmp((gchar*)name, "trkpt"))
+            {
+                data->state = INSIDE_PATH_SEGMENT;
+                data->at_least_one_trkpt = TRUE;
             }
+            else
+                data->state = ERROR;
+            break;
+        case INSIDE_PATH_POINT_TIME:
+            /* only parse time for tracks */
+            if(!strcmp((gchar*)name, "time"))
+            {
+                struct tm time;
+                gchar *ptr;
 
-            x = 5 + i * step;
-            snr_height = _gps_sat[i].snr * height * 0.78f / 100;
-            y = height * 0.1f + (height * 0.78f - snr_height);
+                if(NULL == (ptr = strptime(data->chars->str,
+                            XML_DATE_FORMAT, &time)))
+                    /* Failed to parse dateTime format. */
+                    data->state = ERROR;
+                else
+                {
+                    /* Parse was successful. Now we have to parse timezone.
+                     * From here on, if there is an error, I just assume local
+                     * timezone.  Yes, this is not proper XML, but I don't
+                     * care. */
+                    gchar *error_check;
 
-            /* draw sat rectangle... */
-            gdk_draw_rectangle(widget->window,
-                    gc,
-                    TRUE,
-                    xoffset + x,
-                    yoffset + y,
-                    step - 2,
-                    snr_height);
+                    /* First, set time in "local" time zone. */
+                    data->path.path.track.tail->time = (mktime(&time));
 
-            if(showsnr && _gps_sat[i].snr > 0)
+                    /* Now, skip inconsequential characters */
+                    while(*ptr && *ptr != 'Z' && *ptr != '-' && *ptr != '+')
+                        ptr++;
+
+                    /* Check if we ran to the end of the string. */
+                    if(*ptr)
+                    {
+                        /* Next character is either 'Z', '-', or '+' */
+                        if(*ptr == 'Z')
+                            /* Zulu (UTC) time. Undo the local time zone's
+                             * offset. */
+                            data->path.path.track.tail->time += time.tm_gmtoff;
+                        else
+                        {
+                            /* Not Zulu (UTC). Must parse hours and minutes. */
+                            gint offhours = strtol(ptr, &error_check, 10);
+                            if(error_check != ptr
+                                    && *(ptr = error_check) == ':')
+                            {
+                                /* Parse of hours worked. Check minutes. */
+                                gint offmins = strtol(ptr + 1,
+                                        &error_check, 10);
+                                if(error_check != (ptr + 1))
+                                {
+                                    /* Parse of minutes worked. Calculate. */
+                                    data->path.path.track.tail->time
+                                        += (time.tm_gmtoff
+                                                - (offhours * 60 * 60
+                                                    + offmins * 60));
+                                }
+                            }
+                        }
+                    }
+                    /* Successfully parsed dateTime. */
+                    data->state = INSIDE_PATH_POINT;
+                }
+
+                g_string_free(data->chars, TRUE);
+                data->chars = g_string_new("");
+            }
+            else
+                data->state = ERROR;
+            break;
+        case INSIDE_PATH_POINT_DESC:
+            /* only parse description for routes */
+            if(!strcmp((gchar*)name, "desc"))
             {
-                /* ...snr.. */
-                tmp = g_strdup_printf("%02d", _gps_sat[i].snr);
-                pango_layout_set_text(layout, tmp, 2);
-                pango_layout_get_pixel_size(layout, &x1, &y1);
-                gdk_draw_layout(widget->window,
-                    widget->style->fg_gc[GTK_STATE_NORMAL],
-                    xoffset + x + ((step - 2) - x1)/2,
-                    yoffset + y - 15,
-                    layout);
-                g_free(tmp);
+                MACRO_ROUTE_INCREMENT_WTAIL(data->path.path.route);
+                data->path.path.route.wtail->point = data->path.path.route.tail;
+                data->path.path.route.wtail->desc
+                    = g_string_free(data->chars, FALSE);
+                data->chars = g_string_new("");
+                data->state = INSIDE_PATH_POINT;
             }
-
-            /* ...and sat number */
-            tmp = g_strdup_printf("%02d", _gps_sat[i].prn);
-            pango_layout_set_text(layout, tmp, 2);
-            pango_layout_get_pixel_size(layout, &x1, &y1);
-            gdk_draw_layout(widget->window,
-                widget->style->fg_gc[GTK_STATE_NORMAL],
-                xoffset + x + ((step - 2) - x1)/2 ,
-                yoffset + bymargin + 1,
-                layout);
-            g_free(tmp);
-        }
-        g_object_unref (gc1);
-        g_object_unref (gc2);
+            else
+                data->state = ERROR;
+            break;
+        case UNKNOWN:
+            if(!--data->unknown_depth)
+                data->state = data->prev_state;
+            else
+                data->state = ERROR;
+            break;
+        default:
+            ;
     }
 
-    pango_font_description_free (fontdesc);
-    g_object_unref (layout);
-
-    return;
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
 }
 
+/**
+ * Handle char data in the parsing of a GPX file.
+ */
 static void
-draw_sat_details(GtkWidget *widget, guint x0, guint y0,
-        guint width, guint height)
+gpx_chars(SaxData *data, const xmlChar *ch, int len)
 {
-    guint i, j, x, y, size, halfsize, xoffset, yoffset;
-    guint x1, y1;
-    gfloat tmp;
-    GdkColor color;
-    GdkGC *gc1, *gc2, *gc3, *gc;
-    PangoContext *context = NULL;
-    PangoLayout *layout = NULL;
-    PangoFontDescription *fontdesc = NULL;
-    gchar *buffer = NULL;
+    guint i;
+    vprintf("%s()\n", __PRETTY_FUNCTION__);
 
-    size = MIN(width, height);
-    halfsize = size/2;
-    if(width > height)
-    {
-        xoffset = x0 + (width - height - 10) / 2;
-        yoffset = y0 + 5;
-    }
-    else
+    switch(data->state)
     {
-        xoffset = x0 + 5;
-        yoffset = y0 + (height - width - 10) / 2;
+        case ERROR:
+        case UNKNOWN:
+            break;
+        case INSIDE_PATH_POINT_TIME:
+        case INSIDE_PATH_POINT_DESC:
+            for(i = 0; i < len; i++)
+                data->chars = g_string_append_c(data->chars, ch[i]);
+            vprintf("%s\n", data->chars->str);
+            break;
+        default:
+            break;
     }
 
-    context = gtk_widget_get_pango_context(widget);
-    layout = pango_layout_new(context);
-    fontdesc =  pango_font_description_new();
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
-    pango_font_description_set_family(fontdesc,"Sans Serif");
-    pango_font_description_set_size(fontdesc, 10*PANGO_SCALE);
-    pango_layout_set_font_description (layout, fontdesc);
-    pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
+/**
+ * Handle an entity in the parsing of a GPX file.  We don't do anything
+ * special here.
+ */
+static xmlEntityPtr
+gpx_get_entity(SaxData *data, const xmlChar *name)
+{
+    vprintf("%s()\n", __PRETTY_FUNCTION__);
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+    return xmlGetPredefinedEntity(name);
+}
 
-    /* 90 */
-    gdk_draw_arc(widget->window,
-            widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
-            FALSE,
-            xoffset + 2, yoffset + 2, size - 4, size - 4,
-            0, 64 * 360);
+/**
+ * Handle an error in the parsing of a GPX file.
+ */
+static void
+gpx_error(SaxData *data, const gchar *msg, ...)
+{
+    vprintf("%s()\n", __PRETTY_FUNCTION__);
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+    data->state = ERROR;
+}
 
-    /* 60 */
-    gdk_draw_arc(widget->window,
-            widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
-            FALSE,
-            xoffset + size/6, yoffset + size/6,
-            size/6*4, size/6*4,
-            0, 64 * 360);
+/**
+ * Parse the given character buffer of the given size, replacing the given
+ * Track's pointers with pointers to new arrays depending on the given
+ * policy, adding extra_bins slots in the arrays for new data.
+ *
+ * policy_old should be negative to indicate that the existing data should
+ * be prepended to the new GPX data, positive to indicate the opposite, and
+ * zero to indicate that we should throw away the old data.
+ *
+ * When importing tracks, we *prepend* the GPX data and provide extra_bins.
+ * When importing routes, we *append* in the case of regular routes, and we
+ * *replace* in the case of automatic routing.  Routes get no extra bins.
+ */
+static gboolean
+parse_track_gpx(gchar *buffer, gint size, gint policy_old)
+{
+    SaxData data;
+    xmlSAXHandler sax_handler;
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    /* 30 */
-    gdk_draw_arc(widget->window,
-            widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
-            FALSE,
-            xoffset + size/6*2, yoffset + size/6*2,
-            size/6*2, size/6*2,
-            0, 64 * 360);
+    data.path.path_type = TRACK;
+    MACRO_INIT_TRACK(data.path.path.track);
+    data.state = START;
+    data.chars = g_string_new("");
 
-    guint line[12] = {0,30,60,90,120,150,180,210,240,270,300,330};
+    memset(&sax_handler, 0, sizeof(sax_handler));
+    sax_handler.characters = (charactersSAXFunc)gpx_chars;
+    sax_handler.startElement = (startElementSAXFunc)gpx_start_element;
+    sax_handler.endElement = (endElementSAXFunc)gpx_end_element;
+    sax_handler.entityDecl = (entityDeclSAXFunc)gpx_get_entity;
+    sax_handler.warning = (warningSAXFunc)gpx_error;
+    sax_handler.error = (errorSAXFunc)gpx_error;
+    sax_handler.fatalError = (fatalErrorSAXFunc)gpx_error;
 
-    for(i = 0; i < 6; i++)
+    xmlSAXUserParseMemory(&sax_handler, &data, buffer, size);
+    g_string_free(data.chars, TRUE);
+
+    if(data.state != FINISH)
     {
-        /* line */
-        tmp = (line[i] * (1.f / 180.f)) * PI;
-        gdk_draw_line(widget->window,
-            widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
-            xoffset + halfsize + (halfsize -2) * sinf(tmp),
-            yoffset + halfsize - (halfsize -2) * cosf(tmp),
-            xoffset + halfsize - (halfsize -2) * sinf(tmp),
-            yoffset + halfsize + (halfsize -2) * cosf(tmp));
+        vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
+        return FALSE;
     }
 
-    for(i = 0; i < 12; i++)
+    /* Successful parsing - replace given Track structure. */
+    if(policy_old && _track.head)
     {
-        tmp = (line[i] * (1.f / 180.f)) * PI;
-        /* azimuth */
-        if(line[i] == 0)
-            buffer = g_strdup_printf("N");
-        else
-            buffer = g_strdup_printf("%d\u00b0", line[i]);
-        pango_layout_set_text(layout, buffer, strlen(buffer));
-        pango_layout_get_pixel_size(layout, &x, &y);
-        gdk_draw_layout(widget->window,
-            widget->style->fg_gc[GTK_STATE_NORMAL],
-            (xoffset + halfsize + (halfsize - size/12) * sinf(tmp)) - x/2,
-            (yoffset + halfsize - (halfsize - size/12) * cosf(tmp)) - y/2,
-            layout);
-        g_free(buffer);
-    }
+        TrackPoint *src_first;
+        Track *src, *dest;
 
-    /* elevation 30 */
-    tmp = (30 * (1.f / 180.f)) * PI;
-    buffer = g_strdup_printf("30\u00b0");
-    pango_layout_set_text(layout, buffer, strlen(buffer));
-    pango_layout_get_pixel_size(layout, &x, &y);
-    gdk_draw_layout(widget->window,
-        widget->style->fg_gc[GTK_STATE_NORMAL],
-        (xoffset + halfsize + size/6*2 * sinf(tmp)) - x/2,
-        (yoffset + halfsize - size/6*2 * cosf(tmp)) - y/2,
-        layout);
-    g_free(buffer);
+        if(policy_old > 0)
+        {
+            /* Append to current track. */
+            src = &data.path.path.track;
+            dest = &_track;
+        }
+        else
+        {
+            /* Prepend to current track. */
+            src = &_track;
+            dest = &data.path.path.track;
+        }
 
-    /* elevation 60 */
-    tmp = (30 * (1.f / 180.f)) * PI;
-    buffer = g_strdup_printf("60\u00b0");
-    pango_layout_set_text(layout, buffer, strlen(buffer));
-    pango_layout_get_pixel_size(layout, &x, &y);
-    gdk_draw_layout(widget->window,
-        widget->style->fg_gc[GTK_STATE_NORMAL],
-        (xoffset + halfsize + size/6 * sinf(tmp)) - x/2,
-        (yoffset + halfsize - size/6 * cosf(tmp)) - y/2,
-        layout);
-    g_free(buffer);
+        /* Find src_first non-zero point. */
+        for(src_first = src->head - 1; src_first++ != src->tail; )
+            if(src_first->point.unity)
+                break;
 
-    color.red = 0;
-    color.green = 0;
-    color.blue = 0;
-    gc1 = gdk_gc_new (widget->window);
-    gdk_gc_set_rgb_fg_color (gc1, &color);
+        /* Append track points from src to dest. */
+        if(src->tail >= src_first)
+        {
+            guint num_dest_points = dest->tail - dest->head + 1;
+            guint num_src_points = src->tail - src_first + 1;
 
-    color.red = 0;
-    color.green = 0;
-    color.blue = 0xffff;
-    gc2 = gdk_gc_new (widget->window);
-    gdk_gc_set_rgb_fg_color (gc2, &color);
+            /* Adjust dest->tail to be able to fit src track data
+             * plus room for more track data. */
+            track_resize(dest,
+                    num_dest_points + num_src_points + ARRAY_CHUNK_SIZE);
 
-    color.red = 0xffff;
-    color.green = 0xffff;
-    color.blue = 0xffff;
-    gc3 = gdk_gc_new (widget->window);
-    gdk_gc_set_rgb_fg_color (gc3, &color);
+            memcpy(dest->tail + 1, src_first,
+                    num_src_points * sizeof(TrackPoint));
 
-    for(i = 0; i < _gps.satinview; i++)
-    {
-        /* Sat used or not */
-        gc = gc1;
-        for(j = 0; j < _gps.satinuse ; j++)
-        {
-            if(_gps.satforfix[j] == _gps_sat[i].prn)
-            {
-                gc = gc2;
-                break;
-            }
+            dest->tail += num_src_points;
         }
 
-        tmp = (_gps_sat[i].azimuth * (1.f / 180.f)) * PI;
-        x = xoffset + halfsize
-            + (90 - _gps_sat[i].elevation)*halfsize/90 * sinf(tmp);
-        y = yoffset + halfsize
-            - (90 - _gps_sat[i].elevation)*halfsize/90 * cosf(tmp);
-
-        gdk_draw_arc (widget->window,
-            gc, TRUE,
-            x - 10, y - 10, 20, 20,
-            0, 64 * 360);
-
-        buffer = g_strdup_printf("%02d", _gps_sat[i].prn);
-        pango_layout_set_text(layout, buffer, strlen(buffer));
-        pango_layout_get_pixel_size(layout, &x1, &y1);
-        gdk_draw_layout(widget->window,
-            gc3,
-            x - x1/2,
-            y - y1/2,
-            layout);
-        g_free(buffer);
+        MACRO_CLEAR_TRACK(*src);
+        if(policy_old < 0)
+            _track = *dest;
+    }
+    else
+    {
+        MACRO_CLEAR_TRACK(_track);
+        /* Overwrite with data.track. */
+        _track = data.path.path.track;
+        track_resize(&_track,
+                _track.tail - _track.head + 1 + ARRAY_CHUNK_SIZE);
     }
-    g_object_unref (gc1);
-    g_object_unref (gc2);
-    g_object_unref (gc3);
-
-    pango_font_description_free (fontdesc);
-    g_object_unref (layout);
 
-    return;
+    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
+    return TRUE;
 }
 
-
 static gboolean
-sat_details_panel_expose(GtkWidget *widget, GdkEventExpose *event)
+parse_route_gpx(gchar *buffer, gint size, gint policy_old)
 {
-    guint width, height, x, y;
-    PangoContext *context = NULL;
-    PangoLayout *layout = NULL;
-    PangoFontDescription *fontdesc = NULL;
-    gchar *buffer = NULL;
+    SaxData data;
+    xmlSAXHandler sax_handler;
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    width = widget->allocation.width;
-    height = widget->allocation.height * 0.9;
+    data.path.path_type = ROUTE;
+    MACRO_INIT_ROUTE(data.path.path.route);
+    data.state = START;
+    data.chars = g_string_new("");
 
-    draw_sat_info(widget, 0, 0, width/2, height, TRUE);
-    draw_sat_details(widget, width/2, 0, width/2, height);
+    memset(&sax_handler, 0, sizeof(sax_handler));
+    sax_handler.characters = (charactersSAXFunc)gpx_chars;
+    sax_handler.startElement = (startElementSAXFunc)gpx_start_element;
+    sax_handler.endElement = (endElementSAXFunc)gpx_end_element;
+    sax_handler.entityDecl = (entityDeclSAXFunc)gpx_get_entity;
+    sax_handler.warning = (warningSAXFunc)gpx_error;
+    sax_handler.error = (errorSAXFunc)gpx_error;
+    sax_handler.fatalError = (fatalErrorSAXFunc)gpx_error;
 
-    context = gtk_widget_get_pango_context(widget);
-    layout = pango_layout_new(context);
-    fontdesc =  pango_font_description_new();
+    xmlSAXUserParseMemory(&sax_handler, &data, buffer, size);
+    g_string_free(data.chars, TRUE);
 
-    pango_font_description_set_family(fontdesc,"Sans Serif");
-    pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
-    pango_font_description_set_size(fontdesc, 14*PANGO_SCALE);
-    pango_layout_set_font_description (layout, fontdesc);
+    if(data.state != FINISH)
+    {
+        printf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
+        return FALSE;
+    }
 
-    buffer = g_strdup_printf(
-        _("Satellites in view: %d; in use: %d"),
-        _gps.satinview,
-        _gps.satinuse);
-    pango_layout_set_text(layout, buffer, strlen(buffer));
-    pango_layout_get_pixel_size(layout, &x, &y);
-    gdk_draw_layout(widget->window,
-        widget->style->fg_gc[GTK_STATE_NORMAL],
-        10,
-        height*0.9 + 10,
-        layout);
-    g_free(buffer);
-
-    buffer = g_strdup_printf(_("HDOP: %.01f"), _gps.hdop);
-    pango_layout_set_text(layout, buffer, strlen(buffer));
-    pango_layout_get_pixel_size(layout, &x, &y);
-    gdk_draw_layout(widget->window,
-        widget->style->fg_gc[GTK_STATE_NORMAL],
-        (width/8) - x/2,
-        (height/6) - y/2,
-        layout);
-    g_free(buffer);
-    buffer = g_strdup_printf(_("PDOP: %.01f"), _gps.pdop);
-    pango_layout_set_text(layout, buffer, strlen(buffer));
-    pango_layout_get_pixel_size(layout, &x, &y);
-    gdk_draw_layout(widget->window,
-        widget->style->fg_gc[GTK_STATE_NORMAL],
-        (width/8) - x/2,
-        (height/6) - y/2 + 20,
-        layout);
-    g_free(buffer);
-    buffer = g_strdup_printf(_("VDOP: %.01f"), _gps.vdop);
-    pango_layout_set_text(layout, buffer, strlen(buffer));
-    pango_layout_get_pixel_size(layout, &x, &y);
-    gdk_draw_layout(widget->window,
-        widget->style->fg_gc[GTK_STATE_NORMAL],
-        (width/8) - x/2,
-        (height/6) - y/2 + 40,
-        layout);
-    g_free(buffer);
-
-    pango_font_description_free (fontdesc);
-    g_object_unref (layout);
-
-    return TRUE;
-}
-
-static void
-gps_details(void)
-{
-    GtkWidget *dialog;
-    GtkWidget *table;
-    GtkWidget *label;
-    GtkWidget *notebook;
-    printf("%s()\n", __PRETTY_FUNCTION__);
-
-    dialog = gtk_dialog_new_with_buttons(_("GPS Details"),
-            GTK_WINDOW(_window), GTK_DIALOG_MODAL,
-            GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
-            NULL);
-
-    gtk_window_set_default_size(GTK_WINDOW(dialog), 600, 300);
+    if(policy_old && _route.head)
+    {
+        Point *src_first;
+        Route *src, *dest;
 
-    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
-            notebook = gtk_notebook_new(), TRUE, TRUE, 0);
+        if(policy_old > 0)
+        {
+            /* Append to current route. */
+            src = &data.path.path.route;
+            dest = &_route;
+        }
+        else
+        {
+            /* Prepend to current route. */
+            src = &_route;
+            dest = &data.path.path.route;
+        }
 
-    /* textual info */
-    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
-            table = gtk_table_new(4, 6, FALSE),
-            label = gtk_label_new(_("GPS Information")));
+        /* Find src_first non-zero point. */
+        for(src_first = src->head - 1; src_first++ != src->tail; )
+            if(src_first->unity)
+                break;
 
-    _sat_details_panel = gtk_drawing_area_new ();
-    gtk_widget_set_size_request (_sat_details_panel, 300, 300);
-    /* sat details info */
-    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
-            _sat_details_panel,
-            label = gtk_label_new(_("Satellites details")));
-    g_signal_connect (G_OBJECT (_sat_details_panel), "expose_event",
-                        G_CALLBACK (sat_details_panel_expose), NULL);
+        /* Append route points from src to dest. */
+        if(src->tail >= src_first)
+        {
+            WayPoint *curr;
+            guint num_dest_points = dest->tail - dest->head + 1;
+            guint num_src_points = src->tail - src_first + 1;
 
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Latitude")),
-            0, 1, 0, 1, GTK_EXPAND | GTK_FILL, 0, 20, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            _sdi_lat = gtk_label_new(" --- "),
-            1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(_sdi_lat), 0.f, 0.5f);
+            /* Adjust dest->tail to be able to fit src route data
+             * plus room for more route data. */
+            route_resize(dest, num_dest_points + num_src_points);
 
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Longitude")),
-            0, 1, 1, 2, GTK_EXPAND | GTK_FILL, 0, 20, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            _sdi_lon = gtk_label_new(" --- "),
-            1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(_sdi_lon), 0.f, 0.5f);
+            memcpy(dest->tail + 1, src_first,
+                    num_src_points * sizeof(Point));
 
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Speed")),
-            0, 1, 2, 3, GTK_EXPAND | GTK_FILL, 0, 20, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            _sdi_spd = gtk_label_new(" --- "),
-            1, 2, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(_sdi_spd), 0.f, 0.5f);
+            dest->tail += num_src_points;
 
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Altitude")),
-            0, 1, 3, 4, GTK_EXPAND | GTK_FILL, 0, 20, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            _sdi_alt = gtk_label_new(" --- "),
-            1, 2, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(_sdi_alt), 0.f, 0.5f);
+            /* Append waypoints from src to dest->. */
+            route_wresize(dest, (dest->wtail - dest->whead)
+                    + (src->wtail - src->whead) + 2);
+            for(curr = src->whead - 1; curr++ != src->wtail; )
+            {
+                (++(dest->wtail))->point = dest->head + num_dest_points
+                    + (curr->point - src_first);
+                dest->wtail->desc = curr->desc;
+            }
 
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Heading")),
-            0, 1, 4, 5, GTK_EXPAND | GTK_FILL, 0, 20, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            _sdi_hea = gtk_label_new(" --- "),
-            1, 2, 4, 5, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(_sdi_hea), 0.f, 0.5f);
+        }
 
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Local time")),
-            0, 1, 5, 6, GTK_EXPAND | GTK_FILL, 0, 20, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            _sdi_tim = gtk_label_new(" --:--:-- "),
-            1, 2, 5, 6, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(_sdi_tim), 0.f, 0.5f);
+        /* Kill old route - don't use MACRO_CLEAR_ROUTE(), because that
+         * would free the string desc's that we just moved to data.route. */
+        g_free(src->head);
+        g_free(src->whead);
+        if(policy_old < 0)
+            _route = *dest;
+    }
+    else
+    {
+        MACRO_CLEAR_ROUTE(_route);
+        /* Overwrite with data.route. */
+        _route = data.path.path.route;
+        route_resize(&_route, _route.tail - _route.head + 1);
+        route_wresize(&_route, _route.wtail - _route.whead + 1);
+    }
 
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Sat in view")),
-            2, 3, 0, 1, GTK_EXPAND | GTK_FILL, 0, 20, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            _sdi_vie = gtk_label_new("0"),
-            3, 4, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(_sdi_vie), 0.f, 0.5f);
+    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
+    return TRUE;
+}
 
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Sat in use")),
-            2, 3, 1, 2, GTK_EXPAND | GTK_FILL, 0, 20, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            _sdi_use = gtk_label_new("0"),
-            3, 4, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(_sdi_use), 0.f, 0.5f);
+/****************************************************************************
+ * ABOVE: FILE-HANDLING ROUTINES *********************************************
+ ****************************************************************************/
 
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Fix")),
-            2, 3, 2, 3, GTK_EXPAND | GTK_FILL, 0, 20, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            _sdi_fix = gtk_label_new(_("nofix")),
-            3, 4, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(_sdi_fix), 0.f, 0.5f);
 
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Fix Quality")),
-            2, 3, 3, 4, GTK_EXPAND | GTK_FILL, 0, 20, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            _sdi_fqu = gtk_label_new(_("none")),
-            3, 4, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(_sdi_fix), 0.f, 0.5f);
+/****************************************************************************
+ * BELOW: ROUTINES **********************************************************
+ ****************************************************************************/
 
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Max speed")),
-            2, 3, 5, 6, GTK_EXPAND | GTK_FILL, 0, 20, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            _sdi_msp = gtk_label_new(" --- "),
-            3, 4, 5, 6, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(_sdi_msp), 0.f, 0.5f);
+static gboolean
+gps_display_details(void)
+{
+    gchar *buffer, strtime[15];
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    gtk_widget_show_all(dialog);
-    _satdetails_on = TRUE;
-    gps_display_details();
-    while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
+    if(_gps.fix < 2)
     {
-        _satdetails_on = FALSE;
-        break;
+        /* no fix no fun */
+        gtk_label_set_label(GTK_LABEL(_sdi_lat), " --- ");
+        gtk_label_set_label(GTK_LABEL(_sdi_lon), " --- ");
+        gtk_label_set_label(GTK_LABEL(_sdi_spd), " --- ");
+        gtk_label_set_label(GTK_LABEL(_sdi_alt), " --- ");
+        gtk_label_set_label(GTK_LABEL(_sdi_hea), " --- ");
+        gtk_label_set_label(GTK_LABEL(_sdi_tim), " --:--:-- ");
     }
-    gtk_widget_destroy(dialog);
+    else
+    {
+        gfloat speed = _gps.speed * UNITS_CONVERT[_units];
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
+        /* latitude */
+        gtk_label_set_label(GTK_LABEL(_sdi_lat), _gps.slatitude);
 
-static gfloat
-calculate_distance(gfloat lat1, gfloat lon1, gfloat lat2, gfloat lon2)
-{
-    gfloat dlat, dlon, slat, slon, a;
+        /* longitude */
+        gtk_label_set_label(GTK_LABEL(_sdi_lon), _gps.slongitude);
 
-    /* Convert to radians. */
-    lat1 *= (PI / 180.f);
-    lon1 *= (PI / 180.f);
-    lat2 *= (PI / 180.f);
-    lon2 *= (PI / 180.f);
-
-    dlat = lat2 - lat1;
-    dlon = lon2 - lon1;
-
-    slat = sinf(dlat / 2.f);
-    slon = sinf(dlon / 2.f);
-    a = (slat * slat) + (cosf(lat1) * cosf(lat2) * slon * slon);
-
-    return ((2.f * atan2f(sqrtf(a), sqrtf(1.f - a))) * EARTH_RADIUS)
-        * UNITS_CONVERT[_units];
-}
-
-/**
- * Pop up a modal dialog box with simple error information in it.
- */
-static void
-popup_error(GtkWidget *window, const gchar *error)
-{
-    GtkWidget *dialog;
-    printf("%s(\"%s\")\n", __PRETTY_FUNCTION__, error);
+        /* speed */
+        switch(_units)
+        {
+            case UNITS_MI:
+                buffer = g_strdup_printf("%.1f mph", speed);
+                break;
+            case UNITS_NM:
+                buffer = g_strdup_printf("%.1f kn", speed);
+                break;
+            default:
+                buffer = g_strdup_printf("%.1f km/h", speed);
+                break;
+        }
+        gtk_label_set_label(GTK_LABEL(_sdi_spd), buffer);
+        g_free(buffer);
 
-    dialog = hildon_note_new_information(GTK_WINDOW(window), error);
+        /* altitude */
+        switch(_units)
+        {
+            case UNITS_MI:
+            case UNITS_NM:
+                buffer = g_strdup_printf("%d ft",
+                        (guint)(_gps.altitude * 3.2808399f));
+                break;
+            default:
+                buffer = g_strdup_printf("%d m", _gps.altitude);
+                break;
+        }
+        gtk_label_set_label(GTK_LABEL(_sdi_alt), buffer);
+        g_free(buffer);
 
-    gtk_dialog_run(GTK_DIALOG(dialog));
-    gtk_widget_destroy(dialog);
+        /* heading */
+        buffer = g_strdup_printf("%0.0f\u00b0", _gps.heading);
+        gtk_label_set_label(GTK_LABEL(_sdi_hea), buffer);
+        g_free(buffer);
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
+        /* local time */
+        strftime(strtime, 15, "%X", &_gps.timeloc);
+        gtk_label_set_label(GTK_LABEL(_sdi_tim), strtime);
+    }
 
-static void
-db_connect()
-{
-    gchar buffer[100];
-    gchar *perror;
-    gchar **pszResult;
-    guint nRow, nColumn;
+    /* Sat in view */
+    buffer = g_strdup_printf("%d", _gps.satinview);
+    gtk_label_set_label(GTK_LABEL(_sdi_vie), buffer);
+    g_free(buffer);
 
-    _dbconn = FALSE;
+    /* Sat in use */
+    buffer = g_strdup_printf("%d", _gps.satinuse);
+    gtk_label_set_label(GTK_LABEL(_sdi_use), buffer);
+    g_free(buffer);
 
-    if(!_poi_db)
-        return;
+    /* fix */
+    switch(_gps.fix)
+    {
+        case 2:
+        case 3: buffer = g_strdup_printf("%dD fix", _gps.fix); break;
+        default: buffer = g_strdup_printf("nofix"); break;
+    }
+    gtk_label_set_label(GTK_LABEL(_sdi_fix), buffer);
+    g_free(buffer);
 
-    if(NULL == (_db = sqlite_open(_poi_db, 0666, &perror)))
+    if(_gps.fix == 1)
+        buffer = g_strdup("none");
+    else
     {
-        gchar buffer2[200];
-        sprintf(buffer2, "%s: %s", _("Problem with POI database"), perror);
-        popup_error(_window, buffer2);
-        g_free(perror);
-        return;
+        switch (_gps.fixquality)
+        {
+            case 1 : buffer = g_strdup_printf(_("SPS")); break;
+            case 2 : buffer = g_strdup_printf(_("DGPS")); break;
+            case 3 : buffer = g_strdup_printf(_("PPS")); break;
+            case 4 : buffer = g_strdup_printf(_("Real Time Kinematic")); break;
+            case 5 : buffer = g_strdup_printf(_("Float RTK")); break;
+            case 6 : buffer = g_strdup_printf(_("Estimated")); break;
+            case 7 : buffer = g_strdup_printf(_("Manual)")); break;
+            case 8 : buffer = g_strdup_printf(_("Simulation")); break;
+            default : buffer = g_strdup_printf(_("none")); break;
+        }
     }
+    gtk_label_set_label(GTK_LABEL(_sdi_fqu), buffer);
+    g_free(buffer);
 
-    if(SQLITE_OK != sqlite_get_table(_db, "select label from poi limit 1",
-        &pszResult, &nRow, &nColumn, NULL))
+    /* max speed */
     {
-        if(SQLITE_OK != sqlite_exec(_db,
-                /* Create the necessary tables... */
-                "create table poi (poi_id integer PRIMARY KEY, lat real, "
-                "lon real, label text, desc text, cat_id integer);"
-                "create table category (cat_id integer PRIMARY KEY,"
-                "label text, desc text, enabled integer);"
-                /* Add some default categories... */
-                "insert into category (label, desc, enabled) "
-                "values ('Fuel',"
-                  "'Stations for purchasing fuel for vehicles.', 1);"
-                "insert into category (label, desc, enabled) "
-                "values ('Residence', "
-                  "'Houses, apartments, or other residences of import.', 1);"
-                "insert into category (label, desc, enabled) "
-                "values ('Dining', "
-                  "'Places to eat or drink.', 1);"
-                "insert into category (label, desc, enabled) "
-                "values ('Shopping/Services', "
-                  "'Places to shop or acquire services.', 1);"
-                "insert into category (label, desc, enabled) "
-                "values ('Recreation', "
-                  "'Indoor or Outdoor places to have fun.', 1);"
-                "insert into category (label, desc, enabled) "
-                "values ('Transportation', "
-                  "'Bus stops, airports, train stations, etc.', 1);"
-                "insert into category (label, desc, enabled) "
-                "values ('Lodging', "
-                  "'Places to stay temporarily or for the night.', 1);"
-                "insert into category (label, desc, enabled) "
-                "values ('School', "
-                  "'Elementary schools, college campuses, etc.', 1);"
-                "insert into category (label, desc, enabled) "
-                "values ('Business', "
-                  "'General places of business.', 1);"
-                "insert into category (label, desc, enabled) "
-                "values ('Landmark', "
-                  "'General landmarks.', 1);"
-                "insert into category (label, desc, enabled) "
-                "values ('Other', "
-                  "'Miscellaneous category for everything else.', 1);",
-                NULL,
-                NULL,
-                &perror)
-                && (SQLITE_OK != sqlite_get_table(_db,
-                            "select label from poi limit 1",
-                            &pszResult, &nRow, &nColumn, NULL)))
+        gfloat maxspeed = _gps.maxspeed * UNITS_CONVERT[_units];
+
+        /* speed */
+        switch(_units)
         {
-            sprintf(buffer, _("Failed to open or create database:\n%s"),
-                    _poi_db);
-            popup_error(_window, buffer);
-            sqlite_close(_db);
-            return;
+            case UNITS_MI:
+                buffer = g_strdup_printf("%.1f mph", maxspeed);
+                break;
+            case UNITS_NM:
+                buffer = g_strdup_printf("%.1f kn", maxspeed);
+                break;
+            default:
+                buffer = g_strdup_printf("%.1f km/h", maxspeed);
+                break;
         }
+        gtk_label_set_label(GTK_LABEL(_sdi_msp), buffer);
+        g_free(buffer);
     }
-    else
-        sqlite_free_table(pszResult);
 
-    _dbconn = TRUE;
+    /* refresh sat panel */
+    gtk_widget_queue_draw_area(GTK_WIDGET(_sat_details_panel),
+        0, 0,
+        _sat_details_panel->allocation.width,
+        _sat_details_panel->allocation.height);
+
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+    return TRUE;
 }
 
-/**
- * Set the connection state.  This function controls all connection-related
- * banners.
- */
 static void
-set_conn_state(ConnState new_conn_state)
+gps_display_data(void)
 {
-    printf("%s(%d)\n", __PRETTY_FUNCTION__, new_conn_state);
+    gchar *buffer, strtime[15];
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    switch(_conn_state = new_conn_state)
+    if(_gps.fix < 2)
     {
-        case RCVR_OFF:
-        case RCVR_FIXED:
-            if(_connect_banner)
-            {
-                gtk_widget_destroy(_connect_banner);
-                _connect_banner = NULL;
-            }
-            if(_fix_banner)
-            {
-                gtk_widget_destroy(_fix_banner);
-                _fix_banner = NULL;
-            }
-            break;
-        case RCVR_DOWN:
-            if(_fix_banner)
-            {
-                gtk_widget_destroy(_fix_banner);
-                _fix_banner = NULL;
-            }
-            if(!_connect_banner)
-                _connect_banner = hildon_banner_show_animation(
-                        _window, NULL, _("Searching for GPS receiver"));
-            break;
-        case RCVR_UP:
-            if(_connect_banner)
-            {
-                gtk_widget_destroy(_connect_banner);
-                _connect_banner = NULL;
-            }
-            if(!_fix_banner)
-                _fix_banner = hildon_banner_show_progress(
-                        _window, NULL, _("Establishing GPS fix"));
-            break;
-        default: ; /* to quell warning. */
+        /* no fix no fun */
+        gtk_label_set_label(GTK_LABEL(_text_lat), " --- ");
+        gtk_label_set_label(GTK_LABEL(_text_lon), " --- ");
+        gtk_label_set_label(GTK_LABEL(_text_speed), " --- ");
+        gtk_label_set_label(GTK_LABEL(_text_alt), " --- ");
+        gtk_label_set_label(GTK_LABEL(_text_time), " --:--:-- ");
     }
+    else
+    {
+        gfloat speed = _gps.speed * UNITS_CONVERT[_units];
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
+        /* latitude */
+        gtk_label_set_label(GTK_LABEL(_text_lat), _gps.slatitude);
 
-/**
- * Updates _near_point, _next_way, and _next_wpt.  If quick is FALSE (as
- * it is when this function is called from route_find_nearest_point), then
- * the entire list (starting from _near_point) is searched.  Otherwise, we
- * stop searching when we find a point that is farther away.
- */
-static gboolean
-route_update_nears(gboolean quick)
-{
-    gboolean ret = FALSE;
-    Point *curr, *near;
-    WayPoint *wcurr, *wnext;
-    guint near_dist_rough;
-    printf("%s(%d)\n", __PRETTY_FUNCTION__, quick);
-
-    /* If we have waypoints (_next_way != NULL), then determine the "next
-     * waypoint", which is defined as the waypoint after the nearest point,
-     * UNLESS we've passed that waypoint, in which case the waypoint after
-     * that waypoint becomes the "next" waypoint. */
-    if(_next_way)
-    {
-        /* First, set near_dist_rough with the new distance from _near_point. */
-        near = _near_point;
-        near_dist_rough = DISTANCE_ROUGH(_pos, *near);
+        /* longitude */
+        gtk_label_set_label(GTK_LABEL(_text_lon), _gps.slongitude);
 
-        /* Now, search _route for a closer point.  If quick is TRUE, then we'll
-         * only search forward, only as long as we keep finding closer points.
-         */
-        for(curr = _near_point; curr++ != _route.tail; )
+        /* speed */
+        switch(_units)
         {
-            if(curr->unity)
-            {
-                guint dist_rough = DISTANCE_ROUGH(_pos, *curr);
-                if(dist_rough <= near_dist_rough)
-                {
-                    near = curr;
-                    near_dist_rough = dist_rough;
-                }
-                else if(quick)
-                    break;
-            }
+            case UNITS_MI:
+                buffer = g_strdup_printf("Spd: %.1f mph", speed);
+                break;
+            case UNITS_NM:
+                buffer = g_strdup_printf("Spd: %.1f kn", speed);
+                break;
+            default:
+                buffer = g_strdup_printf("Spd: %.1f km/h", speed);
+                break;
         }
+        gtk_label_set_label(GTK_LABEL(_text_speed), buffer);
+        g_free(buffer);
 
-        /* Update _near_point. */
-        _near_point = near;
-        _near_point_dist_rough = near_dist_rough;
-
-        for(wnext = wcurr = _next_way; wcurr != _route.wtail; wcurr++)
+        /* altitude */
+        switch(_units)
         {
-            if(wcurr->point < near
-            /* Okay, this else if expression warrants explanation.  If the
-             * nearest track point happens to be a waypoint, then we want to
-             * check if we have "passed" that waypoint.  To check this, we
-             * test the distance from _pos to the waypoint and from _pos to
-             * _next_wpt, and if the former is increasing and the latter is
-             * decreasing, then we have passed the waypoint, and thus we
-             * should skip it.  Note that if there is no _next_wpt, then
-             * there is no next waypoint, so we do not skip it in that case. */
-                || (wcurr->point == near && quick
-                    && (_next_wpt
-                     && (DISTANCE_ROUGH(_pos, *near) > _next_way_dist_rough
-                      && DISTANCE_ROUGH(_pos, *_next_wpt)
-                                                     < _next_wpt_dist_rough))))
-                wnext = wcurr + 1;
-            else
+            case UNITS_MI:
+            case UNITS_NM:
+                buffer = g_strdup_printf("Alt: %d ft",
+                        (guint)(_gps.altitude * 3.2808399f));
                 break;
+            default:
+                buffer = g_strdup_printf("Alt: %d m", _gps.altitude);
         }
+        gtk_label_set_label(GTK_LABEL(_text_alt), buffer);
+        g_free(buffer);
 
-        if(wnext == _route.wtail && (wnext->point < near
-                || (wnext->point == near && quick
-                    && (!_next_wpt
-                     || (DISTANCE_ROUGH(_pos, *near) > _next_way_dist_rough
-                      &&DISTANCE_ROUGH(_pos, *_next_wpt)
-                                                     < _next_wpt_dist_rough)))))
-        {
-            _next_way = NULL;
-            _next_wpt = NULL;
-            _next_way_dist_rough = -1;
-            _next_wpt_dist_rough = -1;
-            ret = TRUE;
-        }
-        /* Only update _next_way (and consequently _next_wpt) if _next_way is
-         * different, and record that fact for return. */
-        else
-        {
-            if(!quick || _next_way != wnext)
-            {
-                _next_way = wnext;
-                _next_wpt = wnext->point;
-                if(_next_wpt == _route.tail)
-                    _next_wpt = NULL;
-                else
-                {
-                    while(!(++_next_wpt)->unity)
-                    {
-                        if(_next_wpt == _route.tail)
-                        {
-                            _next_wpt = NULL;
-                            break;
-                        }
-                    }
-                }
-                ret = TRUE;
-            }
-            _next_way_dist_rough = DISTANCE_ROUGH(_pos, *wnext->point);
-            if(_next_wpt)
-                _next_wpt_dist_rough = DISTANCE_ROUGH(_pos, *_next_wpt);
-        }
+        /* local time */
+        strftime(strtime, 15, "%X", &_gps.timeloc);
+        gtk_label_set_label(GTK_LABEL(_text_time), strtime);
     }
 
-    vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, ret);
-    return ret;
+    /* refresh sat panel */
+    gtk_widget_queue_draw_area(GTK_WIDGET(_sat_panel),
+        0, 0,
+        _sat_panel->allocation.width,
+        _sat_panel->allocation.height);
+
+    /* refresh heading panel*/
+    gtk_widget_queue_draw_area(GTK_WIDGET(_heading_panel),
+        0, 0,
+        _heading_panel->allocation.width,
+        _heading_panel->allocation.height);
+
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+    return;
 }
 
-/**
- * Reset the _near_point data by searching the entire route for the nearest
- * route point and waypoint.
- */
 static void
-route_find_nearest_point()
+gps_hide_text(void)
 {
     printf("%s()\n", __PRETTY_FUNCTION__);
 
-    /* Initialize _near_point. */
-    _near_point = _route.head;
-    while(!_near_point->unity && _near_point != _route.tail)
-        _near_point++;
-
-    /* Initialize _next_way. */
-    if(_route.wtail == _route.whead - 1
-            || (_autoroute_data.enabled && _route.wtail == _route.whead))
-        _next_way = NULL;
-    else
-        /* We have at least one waypoint. */
-        _next_way = (_autoroute_data.enabled ? _route.whead + 1 : _route.whead);
-    _next_way_dist_rough = -1;
-
-    /* Initialize _next_wpt. */
-    _next_wpt = NULL;
-    _next_wpt_dist_rough = -1;
+    /* Clear gps data */
+    _gps.fix = 1;
+    _gps.satinuse = 0;
+    _gps.satinview = 0;
 
-    route_update_nears(FALSE);
+    if(_gps_info)
+        gps_display_data();
 
     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
 }
 
-/**
- * Render a single track line to _map_pixmap.  If either point on the line
- * is a break (defined as unity == 0), a circle is drawn at the other point.
- * IT IS AN ERROR FOR BOTH POINTS TO INDICATE A BREAK.
- */
 static void
-map_render_segment(GdkGC *gc_norm, GdkGC *gc_alt,
-        guint unitx1, guint unity1, guint unitx2, guint unity2)
+gps_show_info(void)
 {
-    vprintf("%s()\n", __PRETTY_FUNCTION__);
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    if(!unity1)
-    {
-        guint x2, y2;
-        x2 = unit2bufx(unitx2);
-        y2 = unit2bufy(unity2);
-        /* Make sure this circle will be visible. */
-        if((x2 < BUF_WIDTH_PIXELS)
-                && (y2 < BUF_HEIGHT_PIXELS))
-            gdk_draw_arc(_map_pixmap, gc_alt,
-                    FALSE, /* FALSE: not filled. */
-                    x2 - _draw_line_width,
-                    y2 - _draw_line_width,
-                    2 * _draw_line_width,
-                    2 * _draw_line_width,
-                    0, /* start at 0 degrees. */
-                    360 * 64);
-    }
-    else if(!unity2)
-    {
-        guint x1, y1;
-        x1 = unit2bufx(unitx1);
-        y1 = unit2bufy(unity1);
-        /* Make sure this circle will be visible. */
-        if((x1 < BUF_WIDTH_PIXELS)
-                && ((unsigned)y1 < BUF_HEIGHT_PIXELS))
-            gdk_draw_arc(_map_pixmap, gc_alt,
-                    FALSE, /* FALSE: not filled. */
-                    x1 - _draw_line_width,
-                    y1 - _draw_line_width,
-                    2 * _draw_line_width,
-                    2 * _draw_line_width,
-                    0, /* start at 0 degrees. */
-                    360 * 64);
-    }
+    if(_gps_info && _enable_gps)
+        gtk_widget_show_all(GTK_WIDGET(_gps_widget));
     else
     {
-        gint x1, y1, x2, y2;
-        x1 = unit2bufx(unitx1);
-        y1 = unit2bufy(unity1);
-        x2 = unit2bufx(unitx2);
-        y2 = unit2bufy(unity2);
-        /* Make sure this line could possibly be visible. */
-        if(!((x1 > BUF_WIDTH_PIXELS && x2 > BUF_WIDTH_PIXELS)
-                || (x1 < 0 && x2 < 0)
-                || (y1 > BUF_HEIGHT_PIXELS && y2 > BUF_HEIGHT_PIXELS)
-                || (y1 < 0 && y2 < 0)))
-            gdk_draw_line(_map_pixmap, gc_norm, x1, y1, x2, y2);
+        gps_hide_text();
+        gtk_widget_hide_all(GTK_WIDGET(_gps_widget));
     }
 
     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
 }
 
-/**
- * Render all track data onto the _map_pixmap.  Note that this does not
- * clear the pixmap of previous track data (use map_force_redraw() for
- * that), and also note that this method does not queue any redraws, so it
- * is up to the caller to decide which part of the track really needs to be
- * redrawn.
- */
 static void
-map_render_track()
+draw_sat_info(GtkWidget *widget, guint x0, guint y0,
+        guint width, guint height, gboolean showsnr)
 {
-    TrackPoint *curr;
-    printf("%s()\n", __PRETTY_FUNCTION__);
-
-    for(curr = _track.head; curr != _track.tail; curr++)
-        map_render_segment(_gc_track, _gc_track_break,
-                curr->point.unitx, curr->point.unity,
-                curr[1].point.unitx, curr[1].point.unity);
+    PangoContext *context = NULL;
+    PangoLayout *layout = NULL;
+    PangoFontDescription *fontdesc = NULL;
+    GdkColor color;
+    GdkGC *gc1, *gc2, *gc;
+    guint step, i, j, snr_height, bymargin, xoffset, yoffset;
+    guint x, y, x1, y1;
+    gchar *tmp = NULL;
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
+    xoffset = x0;
+    yoffset = y0;
+    /* Bootom margin - 12% */
+    bymargin = height * 0.88f;
 
-/**
- * Render all track data onto the _map_pixmap.  Note that this does not
- * clear the pixmap of previous track data (use map_force_redraw() for
- * that), and also note that this method does not queue any redraws, so it
- * is up to the caller to decide which part of the track really needs to be
- * redrawn.
- */
-static void
-map_render_route()
-{
-    Point *curr;
-    WayPoint *wcurr;
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    /* Bottom line */
+    gdk_draw_line(widget->window,
+        widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+        xoffset + 5, yoffset + bymargin,
+        xoffset + width - 10 - 2, yoffset + bymargin);
+    gdk_draw_line(widget->window,
+        widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+        xoffset + 5, yoffset + bymargin - 1,
+        xoffset + width - 10 - 2, yoffset + bymargin - 1);
 
-    _visible_way_first = _visible_way_last = NULL;
-    for(curr = _route.head, wcurr = _route.whead; curr != _route.tail; curr++)
+    context = gtk_widget_get_pango_context(widget);
+    layout = pango_layout_new(context);
+    fontdesc =  pango_font_description_new();
+
+    pango_font_description_set_family(fontdesc,"Sans Serif");
+
+    if(_gps.satinview > 0 )
     {
-        if(wcurr <= _route.wtail && curr == wcurr->point)
+        pango_font_description_set_size(fontdesc, 8*PANGO_SCALE);
+
+        pango_layout_set_font_description (layout, fontdesc);
+        pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
+
+        /* Left margin - 5pix, Right margin - 5pix */
+        step = (width - 10) / _gps.satinview;
+
+        color.red = 0;
+        color.green = 0;
+        color.blue = 0;
+        gc1 = gdk_gc_new (widget->window);
+        gdk_gc_set_rgb_fg_color (gc1, &color);
+
+        color.red = 0;
+        color.green = 0;
+        color.blue = 0xffff;
+        gc2 = gdk_gc_new (widget->window);
+        gdk_gc_set_rgb_fg_color (gc2, &color);
+
+        for(i = 0; i < _gps.satinview; i++)
         {
-            guint x1 = unit2bufx(wcurr->point->unitx);
-            guint y1 = unit2bufy(wcurr->point->unity);
-            if((x1 < BUF_WIDTH_PIXELS)
-                    && (y1 < BUF_HEIGHT_PIXELS))
+            /* Sat used or not */
+            gc = gc1;
+            for(j = 0; j < _gps.satinuse ; j++)
             {
-                gdk_draw_arc(_map_pixmap,
-                        (wcurr==_next_way ? _gc_route_nextway : _gc_route_way),
-                        FALSE, /* FALSE: not filled. */
-                        x1 - _draw_line_width,
-                        y1 - _draw_line_width,
-                        2 * _draw_line_width,
-                        2 * _draw_line_width,
-                        0, /* start at 0 degrees. */
-                        360 * 64);
-                if(!_visible_way_first)
-                    _visible_way_first = wcurr;
-                _visible_way_last = wcurr;
+                if(_gps.satforfix[j] == _gps_sat[i].prn)
+                {
+                    gc = gc2;
+                    break;
+                }
             }
-            wcurr++;
-            if(!curr[1].unity)
-                continue;
-        }
-        map_render_segment(_gc_route, _gc_route_way,
-                curr->unitx, curr->unity, curr[1].unitx, curr[1].unity);
-    }
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
+            x = 5 + i * step;
+            snr_height = _gps_sat[i].snr * height * 0.78f / 100;
+            y = height * 0.1f + (height * 0.78f - snr_height);
 
-static void
-map_render_paths()
-{
-    printf("%s()\n", __PRETTY_FUNCTION__);
+            /* draw sat rectangle... */
+            gdk_draw_rectangle(widget->window,
+                    gc,
+                    TRUE,
+                    xoffset + x,
+                    yoffset + y,
+                    step - 2,
+                    snr_height);
 
-    if((_show_tracks & ROUTES_MASK) && _route.head)
-    {
-        map_render_route();
-        if(_next_way == NULL)
-        {
-            guint x1 = unit2bufx(_route.tail[-1].unitx);
-            guint y1 = unit2bufy(_route.tail[-1].unity);
-            if((x1 < BUF_WIDTH_PIXELS)
-                    && (y1 < BUF_HEIGHT_PIXELS))
+            if(showsnr && _gps_sat[i].snr > 0)
             {
-                gdk_draw_arc(_map_pixmap,
-                        _gc_route_nextway,
-                        FALSE, /* FALSE: not filled. */
-                        x1 - _draw_line_width,
-                        y1 - _draw_line_width,
-                        2 * _draw_line_width,
-                        2 * _draw_line_width,
-                        0, /* start at 0 degrees. */
-                        360 * 64);
+                /* ...snr.. */
+                tmp = g_strdup_printf("%02d", _gps_sat[i].snr);
+                pango_layout_set_text(layout, tmp, 2);
+                pango_layout_get_pixel_size(layout, &x1, &y1);
+                gdk_draw_layout(widget->window,
+                    widget->style->fg_gc[GTK_STATE_NORMAL],
+                    xoffset + x + ((step - 2) - x1)/2,
+                    yoffset + y - 15,
+                    layout);
+                g_free(tmp);
             }
+
+            /* ...and sat number */
+            tmp = g_strdup_printf("%02d", _gps_sat[i].prn);
+            pango_layout_set_text(layout, tmp, 2);
+            pango_layout_get_pixel_size(layout, &x1, &y1);
+            gdk_draw_layout(widget->window,
+                widget->style->fg_gc[GTK_STATE_NORMAL],
+                xoffset + x + ((step - 2) - x1)/2 ,
+                yoffset + bymargin + 1,
+                layout);
+            g_free(tmp);
         }
+        g_object_unref (gc1);
+        g_object_unref (gc2);
     }
-    if(_show_tracks & TRACKS_MASK)
-        map_render_track();
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+    pango_font_description_free (fontdesc);
+    g_object_unref (layout);
+
+    return;
 }
 
 static void
-track_resize(Track *track, guint size)
+draw_sat_details(GtkWidget *widget, guint x0, guint y0,
+        guint width, guint height)
 {
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    guint i, j, x, y, size, halfsize, xoffset, yoffset;
+    guint x1, y1;
+    gfloat tmp;
+    GdkColor color;
+    GdkGC *gc1, *gc2, *gc3, *gc;
+    PangoContext *context = NULL;
+    PangoLayout *layout = NULL;
+    PangoFontDescription *fontdesc = NULL;
+    gchar *buffer = NULL;
 
-    if(track->head + size != track->cap)
+    size = MIN(width, height);
+    halfsize = size/2;
+    if(width > height)
     {
-        TrackPoint *old_head = track->head;
-        track->head = g_renew(TrackPoint, old_head, size);
-        track->cap = track->head + size;
-        if(track->head != old_head)
-            track->tail = track->head + (track->tail - old_head);
+        xoffset = x0 + (width - height - 10) / 2;
+        yoffset = y0 + 5;
+    }
+    else
+    {
+        xoffset = x0 + 5;
+        yoffset = y0 + (height - width - 10) / 2;
     }
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
+    context = gtk_widget_get_pango_context(widget);
+    layout = pango_layout_new(context);
+    fontdesc =  pango_font_description_new();
 
-static void
-route_resize(Route *route, guint size)
-{
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    pango_font_description_set_family(fontdesc,"Sans Serif");
+    pango_font_description_set_size(fontdesc, 10*PANGO_SCALE);
+    pango_layout_set_font_description (layout, fontdesc);
+    pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
 
-    if(route->head + size != route->cap)
-    {
-        Point *old_head = route->head;
-        WayPoint *curr;
-        route->head = g_renew(Point, old_head, size);
-        route->cap = route->head + size;
-        if(route->head != old_head)
-        {
-            route->tail = route->head + (route->tail - old_head);
+    /* 90 */
+    gdk_draw_arc(widget->window,
+            widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
+            FALSE,
+            xoffset + 2, yoffset + 2, size - 4, size - 4,
+            0, 64 * 360);
 
-            /* Adjust all of the waypoints. */
-            for(curr = route->whead - 1; curr++ != route->wtail; )
-                curr->point = route->head + (curr->point - old_head);
-        }
-    }
+    /* 60 */
+    gdk_draw_arc(widget->window,
+            widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
+            FALSE,
+            xoffset + size/6, yoffset + size/6,
+            size/6*4, size/6*4,
+            0, 64 * 360);
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
+    /* 30 */
+    gdk_draw_arc(widget->window,
+            widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
+            FALSE,
+            xoffset + size/6*2, yoffset + size/6*2,
+            size/6*2, size/6*2,
+            0, 64 * 360);
 
-static void
-route_wresize(Route *route, guint wsize)
-{
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    guint line[12] = {0,30,60,90,120,150,180,210,240,270,300,330};
 
-    if(route->whead + wsize != route->wcap)
+    for(i = 0; i < 6; i++)
     {
-        WayPoint *old_whead = route->whead;
-        route->whead = g_renew(WayPoint, old_whead, wsize);
-        route->wtail = route->whead + (route->wtail - old_whead);
-        route->wcap = route->whead + wsize;
+        /* line */
+        tmp = (line[i] * (1.f / 180.f)) * PI;
+        gdk_draw_line(widget->window,
+            widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+            xoffset + halfsize + (halfsize -2) * sinf(tmp),
+            yoffset + halfsize - (halfsize -2) * cosf(tmp),
+            xoffset + halfsize - (halfsize -2) * sinf(tmp),
+            yoffset + halfsize + (halfsize -2) * cosf(tmp));
     }
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
-
-#define MACRO_TRACK_INCREMENT_TAIL(track) { \
-    if(++(track).tail == (track).cap) \
-        track_resize(&(track), (track).cap - (track).head + ARRAY_CHUNK_SIZE); \
-}
-
-#define MACRO_ROUTE_INCREMENT_TAIL(route) { \
-    if(++(route).tail == (route).cap) \
-        route_resize(&(route), (route).cap - (route).head + ARRAY_CHUNK_SIZE); \
-}
-
-#define MACRO_ROUTE_INCREMENT_WTAIL(route) { \
-    if(++(route).wtail == (route).wcap) \
-        route_wresize(&(route), \
-                (route).wcap - (route).whead + ARRAY_CHUNK_SIZE); \
-}
+    for(i = 0; i < 12; i++)
+    {
+        tmp = (line[i] * (1.f / 180.f)) * PI;
+        /* azimuth */
+        if(line[i] == 0)
+            buffer = g_strdup_printf("N");
+        else
+            buffer = g_strdup_printf("%d\u00b0", line[i]);
+        pango_layout_set_text(layout, buffer, strlen(buffer));
+        pango_layout_get_pixel_size(layout, &x, &y);
+        gdk_draw_layout(widget->window,
+            widget->style->fg_gc[GTK_STATE_NORMAL],
+            (xoffset + halfsize + (halfsize - size/12) * sinf(tmp)) - x/2,
+            (yoffset + halfsize - (halfsize - size/12) * cosf(tmp)) - y/2,
+            layout);
+        g_free(buffer);
+    }
 
-/**
- * Add a point to the _track list.  This function is slightly overloaded,
- * since it is what houses the check for "have we moved
- * significantly": it also initiates the re-calculation of the _near_point
- * data, as well as calling osso_display_state_on() when we have the focus.
- *
- * If a non-zero time is given, then the current position (as taken from the
- * _pos variable) is appended to _track with the given time.  If time is zero,
- * then _pos_null is appended to _track with time zero (this produces a "break"
- * in the track).
- */
-static void
-track_add(time_t time, gboolean newly_fixed)
-{
-    Point pos = (time == 0 ? _pos_null : _pos);
-    printf("%s(%u, %u)\n", __PRETTY_FUNCTION__, pos.unitx, pos.unity);
+    /* elevation 30 */
+    tmp = (30 * (1.f / 180.f)) * PI;
+    buffer = g_strdup_printf("30\u00b0");
+    pango_layout_set_text(layout, buffer, strlen(buffer));
+    pango_layout_get_pixel_size(layout, &x, &y);
+    gdk_draw_layout(widget->window,
+        widget->style->fg_gc[GTK_STATE_NORMAL],
+        (xoffset + halfsize + size/6*2 * sinf(tmp)) - x/2,
+        (yoffset + halfsize - size/6*2 * cosf(tmp)) - y/2,
+        layout);
+    g_free(buffer);
 
-    if(abs((gint)pos.unitx - _track.tail->point.unitx) > _draw_line_width
-    || abs((gint)pos.unity - _track.tail->point.unity) > _draw_line_width)
-    {
-        if(time && _route.head
-                && (newly_fixed ? (route_find_nearest_point(), TRUE)
-                                : route_update_nears(TRUE)))
-        {
-            map_render_paths();
-            MACRO_QUEUE_DRAW_AREA();
-        }
-        if(_show_tracks & TRACKS_MASK)
-        {
-            /* Instead of calling map_render_paths(), we'll draw the new line
-             * ourselves and call gtk_widget_queue_draw_area(). */
-            gint tx1, ty1, tx2, ty2;
-            map_render_segment(_gc_track, _gc_track_break,
-                    _track.tail->point.unitx, _track.tail->point.unity,
-                    pos.unitx, pos.unity);
-            if(time && _track.tail->point.unity)
-            {
-                tx1 = unit2x(_track.tail->point.unitx);
-                ty1 = unit2y(_track.tail->point.unity);
-                tx2 = unit2x(pos.unitx);
-                ty2 = unit2y(pos.unity);
-                gtk_widget_queue_draw_area(_map_widget,
-                        MIN(tx1, tx2) - _draw_line_width,
-                        MIN(ty1, ty2) - _draw_line_width,
-                        abs(tx1 - tx2) + (2 * _draw_line_width),
-                        abs(ty1 - ty2) + (2 * _draw_line_width));
-            }
-        }
-        MACRO_TRACK_INCREMENT_TAIL(_track);
+    /* elevation 60 */
+    tmp = (30 * (1.f / 180.f)) * PI;
+    buffer = g_strdup_printf("60\u00b0");
+    pango_layout_set_text(layout, buffer, strlen(buffer));
+    pango_layout_get_pixel_size(layout, &x, &y);
+    gdk_draw_layout(widget->window,
+        widget->style->fg_gc[GTK_STATE_NORMAL],
+        (xoffset + halfsize + size/6 * sinf(tmp)) - x/2,
+        (yoffset + halfsize - size/6 * cosf(tmp)) - y/2,
+        layout);
+    g_free(buffer);
 
-        _track.tail->point = pos;
-        _track.tail->time = time;
+    color.red = 0;
+    color.green = 0;
+    color.blue = 0;
+    gc1 = gdk_gc_new (widget->window);
+    gdk_gc_set_rgb_fg_color (gc1, &color);
 
-        if(_autoroute_data.enabled && !_autoroute_data.in_progress
-                && _near_point_dist_rough > 400)
-        {
-            _autoroute_data.in_progress = TRUE;
-            g_idle_add((GSourceFunc)auto_route_dl_idle, NULL);
-        }
+    color.red = 0;
+    color.green = 0;
+    color.blue = 0xffff;
+    gc2 = gdk_gc_new (widget->window);
+    gdk_gc_set_rgb_fg_color (gc2, &color);
 
-        /* Keep the display on. */
-        KEEP_DISPLAY_ON();
-    }
+    color.red = 0xffff;
+    color.green = 0xffff;
+    color.blue = 0xffff;
+    gc3 = gdk_gc_new (widget->window);
+    gdk_gc_set_rgb_fg_color (gc3, &color);
 
-    /* Check if we should announce upcoming waypoints. */
-    if(time && _next_way_dist_rough
-            < (20 + (guint)_speed) * _announce_notice_ratio * 3)
+    for(i = 0; i < _gps.satinview; i++)
     {
-        if(_enable_voice && strcmp(_next_way->desc, _last_spoken_phrase))
+        /* Sat used or not */
+        gc = gc1;
+        for(j = 0; j < _gps.satinuse ; j++)
         {
-            g_free(_last_spoken_phrase);
-            _last_spoken_phrase = g_strdup(_next_way->desc);
-            if(!fork())
+            if(_gps.satforfix[j] == _gps_sat[i].prn)
             {
-                /* We are the fork child.  Synthesize the voice. */
-                hildon_play_system_sound(
-                        "/usr/share/sounds/ui-information_note.wav");
-                sleep(1);
-#               define _voice_synth_path "/usr/bin/flite"
-                printf("%s %s\n", _voice_synth_path, _last_spoken_phrase);
-                execl(_voice_synth_path, _voice_synth_path,
-                        "-t", _last_spoken_phrase, (char *)NULL);
-                exit(0);
+                gc = gc2;
+                break;
             }
         }
-        hildon_banner_show_information(_window, NULL, _next_way->desc);
-    }
-
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
 
-/**
- * Disconnect from the receiver.  This method cleans up any and everything
- * that might be associated with the receiver.
- */
-static void
-rcvr_disconnect()
-{
-    printf("%s()\n", __PRETTY_FUNCTION__);
+        tmp = (_gps_sat[i].azimuth * (1.f / 180.f)) * PI;
+        x = xoffset + halfsize
+            + (90 - _gps_sat[i].elevation)*halfsize/90 * sinf(tmp);
+        y = yoffset + halfsize
+            - (90 - _gps_sat[i].elevation)*halfsize/90 * cosf(tmp);
 
-    /* Remove watches. */
-    if(_clater_sid)
-    {
-        g_source_remove(_clater_sid);
-        _clater_sid = 0;
-    }
-    if(_error_sid)
-    {
-        g_source_remove(_error_sid);
-        _error_sid = 0;
-    }
-    if(_connect_sid)
-    {
-        g_source_remove(_connect_sid);
-        _connect_sid = 0;
-    }
-    if(_input_sid)
-    {
-        g_source_remove(_input_sid);
-        _input_sid = 0;
-    }
+        gdk_draw_arc (widget->window,
+            gc, TRUE,
+            x - 10, y - 10, 20, 20,
+            0, 64 * 360);
 
-    /* Destroy the GIOChannel object. */
-    if(_channel)
-    {
-        g_io_channel_shutdown(_channel, FALSE, NULL);
-        g_io_channel_unref(_channel);
-        _channel = NULL;
+        buffer = g_strdup_printf("%02d", _gps_sat[i].prn);
+        pango_layout_set_text(layout, buffer, strlen(buffer));
+        pango_layout_get_pixel_size(layout, &x1, &y1);
+        gdk_draw_layout(widget->window,
+            gc3,
+            x - x1/2,
+            y - y1/2,
+            layout);
+        g_free(buffer);
     }
+    g_object_unref (gc1);
+    g_object_unref (gc2);
+    g_object_unref (gc3);
 
-    /* Close the file descriptor. */
-    if(_fd != -1)
-    {
-        close(_fd);
-        _fd = -1;
-    }
+    pango_font_description_free (fontdesc);
+    g_object_unref (layout);
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+    return;
 }
 
-static void rcvr_connect_later(); /* Forward declaration. */
 
-/**
- * Connect to the receiver.
- * This method assumes that _fd is -1 and _channel is NULL.  If unsure, call
- * rcvr_disconnect() first.
- * Since this is an idle function, this function returns whether or not it
- * should be called again, which is always FALSE.
- */
 static gboolean
-rcvr_connect_now()
+sat_details_panel_expose(GtkWidget *widget, GdkEventExpose *event)
 {
-    printf("%s(%d)\n", __PRETTY_FUNCTION__, _conn_state);
+    guint width, height, x, y;
+    PangoContext *context = NULL;
+    PangoLayout *layout = NULL;
+    PangoFontDescription *fontdesc = NULL;
+    gchar *buffer = NULL;
 
-    if(_conn_state == RCVR_DOWN && _rcvr_mac) {
-#ifndef DEBUG
-        /* Create the file descriptor. */
-        if(*_rcvr_mac == '/')
-            _fd = open(_rcvr_mac, O_RDONLY);
-        else
-            _fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+    width = widget->allocation.width;
+    height = widget->allocation.height * 0.9;
 
-        /* If file descriptor creation failed, try again later.  Note that
-         * there is no need to call rcvr_disconnect() because the file
-         * descriptor creation is the first step, so if it fails, there's
-         * nothing to clean up. */
-        if(_fd == -1)
-            rcvr_connect_later();
-        else
-        {
-            /* Reset GPS read buffer */
-            _gps_read_buf_curr = _gps_read_buf;
-            *_gps_read_buf_curr = '\0';
+    draw_sat_info(widget, 0, 0, width/2, height, TRUE);
+    draw_sat_details(widget, width/2, 0, width/2, height);
 
-            /* Create channel and add watches. */
-            _channel = g_io_channel_unix_new(_fd);
-            g_io_channel_set_flags(_channel, G_IO_FLAG_NONBLOCK, NULL);
-            _error_sid = g_io_add_watch_full(_channel, G_PRIORITY_HIGH_IDLE,
-                    G_IO_ERR | G_IO_HUP, channel_cb_error, NULL, NULL);
-            _connect_sid = g_io_add_watch_full(_channel, G_PRIORITY_HIGH_IDLE,
-                    G_IO_OUT, channel_cb_connect, NULL, NULL);
-            if(*_rcvr_mac != '/'
-                    && connect(_fd, (struct sockaddr*)&_rcvr_addr,
-                        sizeof(_rcvr_addr))
-                    && errno != EAGAIN)
-            {
-                /* Connection failed.  Disconnect and try again later. */
-                rcvr_disconnect();
-                rcvr_connect_later();
-            }
-        }
-#else
-        /* We're in DEBUG mode, so instead of connecting, skip to FIXED. */
-        set_conn_state(RCVR_FIXED);
-#endif
-    }
+    context = gtk_widget_get_pango_context(widget);
+    layout = pango_layout_new(context);
+    fontdesc =  pango_font_description_new();
 
-    _clater_sid = 0;
+    pango_font_description_set_family(fontdesc,"Sans Serif");
+    pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
+    pango_font_description_set_size(fontdesc, 14*PANGO_SCALE);
+    pango_layout_set_font_description (layout, fontdesc);
 
-    vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
-    return FALSE;
-}
+    buffer = g_strdup_printf(
+        _("Satellites in view: %d; in use: %d"),
+        _gps.satinview,
+        _gps.satinuse);
+    pango_layout_set_text(layout, buffer, strlen(buffer));
+    pango_layout_get_pixel_size(layout, &x, &y);
+    gdk_draw_layout(widget->window,
+        widget->style->fg_gc[GTK_STATE_NORMAL],
+        10,
+        height*0.9 + 10,
+        layout);
+    g_free(buffer);
 
-/**
- * Place a request to connect about 1 second after the function is called.
- */
-static void
-rcvr_connect_later()
-{
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    buffer = g_strdup_printf(_("HDOP: %.01f"), _gps.hdop);
+    pango_layout_set_text(layout, buffer, strlen(buffer));
+    pango_layout_get_pixel_size(layout, &x, &y);
+    gdk_draw_layout(widget->window,
+        widget->style->fg_gc[GTK_STATE_NORMAL],
+        (width/8) - x/2,
+        (height/6) - y/2,
+        layout);
+    g_free(buffer);
+    buffer = g_strdup_printf(_("PDOP: %.01f"), _gps.pdop);
+    pango_layout_set_text(layout, buffer, strlen(buffer));
+    pango_layout_get_pixel_size(layout, &x, &y);
+    gdk_draw_layout(widget->window,
+        widget->style->fg_gc[GTK_STATE_NORMAL],
+        (width/8) - x/2,
+        (height/6) - y/2 + 20,
+        layout);
+    g_free(buffer);
+    buffer = g_strdup_printf(_("VDOP: %.01f"), _gps.vdop);
+    pango_layout_set_text(layout, buffer, strlen(buffer));
+    pango_layout_get_pixel_size(layout, &x, &y);
+    gdk_draw_layout(widget->window,
+        widget->style->fg_gc[GTK_STATE_NORMAL],
+        (width/8) - x/2,
+        (height/6) - y/2 + 40,
+        layout);
+    g_free(buffer);
 
-    _clater_sid = g_timeout_add(1000, (GSourceFunc)rcvr_connect_now, NULL);
+    pango_font_description_free (fontdesc);
+    g_object_unref (layout);
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+    return TRUE;
 }
 
-/**
- * Convert the float lat/lon/speed/heading data into integer units.
- */
 static void
-integerize_data()
+gps_details(void)
 {
-    gfloat tmp;
+    GtkWidget *dialog;
+    GtkWidget *table;
+    GtkWidget *label;
+    GtkWidget *notebook;
     printf("%s()\n", __PRETTY_FUNCTION__);
 
-    latlon2unit(_pos_lat, _pos_lon, _pos.unitx, _pos.unity);
-
-    tmp = (_heading * (1.f / 180.f)) * PI;
-    _vel_offsetx = (gint)(floorf(_speed * sinf(tmp) + 0.5f));
-    _vel_offsety = -(gint)(floorf(_speed * cosf(tmp) + 0.5f));
+    dialog = gtk_dialog_new_with_buttons(_("GPS Details"),
+            GTK_WINDOW(_window), GTK_DIALOG_MODAL,
+            GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+            NULL);
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
+    gtk_window_set_default_size(GTK_WINDOW(dialog), 600, 300);
 
-/**
- * Update all GdkGC objects to reflect the current _draw_line_width.
- */
-#define UPDATE_GC(gc) \
-    gdk_gc_set_line_attributes(gc, \
-            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
-static void
-update_gcs()
-{
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
+            notebook = gtk_notebook_new(), TRUE, TRUE, 0);
 
-    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
-            &_color_mark);
-    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
-            &_color_mark_velocity);
-    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
-            &_color_mark_old);
-    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
-            &_color_track);
-    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
-            &_color_track_break);
-    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
-            &_color_route);
-    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
-            &_color_route_way);
-    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
-            &_color_route_nextway);
-    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
-            &_color_poi);
+    /* textual info */
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+            table = gtk_table_new(4, 6, FALSE),
+            label = gtk_label_new(_("GPS Information")));
 
-    if(_gc_mark)
-    {
-        g_object_unref(_gc_mark);
-        g_object_unref(_gc_mark_velocity);
-        g_object_unref(_gc_mark_old);
-        g_object_unref(_gc_track);
-        g_object_unref(_gc_track_break);
-        g_object_unref(_gc_route);
-        g_object_unref(_gc_route_way);
-        g_object_unref(_gc_route_nextway);
-        g_object_unref(_gc_poi);
-    }
+    _sat_details_panel = gtk_drawing_area_new ();
+    gtk_widget_set_size_request (_sat_details_panel, 300, 300);
+    /* sat details info */
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+            _sat_details_panel,
+            label = gtk_label_new(_("Satellites details")));
+    g_signal_connect (G_OBJECT (_sat_details_panel), "expose_event",
+                        G_CALLBACK (sat_details_panel_expose), NULL);
 
-    /* _gc_mark is used to draw the mark when data is current. */
-    _gc_mark = gdk_gc_new(_map_pixmap);
-    gdk_gc_set_foreground(_gc_mark, &_color_mark);
-    gdk_gc_set_line_attributes(_gc_mark,
-            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Latitude")),
+            0, 1, 0, 1, GTK_EXPAND | GTK_FILL, 0, 20, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            _sdi_lat = gtk_label_new(" --- "),
+            1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(_sdi_lat), 0.f, 0.5f);
 
-    /* _gc_mark_old is used to draw the mark when data is old. */
-    _gc_mark_old = gdk_gc_new(_map_pixmap);
-    gdk_gc_set_foreground(_gc_mark_old, &_color_mark_old);
-    gdk_gc_set_line_attributes(_gc_mark_old,
-            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Longitude")),
+            0, 1, 1, 2, GTK_EXPAND | GTK_FILL, 0, 20, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            _sdi_lon = gtk_label_new(" --- "),
+            1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(_sdi_lon), 0.f, 0.5f);
 
-    /* _gc_mark_velocity is used to draw the vel_current line. */
-    _gc_mark_velocity = gdk_gc_new(_map_pixmap);
-    gdk_gc_set_foreground(_gc_mark_velocity, &_color_mark_velocity);
-    gdk_gc_set_line_attributes(_gc_mark_velocity,
-            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Speed")),
+            0, 1, 2, 3, GTK_EXPAND | GTK_FILL, 0, 20, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            _sdi_spd = gtk_label_new(" --- "),
+            1, 2, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(_sdi_spd), 0.f, 0.5f);
 
-    /* _gc_track is used to draw the track line. */
-    _gc_track = gdk_gc_new(_map_pixmap);
-    gdk_gc_set_foreground(_gc_track, &_color_track);
-    gdk_gc_set_line_attributes(_gc_track,
-            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Altitude")),
+            0, 1, 3, 4, GTK_EXPAND | GTK_FILL, 0, 20, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            _sdi_alt = gtk_label_new(" --- "),
+            1, 2, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(_sdi_alt), 0.f, 0.5f);
 
-    /* _gc_track_break is used to draw the track_break dots. */
-    _gc_track_break = gdk_gc_new(_map_pixmap);
-    gdk_gc_set_foreground(_gc_track_break, &_color_track_break);
-    gdk_gc_set_line_attributes(_gc_track_break,
-            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Heading")),
+            0, 1, 4, 5, GTK_EXPAND | GTK_FILL, 0, 20, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            _sdi_hea = gtk_label_new(" --- "),
+            1, 2, 4, 5, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(_sdi_hea), 0.f, 0.5f);
 
-    /* _gc_route is used to draw the route line. */
-    _gc_route = gdk_gc_new(_map_pixmap);
-    gdk_gc_set_foreground(_gc_route, &_color_route);
-    gdk_gc_set_line_attributes(_gc_route,
-            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Local time")),
+            0, 1, 5, 6, GTK_EXPAND | GTK_FILL, 0, 20, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            _sdi_tim = gtk_label_new(" --:--:-- "),
+            1, 2, 5, 6, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(_sdi_tim), 0.f, 0.5f);
 
-    /* _way_gc is used to draw the waypoint dots. */
-    _gc_route_way = gdk_gc_new(_map_pixmap);
-    gdk_gc_set_foreground(_gc_route_way, &_color_route_way);
-    gdk_gc_set_line_attributes(_gc_route_way,
-            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Sat in view")),
+            2, 3, 0, 1, GTK_EXPAND | GTK_FILL, 0, 20, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            _sdi_vie = gtk_label_new("0"),
+            3, 4, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(_sdi_vie), 0.f, 0.5f);
 
-    /* _gc_route_nextway is used to draw the next_way labels. */
-    _gc_route_nextway = gdk_gc_new(_map_pixmap);
-    gdk_gc_set_foreground(_gc_route_nextway, &_color_route_nextway);
-    gdk_gc_set_line_attributes(_gc_route_nextway,
-            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Sat in use")),
+            2, 3, 1, 2, GTK_EXPAND | GTK_FILL, 0, 20, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            _sdi_use = gtk_label_new("0"),
+            3, 4, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(_sdi_use), 0.f, 0.5f);
 
-    /* _gc_poi is used to draw the default POI icon. */
-    _gc_poi = gdk_gc_new(_map_pixmap);
-    gdk_gc_set_foreground(_gc_poi, &_color_poi);
-    gdk_gc_set_background(_gc_poi, &_color_poi);
-    gdk_gc_set_line_attributes(_gc_poi,
-            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Fix")),
+            2, 3, 2, 3, GTK_EXPAND | GTK_FILL, 0, 20, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            _sdi_fix = gtk_label_new(_("nofix")),
+            3, 4, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(_sdi_fix), 0.f, 0.5f);
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Fix Quality")),
+            2, 3, 3, 4, GTK_EXPAND | GTK_FILL, 0, 20, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            _sdi_fqu = gtk_label_new(_("none")),
+            3, 4, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(_sdi_fix), 0.f, 0.5f);
 
-/**
- * Save all configuration data to GCONF.
- */
-static void
-config_save()
-{
-    GConfClient *gconf_client = gconf_client_get_default();
-    gchar buffer[16];
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Max speed")),
+            2, 3, 5, 6, GTK_EXPAND | GTK_FILL, 0, 20, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            _sdi_msp = gtk_label_new(" --- "),
+            3, 4, 5, 6, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(_sdi_msp), 0.f, 0.5f);
 
-    if(!gconf_client)
+    gtk_widget_show_all(dialog);
+    _satdetails_on = TRUE;
+    gps_display_details();
+    while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
     {
-        popup_error(_window,
-                _("Failed to initialize GConf.  Settings were not saved."));
-        return;
+        _satdetails_on = FALSE;
+        break;
     }
+    gtk_widget_destroy(dialog);
 
-    /* Save Receiver MAC from GConf. */
-    if(_rcvr_mac)
-        gconf_client_set_string(gconf_client,
-                GCONF_KEY_RCVR_MAC, _rcvr_mac, NULL);
-    else
-        gconf_client_unset(gconf_client,
-                GCONF_KEY_RCVR_MAC, NULL);
-
-    /* Save Receiver Channel to GConf. */
-    gconf_client_set_int(gconf_client,
-            GCONF_KEY_RCVR_CHAN, _rcvr_addr.rc_channel, NULL);
-
-    /* Save Map Download URI Format. */
-    gconf_client_set_string(gconf_client,
-            GCONF_KEY_MAP_URI_FORMAT, _curr_repo->url, NULL);
-
-    /* Save Map Download Zoom Steps. */
-    gconf_client_set_int(gconf_client,
-            GCONF_KEY_MAP_ZOOM_STEPS, _curr_repo->dl_zoom_steps, NULL);
-
-    /* Save Map Cache Directory. */
-    if(_curr_repo->cache_dir)
-        gconf_client_set_string(gconf_client,
-            GCONF_KEY_MAP_DIR_NAME, _curr_repo->cache_dir, NULL);
-
-    /* Save Auto-Download. */
-    gconf_client_set_bool(gconf_client,
-            GCONF_KEY_AUTO_DOWNLOAD, _auto_download, NULL);
-
-    /* Save Auto-Center Sensitivity. */
-    gconf_client_set_int(gconf_client,
-            GCONF_KEY_CENTER_SENSITIVITY, _center_ratio, NULL);
-
-    /* Save Auto-Center Lead Amount. */
-    gconf_client_set_int(gconf_client,
-            GCONF_KEY_LEAD_AMOUNT, _lead_ratio, NULL);
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
-    /* Save Draw Line Width. */
-    gconf_client_set_int(gconf_client,
-            GCONF_KEY_DRAW_LINE_WIDTH, _draw_line_width, NULL);
+static gfloat
+calculate_distance(gfloat lat1, gfloat lon1, gfloat lat2, gfloat lon2)
+{
+    gfloat dlat, dlon, slat, slon, a;
 
-    /* Save Announce Advance Notice Ratio. */
-    gconf_client_set_int(gconf_client,
-            GCONF_KEY_ANNOUNCE_NOTICE, _announce_notice_ratio, NULL);
+    /* Convert to radians. */
+    lat1 *= (PI / 180.f);
+    lon1 *= (PI / 180.f);
+    lat2 *= (PI / 180.f);
+    lon2 *= (PI / 180.f);
 
-    /* Save Enable Voice flag. */
-    gconf_client_set_bool(gconf_client,
-            GCONF_KEY_ENABLE_VOICE, _enable_voice, NULL);
+    dlat = lat2 - lat1;
+    dlon = lon2 - lon1;
 
-    /* Save Keep On When Fullscreen flag. */
-    gconf_client_set_bool(gconf_client,
-            GCONF_KEY_ALWAYS_KEEP_ON, _always_keep_on, NULL);
+    slat = sinf(dlat / 2.f);
+    slon = sinf(dlon / 2.f);
+    a = (slat * slat) + (cosf(lat1) * cosf(lat2) * slon * slon);
 
-    /* Save Units. */
-    gconf_client_set_string(gconf_client,
-            GCONF_KEY_UNITS, UNITS_TEXT[_units], NULL);
+    return ((2.f * atan2f(sqrtf(a), sqrtf(1.f - a))) * EARTH_RADIUS)
+        * UNITS_CONVERT[_units];
+}
 
-    /* Save Escape Key Function. */
-    gconf_client_set_string(gconf_client,
-            GCONF_KEY_ESCAPE_KEY, ESCAPE_KEY_TEXT[_escape_key], NULL);
+static void
+db_connect()
+{
+    gchar buffer[100];
+    gchar *perror;
+    gchar **pszResult;
+    guint nRow, nColumn;
 
-    /* Save last saved latitude. */
-    gconf_client_set_float(gconf_client,
-            GCONF_KEY_LAT, _pos_lat, NULL);
+    _dbconn = FALSE;
 
-    /* Save last saved longitude. */
-    gconf_client_set_float(gconf_client,
-            GCONF_KEY_LON, _pos_lon, NULL);
+    if(!_poi_db)
+        return;
 
-    /* Save last center point. */
+    if(NULL == (_db = sqlite_open(_poi_db, 0666, &perror)))
     {
-        gfloat center_lat, center_lon;
-        unit2latlon(_center.unitx, _center.unity, center_lat, center_lon);
-
-        /* Save last center latitude. */
-        gconf_client_set_float(gconf_client,
-                GCONF_KEY_CENTER_LAT, center_lat, NULL);
+        gchar buffer2[200];
+        sprintf(buffer2, "%s: %s", _("Problem with POI database"), perror);
+        popup_error(_window, buffer2);
+        g_free(perror);
+        return;
+    }
 
-        /* Save last center longitude. */
-        gconf_client_set_float(gconf_client,
-                GCONF_KEY_CENTER_LON, center_lon, NULL);
+    if(SQLITE_OK != sqlite_get_table(_db, "select label from poi limit 1",
+        &pszResult, &nRow, &nColumn, NULL))
+    {
+        if(SQLITE_OK != sqlite_exec(_db,
+                /* Create the necessary tables... */
+                "create table poi (poi_id integer PRIMARY KEY, lat real, "
+                "lon real, label text, desc text, cat_id integer);"
+                "create table category (cat_id integer PRIMARY KEY,"
+                "label text, desc text, enabled integer);"
+                /* Add some default categories... */
+                "insert into category (label, desc, enabled) "
+                "values ('Fuel',"
+                  "'Stations for purchasing fuel for vehicles.', 1);"
+                "insert into category (label, desc, enabled) "
+                "values ('Residence', "
+                  "'Houses, apartments, or other residences of import.', 1);"
+                "insert into category (label, desc, enabled) "
+                "values ('Dining', "
+                  "'Places to eat or drink.', 1);"
+                "insert into category (label, desc, enabled) "
+                "values ('Shopping/Services', "
+                  "'Places to shop or acquire services.', 1);"
+                "insert into category (label, desc, enabled) "
+                "values ('Recreation', "
+                  "'Indoor or Outdoor places to have fun.', 1);"
+                "insert into category (label, desc, enabled) "
+                "values ('Transportation', "
+                  "'Bus stops, airports, train stations, etc.', 1);"
+                "insert into category (label, desc, enabled) "
+                "values ('Lodging', "
+                  "'Places to stay temporarily or for the night.', 1);"
+                "insert into category (label, desc, enabled) "
+                "values ('School', "
+                  "'Elementary schools, college campuses, etc.', 1);"
+                "insert into category (label, desc, enabled) "
+                "values ('Business', "
+                  "'General places of business.', 1);"
+                "insert into category (label, desc, enabled) "
+                "values ('Landmark', "
+                  "'General landmarks.', 1);"
+                "insert into category (label, desc, enabled) "
+                "values ('Other', "
+                  "'Miscellaneous category for everything else.', 1);",
+                NULL,
+                NULL,
+                &perror)
+                && (SQLITE_OK != sqlite_get_table(_db,
+                            "select label from poi limit 1",
+                            &pszResult, &nRow, &nColumn, NULL)))
+        {
+            sprintf(buffer, _("Failed to open or create database:\n%s"),
+                    _poi_db);
+            popup_error(_window, buffer);
+            sqlite_close(_db);
+            return;
+        }
     }
+    else
+        sqlite_free_table(pszResult);
 
-    /* Save last Zoom Level. */
-    gconf_client_set_int(gconf_client,
-            GCONF_KEY_ZOOM, _zoom, NULL);
+    _dbconn = TRUE;
+}
 
-    /* Save Route Directory. */
-    if(_route_dir_uri)
-        gconf_client_set_string(gconf_client,
-                GCONF_KEY_ROUTEDIR, _route_dir_uri, NULL);
+/**
+ * Set the connection state.  This function controls all connection-related
+ * banners.
+ */
+static void
+set_conn_state(ConnState new_conn_state)
+{
+    printf("%s(%d)\n", __PRETTY_FUNCTION__, new_conn_state);
 
-    /* Save the repositories. */
+    switch(_conn_state = new_conn_state)
     {
-        GList *curr = _repo_list;
-        GSList *temp_list = NULL;
-        gint curr_repo_index = 0;
-
-        for(curr = _repo_list; curr != NULL; curr = curr->next)
-        {
-            /* Build from each part of a repo, delimited by newline characters:
-             * 1. url
-             * 2. cache_dir
-             * 3. dl_zoom_steps
-             * 4. view_zoom_steps
-             */
-            RepoData *rd = curr->data;
-            gchar buffer[1024];
-            sprintf(buffer, "%s\n%s\n%s\n%d\n%d\n",
-                    rd->name,
-                    rd->url,
-                    rd->cache_dir,
-                    rd->dl_zoom_steps,
-                    rd->view_zoom_steps);
-            temp_list = g_slist_append(temp_list, g_strdup(buffer));
-            if(rd == _curr_repo)
-                gconf_client_set_int(gconf_client,
-                        GCONF_KEY_CURRREPO, curr_repo_index, NULL);
-            curr_repo_index++;
-        }
-        gconf_client_set_list(gconf_client,
-                GCONF_KEY_REPOSITORIES, GCONF_VALUE_STRING, temp_list, NULL);
+        case RCVR_OFF:
+        case RCVR_FIXED:
+            if(_connect_banner)
+            {
+                gtk_widget_destroy(_connect_banner);
+                _connect_banner = NULL;
+            }
+            if(_fix_banner)
+            {
+                gtk_widget_destroy(_fix_banner);
+                _fix_banner = NULL;
+            }
+            break;
+        case RCVR_DOWN:
+            if(_fix_banner)
+            {
+                gtk_widget_destroy(_fix_banner);
+                _fix_banner = NULL;
+            }
+            if(!_connect_banner)
+                _connect_banner = hildon_banner_show_animation(
+                        _window, NULL, _("Searching for GPS receiver"));
+            break;
+        case RCVR_UP:
+            if(_connect_banner)
+            {
+                gtk_widget_destroy(_connect_banner);
+                _connect_banner = NULL;
+            }
+            if(!_fix_banner)
+                _fix_banner = hildon_banner_show_progress(
+                        _window, NULL, _("Establishing GPS fix"));
+            break;
+        default: ; /* to quell warning. */
     }
 
-    /* Save Last Track File. */
-    if(_track_file_uri)
-        gconf_client_set_string(gconf_client,
-                GCONF_KEY_TRACKFILE, _track_file_uri, NULL);
-
-    /* Save Auto-Center Mode. */
-    gconf_client_set_int(gconf_client,
-            GCONF_KEY_AUTOCENTER_MODE, _center_mode, NULL);
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
-    /* Save Show Tracks flag. */
-    gconf_client_set_bool(gconf_client,
-            GCONF_KEY_SHOWTRACKS, _show_tracks & TRACKS_MASK, NULL);
+/**
+ * Updates _near_point, _next_way, and _next_wpt.  If quick is FALSE (as
+ * it is when this function is called from route_find_nearest_point), then
+ * the entire list (starting from _near_point) is searched.  Otherwise, we
+ * stop searching when we find a point that is farther away.
+ */
+static gboolean
+route_update_nears(gboolean quick)
+{
+    gboolean ret = FALSE;
+    Point *curr, *near;
+    WayPoint *wcurr, *wnext;
+    guint near_dist_rough;
+    printf("%s(%d)\n", __PRETTY_FUNCTION__, quick);
 
-    /* Save Show Routes flag. */
-    gconf_client_set_bool(gconf_client,
-            GCONF_KEY_SHOWROUTES, _show_tracks & ROUTES_MASK, NULL);
+    /* If we have waypoints (_next_way != NULL), then determine the "next
+     * waypoint", which is defined as the waypoint after the nearest point,
+     * UNLESS we've passed that waypoint, in which case the waypoint after
+     * that waypoint becomes the "next" waypoint. */
+    if(_next_way)
+    {
+        /* First, set near_dist_rough with the new distance from _near_point. */
+        near = _near_point;
+        near_dist_rough = DISTANCE_ROUGH(_pos, *near);
 
-    /* Save Show Velocity Vector flag. */
-    gconf_client_set_bool(gconf_client,
-            GCONF_KEY_SHOWVELVEC, _show_velvec, NULL);
+        /* Now, search _route for a closer point.  If quick is TRUE, then we'll
+         * only search forward, only as long as we keep finding closer points.
+         */
+        for(curr = _near_point; curr++ != _route.tail; )
+        {
+            if(curr->unity)
+            {
+                guint dist_rough = DISTANCE_ROUGH(_pos, *curr);
+                if(dist_rough <= near_dist_rough)
+                {
+                    near = curr;
+                    near_dist_rough = dist_rough;
+                }
+                else if(quick)
+                    break;
+            }
+        }
 
-    /* Save Enable GPS flag. */
-    gconf_client_set_bool(gconf_client,
-            GCONF_KEY_ENABLE_GPS, _enable_gps, NULL);
+        /* Update _near_point. */
+        _near_point = near;
+        _near_point_dist_rough = near_dist_rough;
 
-    /* Save Route Locations. */
-    gconf_client_set_list(gconf_client,
-            GCONF_KEY_ROUTE_LOCATIONS, GCONF_VALUE_STRING, _loc_list, NULL);
+        for(wnext = wcurr = _next_way; wcurr != _route.wtail; wcurr++)
+        {
+            if(wcurr->point < near
+            /* Okay, this else if expression warrants explanation.  If the
+             * nearest track point happens to be a waypoint, then we want to
+             * check if we have "passed" that waypoint.  To check this, we
+             * test the distance from _pos to the waypoint and from _pos to
+             * _next_wpt, and if the former is increasing and the latter is
+             * decreasing, then we have passed the waypoint, and thus we
+             * should skip it.  Note that if there is no _next_wpt, then
+             * there is no next waypoint, so we do not skip it in that case. */
+                || (wcurr->point == near && quick
+                    && (_next_wpt
+                     && (DISTANCE_ROUGH(_pos, *near) > _next_way_dist_rough
+                      && DISTANCE_ROUGH(_pos, *_next_wpt)
+                                                     < _next_wpt_dist_rough))))
+                wnext = wcurr + 1;
+            else
+                break;
+        }
 
-    /* Save GPS Info flag. */
-    gconf_client_set_bool(gconf_client,
-            GCONF_KEY_GPS_INFO, _gps_info, NULL);
+        if(wnext == _route.wtail && (wnext->point < near
+                || (wnext->point == near && quick
+                    && (!_next_wpt
+                     || (DISTANCE_ROUGH(_pos, *near) > _next_way_dist_rough
+                      &&DISTANCE_ROUGH(_pos, *_next_wpt)
+                                                     < _next_wpt_dist_rough)))))
+        {
+            _next_way = NULL;
+            _next_wpt = NULL;
+            _next_way_dist_rough = -1;
+            _next_wpt_dist_rough = -1;
+            ret = TRUE;
+        }
+        /* Only update _next_way (and consequently _next_wpt) if _next_way is
+         * different, and record that fact for return. */
+        else
+        {
+            if(!quick || _next_way != wnext)
+            {
+                _next_way = wnext;
+                _next_wpt = wnext->point;
+                if(_next_wpt == _route.tail)
+                    _next_wpt = NULL;
+                else
+                {
+                    while(!(++_next_wpt)->unity)
+                    {
+                        if(_next_wpt == _route.tail)
+                        {
+                            _next_wpt = NULL;
+                            break;
+                        }
+                    }
+                }
+                ret = TRUE;
+            }
+            _next_way_dist_rough = DISTANCE_ROUGH(_pos, *wnext->point);
+            if(_next_wpt)
+                _next_wpt_dist_rough = DISTANCE_ROUGH(_pos, *_next_wpt);
+        }
+    }
 
-    /* Save Colors. */
-    sprintf(buffer, "#%02x%02x%02x",
-            _color_mark.red >> 8,
-            _color_mark.green >> 8,
-            _color_mark.blue >> 8);
-    gconf_client_set_string(gconf_client,
-            GCONF_KEY_COLOR_MARK, buffer, NULL);
+    vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, ret);
+    return ret;
+}
 
-    sprintf(buffer, "#%02x%02x%02x",
-            _color_mark_velocity.red >> 8,
-            _color_mark_velocity.green >> 8,
-            _color_mark_velocity.blue >> 8);
-    gconf_client_set_string(gconf_client,
-            GCONF_KEY_COLOR_MARK_VELOCITY, buffer, NULL);
+/**
+ * Reset the _near_point data by searching the entire route for the nearest
+ * route point and waypoint.
+ */
+static void
+route_find_nearest_point()
+{
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    sprintf(buffer, "#%02x%02x%02x",
-            _color_mark_old.red >> 8,
-            _color_mark_old.green >> 8,
-            _color_mark_old.blue >> 8);
-    gconf_client_set_string(gconf_client,
-            GCONF_KEY_COLOR_MARK_OLD, buffer, NULL);
+    /* Initialize _near_point. */
+    _near_point = _route.head;
+    while(!_near_point->unity && _near_point != _route.tail)
+        _near_point++;
 
-    sprintf(buffer, "#%02x%02x%02x",
-            _color_track.red >> 8,
-            _color_track.green >> 8,
-            _color_track.blue >> 8);
-    gconf_client_set_string(gconf_client,
-            GCONF_KEY_COLOR_TRACK, buffer, NULL);
+    /* Initialize _next_way. */
+    if(_route.wtail == _route.whead - 1
+            || (_autoroute_data.enabled && _route.wtail == _route.whead))
+        _next_way = NULL;
+    else
+        /* We have at least one waypoint. */
+        _next_way = (_autoroute_data.enabled ? _route.whead + 1 : _route.whead);
+    _next_way_dist_rough = -1;
 
-    sprintf(buffer, "#%02x%02x%02x",
-            _color_track_break.red >> 8,
-            _color_track_break.green >> 8,
-            _color_track_break.blue >> 8);
-    gconf_client_set_string(gconf_client,
-            GCONF_KEY_COLOR_TRACK_BREAK, buffer, NULL);
+    /* Initialize _next_wpt. */
+    _next_wpt = NULL;
+    _next_wpt_dist_rough = -1;
 
-    sprintf(buffer, "#%02x%02x%02x",
-            _color_route.red >> 8,
-            _color_route.green >> 8,
-            _color_route.blue >> 8);
-    gconf_client_set_string(gconf_client,
-            GCONF_KEY_COLOR_ROUTE, buffer, NULL);
+    route_update_nears(FALSE);
 
-    sprintf(buffer, "#%02x%02x%02x",
-            _color_route_way.red >> 8,
-            _color_route_way.green >> 8,
-            _color_route_way.blue >> 8);
-    gconf_client_set_string(gconf_client,
-            GCONF_KEY_COLOR_ROUTE_WAY, buffer, NULL);
-
-    sprintf(buffer, "#%02x%02x%02x",
-            _color_route_nextway.red >> 8,
-            _color_route_nextway.green >> 8,
-            _color_route_nextway.blue >> 8);
-    gconf_client_set_string(gconf_client,
-            GCONF_KEY_COLOR_ROUTE_NEXTWAY, buffer, NULL);
-
-    sprintf(buffer, "#%02x%02x%02x",
-            _color_poi.red >> 8,
-            _color_poi.green >> 8,
-            _color_poi.blue >> 8);
-    gconf_client_set_string(gconf_client,
-            GCONF_KEY_COLOR_POI, buffer, NULL);
-
-    /* Save POI database. */
-    if(_poi_db)
-        gconf_client_set_string(gconf_client,
-                GCONF_KEY_POI_DB, _poi_db, NULL);
-    else
-        gconf_client_unset(gconf_client, GCONF_KEY_POI_DB, NULL);
-
-   /* Save Show POI below zoom. */
-    gconf_client_set_int(gconf_client,
-            GCONF_KEY_POI_ZOOM, _poi_zoom, NULL);
-
-    g_object_unref(gconf_client);
-
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
+/**
+ * Render a single track line to _map_pixmap.  If either point on the line
+ * is a break (defined as unity == 0), a circle is drawn at the other point.
+ * IT IS AN ERROR FOR BOTH POINTS TO INDICATE A BREAK.
+ */
 static void
-force_min_visible_bars(HildonControlbar *control_bar, gint num_bars)
-{
-    GValue val;
-    memset(&val, 0, sizeof(val));
-    g_value_init(&val, G_TYPE_INT);
-    g_value_set_int(&val, num_bars);
-    g_object_set_property(G_OBJECT(control_bar), "minimum-visible-bars", &val);
-}
-
-
-typedef struct _ScanInfo ScanInfo;
-struct _ScanInfo {
-    GtkWidget *settings_dialog;
-    GtkWidget *txt_rcvr_mac;
-    GtkWidget *scan_dialog;
-    GtkWidget *banner;
-    GtkListStore *store;
-    guint sid;
-};
-
-static gboolean
-scan_bluetooth_idle(ScanInfo *scan_info)
+map_render_segment(GdkGC *gc_norm, GdkGC *gc_alt,
+        guint unitx1, guint unity1, guint unitx2, guint unity2)
 {
-    gint devid, num_rsp;
-    GtkTreeIter iter;
-    inquiry_info *ii = NULL;
-
-    devid = hci_get_route(NULL);
-
-    ii = (inquiry_info*)malloc(255 * sizeof(inquiry_info));
-    num_rsp = hci_inquiry(devid, 4, 255, NULL, &ii, IREQ_CACHE_FLUSH);
+    vprintf("%s()\n", __PRETTY_FUNCTION__);
 
-    if(num_rsp < 0)
+    if(!unity1)
     {
-        gtk_widget_destroy(scan_info->banner);
-        gtk_widget_hide(scan_info->scan_dialog);
-        popup_error(scan_info->settings_dialog,
-                _("An error occurred while scanning."));
+        guint x2, y2;
+        x2 = unit2bufx(unitx2);
+        y2 = unit2bufy(unity2);
+        /* Make sure this circle will be visible. */
+        if((x2 < BUF_WIDTH_PIXELS)
+                && (y2 < BUF_HEIGHT_PIXELS))
+            gdk_draw_arc(_map_pixmap, gc_alt,
+                    FALSE, /* FALSE: not filled. */
+                    x2 - _draw_line_width,
+                    y2 - _draw_line_width,
+                    2 * _draw_line_width,
+                    2 * _draw_line_width,
+                    0, /* start at 0 degrees. */
+                    360 * 64);
     }
-    else if(num_rsp == 0)
+    else if(!unity2)
     {
-        gtk_widget_destroy(scan_info->banner);
-        gtk_widget_hide(scan_info->scan_dialog);
-        popup_error(scan_info->settings_dialog,
-                _("No bluetooth devices found."));
+        guint x1, y1;
+        x1 = unit2bufx(unitx1);
+        y1 = unit2bufy(unity1);
+        /* Make sure this circle will be visible. */
+        if((x1 < BUF_WIDTH_PIXELS)
+                && ((unsigned)y1 < BUF_HEIGHT_PIXELS))
+            gdk_draw_arc(_map_pixmap, gc_alt,
+                    FALSE, /* FALSE: not filled. */
+                    x1 - _draw_line_width,
+                    y1 - _draw_line_width,
+                    2 * _draw_line_width,
+                    2 * _draw_line_width,
+                    0, /* start at 0 degrees. */
+                    360 * 64);
     }
     else
     {
-        guint i;
-        gint sock = hci_open_dev(devid);
-        for(i = 0; i < num_rsp; i++)
-        {
-            gchar addr[19] = { 0 };
-            gchar name[256] = { 0 };
-
-            ba2str(&ii[i].bdaddr, addr);
-            memset(name, 0, sizeof(name));
-            if(hci_read_remote_name(sock, &ii[i].bdaddr, sizeof(name), name, 0))
-                strcpy(name, _("Unknown"));
-
-            gtk_list_store_append(scan_info->store, &iter);
-            gtk_list_store_set(scan_info->store, &iter,
-                    0, g_strdup(addr),
-                    1, g_strdup(name),
-                    -1);
-        }
-        close(sock);
-        gtk_widget_destroy(scan_info->banner);
+        gint x1, y1, x2, y2;
+        x1 = unit2bufx(unitx1);
+        y1 = unit2bufy(unity1);
+        x2 = unit2bufx(unitx2);
+        y2 = unit2bufy(unity2);
+        /* Make sure this line could possibly be visible. */
+        if(!((x1 > BUF_WIDTH_PIXELS && x2 > BUF_WIDTH_PIXELS)
+                || (x1 < 0 && x2 < 0)
+                || (y1 > BUF_HEIGHT_PIXELS && y2 > BUF_HEIGHT_PIXELS)
+                || (y1 < 0 && y2 < 0)))
+            gdk_draw_line(_map_pixmap, gc_norm, x1, y1, x2, y2);
     }
-    free(ii);
-    scan_info->sid = 0;
-    return FALSE;
+
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
 }
 
 /**
- * Scan for all bluetooth devices.  This method can take a few seconds,
- * during which the UI will freeze.
+ * Render all track data onto the _map_pixmap.  Note that this does not
+ * clear the pixmap of previous track data (use map_force_redraw() for
+ * that), and also note that this method does not queue any redraws, so it
+ * is up to the caller to decide which part of the track really needs to be
+ * redrawn.
  */
-static gboolean
-scan_bluetooth(GtkWidget *widget, ScanInfo *scan_info)
+static void
+map_render_track()
 {
-    /* Do an hci_inquiry for our boy. */
-    GtkWidget *dialog;
-    GtkWidget *lst_devices;
-    GtkTreeViewColumn *column;
-    GtkCellRenderer *renderer;
+    TrackPoint *curr;
     printf("%s()\n", __PRETTY_FUNCTION__);
 
-    dialog = gtk_dialog_new_with_buttons(_("Select Bluetooth Device"),
-            GTK_WINDOW(scan_info->settings_dialog), GTK_DIALOG_MODAL,
-            GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
-            GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
-            NULL);
-
-    scan_info->scan_dialog = dialog;
-
-    scan_info->banner = hildon_banner_show_animation(dialog, NULL,
-            _("Scanning Bluetooth Devices"));
-
-    scan_info->store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
-
-    scan_info->sid = g_idle_add((GSourceFunc)scan_bluetooth_idle, scan_info);
-
-    gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300);
-
-    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
-            lst_devices = gtk_tree_view_new_with_model(
-                GTK_TREE_MODEL(scan_info->store)), TRUE, TRUE, 0);
-
-    g_object_unref(G_OBJECT(scan_info->store));
-
-    gtk_tree_selection_set_mode(
-            gtk_tree_view_get_selection(GTK_TREE_VIEW(lst_devices)),
-            GTK_SELECTION_SINGLE);
-    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(lst_devices), TRUE);
-
-    renderer = gtk_cell_renderer_text_new();
-    column = gtk_tree_view_column_new_with_attributes(
-            _("MAC"), renderer, "text", 0);
-    gtk_tree_view_append_column(GTK_TREE_VIEW(lst_devices), column);
+    for(curr = _track.head; curr != _track.tail; curr++)
+        map_render_segment(_gc_track, _gc_track_break,
+                curr->point.unitx, curr->point.unity,
+                curr[1].point.unitx, curr[1].point.unity);
 
-    renderer = gtk_cell_renderer_text_new();
-    column = gtk_tree_view_column_new_with_attributes(
-            _("Description"), renderer, "text", 1);
-    gtk_tree_view_append_column(GTK_TREE_VIEW(lst_devices), column);
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
-    gtk_widget_show_all(dialog);
+/**
+ * Render all track data onto the _map_pixmap.  Note that this does not
+ * clear the pixmap of previous track data (use map_force_redraw() for
+ * that), and also note that this method does not queue any redraws, so it
+ * is up to the caller to decide which part of the track really needs to be
+ * redrawn.
+ */
+static void
+map_render_route()
+{
+    Point *curr;
+    WayPoint *wcurr;
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
+    _visible_way_first = _visible_way_last = NULL;
+    for(curr = _route.head, wcurr = _route.whead; curr != _route.tail; curr++)
     {
-        GtkTreeIter iter;
-        if(gtk_tree_selection_get_selected(
-                    gtk_tree_view_get_selection(GTK_TREE_VIEW(lst_devices)),
-                    NULL, &iter))
+        if(wcurr && wcurr <= _route.wtail && curr == wcurr->point)
         {
-            gchar *mac;
-            gtk_tree_model_get(GTK_TREE_MODEL(scan_info->store),
-                    &iter, 0, &mac, -1);
-            gtk_entry_set_text(GTK_ENTRY(scan_info->txt_rcvr_mac), mac);
-            break;
+            guint x1 = unit2bufx(wcurr->point->unitx);
+            guint y1 = unit2bufy(wcurr->point->unity);
+            if((x1 < BUF_WIDTH_PIXELS)
+                    && (y1 < BUF_HEIGHT_PIXELS))
+            {
+                gdk_draw_arc(_map_pixmap,
+                        (wcurr==_next_way ? _gc_route_nextway : _gc_route_way),
+                        FALSE, /* FALSE: not filled. */
+                        x1 - _draw_line_width,
+                        y1 - _draw_line_width,
+                        2 * _draw_line_width,
+                        2 * _draw_line_width,
+                        0, /* start at 0 degrees. */
+                        360 * 64);
+                if(!_visible_way_first)
+                    _visible_way_first = wcurr;
+                _visible_way_last = wcurr;
+            }
+            wcurr++;
+            if(!curr[1].unity)
+                continue;
         }
-        else
-            popup_error(dialog,
-                    _("Please select a bluetooth device from the list."));
+        map_render_segment(_gc_route, _gc_route_way,
+                curr->unitx, curr->unity, curr[1].unitx, curr[1].unity);
     }
 
-    if(scan_info->sid)
-        g_source_remove(scan_info->sid);
-    gtk_widget_destroy(dialog);
-
-    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
-    return TRUE;
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
 }
 
-typedef struct _BrowseInfo BrowseInfo;
-struct _BrowseInfo {
-    GtkWidget *dialog;
-    GtkWidget *txt;
-};
-
-static gboolean
-settings_dialog_browse_forfile(GtkWidget *widget, BrowseInfo *browse_info)
+static void
+map_render_paths()
 {
-    GtkWidget *dialog;
     printf("%s()\n", __PRETTY_FUNCTION__);
 
-    dialog = GTK_WIDGET(
-            hildon_file_chooser_dialog_new(GTK_WINDOW(browse_info->dialog),
-            GTK_FILE_CHOOSER_ACTION_OPEN));
+    if((_show_tracks & ROUTES_MASK) && _route.head)
+    {
+        map_render_route();
+        if(_next_way == NULL)
+        {
+            guint x1 = unit2bufx(_route.tail[-1].unitx);
+            guint y1 = unit2bufy(_route.tail[-1].unity);
+            if((x1 < BUF_WIDTH_PIXELS)
+                    && (y1 < BUF_HEIGHT_PIXELS))
+            {
+                gdk_draw_arc(_map_pixmap,
+                        _gc_route_nextway,
+                        FALSE, /* FALSE: not filled. */
+                        x1 - _draw_line_width,
+                        y1 - _draw_line_width,
+                        2 * _draw_line_width,
+                        2 * _draw_line_width,
+                        0, /* start at 0 degrees. */
+                        360 * 64);
+            }
+        }
+    }
+    if(_show_tracks & TRACKS_MASK)
+        map_render_track();
 
-    gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dialog), TRUE);
-    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
-            gtk_entry_get_text(GTK_ENTRY(browse_info->txt)));
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
-    if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(dialog)))
+/**
+ * Add a point to the _track list.  This function is slightly overloaded,
+ * since it is what houses the check for "have we moved
+ * significantly": it also initiates the re-calculation of the _near_point
+ * data, as well as calling osso_display_state_on() when we have the focus.
+ *
+ * If a non-zero time is given, then the current position (as taken from the
+ * _pos variable) is appended to _track with the given time.  If time is zero,
+ * then _pos_null is appended to _track with time zero (this produces a "break"
+ * in the track).
+ */
+static void
+track_add(time_t time, gboolean newly_fixed)
+{
+    Point pos = (time == 0 ? _pos_null : _pos);
+    printf("%s(%u, %u)\n", __PRETTY_FUNCTION__, pos.unitx, pos.unity);
+
+    if(abs((gint)pos.unitx - _track.tail->point.unitx) > _draw_line_width
+    || abs((gint)pos.unity - _track.tail->point.unity) > _draw_line_width)
     {
-        gchar *filename = gtk_file_chooser_get_filename(
-                GTK_FILE_CHOOSER(dialog));
-        gtk_entry_set_text(GTK_ENTRY(browse_info->txt), filename);
-        g_free(filename);
-    }
+        if(time && _route.head
+                && (newly_fixed ? (route_find_nearest_point(), TRUE)
+                                : route_update_nears(TRUE)))
+        {
+            map_render_paths();
+            MACRO_QUEUE_DRAW_AREA();
+        }
+        if(_show_tracks & TRACKS_MASK)
+        {
+            /* Instead of calling map_render_paths(), we'll draw the new line
+             * ourselves and call gtk_widget_queue_draw_area(). */
+            gint tx1, ty1, tx2, ty2;
+            map_render_segment(_gc_track, _gc_track_break,
+                    _track.tail->point.unitx, _track.tail->point.unity,
+                    pos.unitx, pos.unity);
+            if(time && _track.tail->point.unity)
+            {
+                tx1 = unit2x(_track.tail->point.unitx);
+                ty1 = unit2y(_track.tail->point.unity);
+                tx2 = unit2x(pos.unitx);
+                ty2 = unit2y(pos.unity);
+                gtk_widget_queue_draw_area(_map_widget,
+                        MIN(tx1, tx2) - _draw_line_width,
+                        MIN(ty1, ty2) - _draw_line_width,
+                        abs(tx1 - tx2) + (2 * _draw_line_width),
+                        abs(ty1 - ty2) + (2 * _draw_line_width));
+            }
+        }
+        MACRO_TRACK_INCREMENT_TAIL(_track);
 
-    gtk_widget_destroy(dialog);
+        _track.tail->point = pos;
+        _track.tail->time = time;
 
-    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
-    return TRUE;
-}
+        if(_autoroute_data.enabled && !_autoroute_data.in_progress
+                && _near_point_dist_rough > 400)
+        {
+            _autoroute_data.in_progress = TRUE;
+            g_idle_add((GSourceFunc)auto_route_dl_idle, NULL);
+        }
 
+        /* Keep the display on. */
+        KEEP_DISPLAY_ON();
+    }
 
-typedef struct _ColorsDialogInfo ColorsDialogInfo;
-struct _ColorsDialogInfo {
-    GtkWidget *col_mark;
-    GtkWidget *col_mark_velocity;
-    GtkWidget *col_mark_old;
-    GtkWidget *col_track;
-    GtkWidget *col_track_break;
-    GtkWidget *col_route;
-    GtkWidget *col_route_way;
-    GtkWidget *col_route_nextway;
-    GtkWidget *col_poi;
-};
+    /* Check if we should announce upcoming waypoints. */
+    if(time && _next_way_dist_rough
+            < (20 + (guint)_speed) * _announce_notice_ratio * 3)
+    {
+        if(_enable_voice && strcmp(_next_way->desc, _last_spoken_phrase))
+        {
+            g_free(_last_spoken_phrase);
+            _last_spoken_phrase = g_strdup(_next_way->desc);
+            if(!fork())
+            {
+                /* We are the fork child.  Synthesize the voice. */
+                hildon_play_system_sound(
+                        "/usr/share/sounds/ui-information_note.wav");
+                sleep(1);
+#               define _voice_synth_path "/usr/bin/flite"
+                printf("%s %s\n", _voice_synth_path, _last_spoken_phrase);
+                execl(_voice_synth_path, _voice_synth_path,
+                        "-t", _last_spoken_phrase, (char *)NULL);
+                exit(0);
+            }
+        }
+        hildon_banner_show_information(_window, NULL, _next_way->desc);
+    }
 
-static gboolean
-settings_dialog_colors_reset(GtkWidget *widget, ColorsDialogInfo *cdi)
-{
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi->col_mark),
-            &DEFAULT_COLOR_MARK);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi->col_mark_velocity),
-            &DEFAULT_COLOR_MARK_VELOCITY);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi->col_mark_old),
-            &DEFAULT_COLOR_MARK_OLD);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi->col_track),
-            &DEFAULT_COLOR_TRACK);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi->col_track_break),
-            &DEFAULT_COLOR_TRACK_BREAK);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi->col_route),
-            &DEFAULT_COLOR_ROUTE);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi->col_route_way),
-            &DEFAULT_COLOR_ROUTE_WAY);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi->col_route_nextway),
-            &DEFAULT_COLOR_ROUTE_NEXTWAY);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi->col_poi),
-            &DEFAULT_COLOR_POI);
-    return TRUE;
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
 }
 
-static gboolean
-settings_dialog_colors(GtkWidget *widget, GtkWidget *parent)
+/**
+ * Disconnect from the receiver.  This method cleans up any and everything
+ * that might be associated with the receiver.
+ */
+static void
+rcvr_disconnect()
 {
-    GtkWidget *dialog;
-    GtkWidget *table;
-    GtkWidget *label;
-    GtkWidget *btn_defaults;
-    ColorsDialogInfo cdi;
     printf("%s()\n", __PRETTY_FUNCTION__);
 
-    dialog = gtk_dialog_new_with_buttons(_("Colors"),
-            GTK_WINDOW(parent), GTK_DIALOG_MODAL,
-            GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
-            NULL);
+    /* Remove watches. */
+    if(_clater_sid)
+    {
+        g_source_remove(_clater_sid);
+        _clater_sid = 0;
+    }
+    if(_error_sid)
+    {
+        g_source_remove(_error_sid);
+        _error_sid = 0;
+    }
+    if(_connect_sid)
+    {
+        g_source_remove(_connect_sid);
+        _connect_sid = 0;
+    }
+    if(_input_sid)
+    {
+        g_source_remove(_input_sid);
+        _input_sid = 0;
+    }
 
-    gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
-            btn_defaults = gtk_button_new_with_label(_("Defaults")));
-    g_signal_connect(G_OBJECT(btn_defaults), "clicked",
-                      G_CALLBACK(settings_dialog_colors_reset), &cdi);
+    /* Destroy the GIOChannel object. */
+    if(_channel)
+    {
+        g_io_channel_shutdown(_channel, FALSE, NULL);
+        g_io_channel_unref(_channel);
+        _channel = NULL;
+    }
 
-    gtk_dialog_add_button(GTK_DIALOG(dialog),
-            GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
+    /* Close the file descriptor. */
+    if(_fd != -1)
+    {
+        close(_fd);
+        _fd = -1;
+    }
 
-    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
-            table = gtk_table_new(4, 3, FALSE), TRUE, TRUE, 0);
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
-    /* Mark. */
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("GPS Mark")),
-            0, 1, 0, 1, GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            cdi.col_mark = hildon_color_button_new(),
-            1, 2, 0, 1, 0, 0, 2, 4);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi.col_mark), &_color_mark);
-    gtk_table_attach(GTK_TABLE(table),
-            cdi.col_mark_velocity = hildon_color_button_new(),
-            2, 3, 0, 1, 0, 0, 2, 4);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi.col_mark_velocity), &_color_mark_velocity);
-    gtk_table_attach(GTK_TABLE(table),
-            cdi.col_mark_old = hildon_color_button_new(),
-            3, 4, 0, 1, 0, 0, 2, 4);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi.col_mark_old), &_color_mark_old);
-
-    /* Track. */
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Track")),
-            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),
-            cdi.col_track = hildon_color_button_new(),
-            1, 2, 1, 2, 0, 0, 2, 4);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi.col_track), &_color_track);
-    gtk_table_attach(GTK_TABLE(table),
-            cdi.col_track_break = hildon_color_button_new(),
-            2, 3, 1, 2, 0, 0, 2, 4);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi.col_track_break), &_color_track_break);
-
-    /* Route. */
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Route")),
-            0, 1, 2, 3, GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            cdi.col_route = hildon_color_button_new(),
-            1, 2, 2, 3, 0, 0, 2, 4);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi.col_route), &_color_route);
-    gtk_table_attach(GTK_TABLE(table),
-            cdi.col_route_way = hildon_color_button_new(),
-            2, 3, 2, 3, 0, 0, 2, 4);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi.col_route_way), &_color_route_way);
-    gtk_table_attach(GTK_TABLE(table),
-            cdi.col_route_nextway = hildon_color_button_new(),
-            3, 4, 2, 3, 0, 0, 2, 4);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi.col_route_nextway), &_color_route_nextway);
-
-    /* POI. */
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("POI")),
-            0, 1, 3, 4, GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            cdi.col_poi = hildon_color_button_new(),
-            1, 2, 3, 4, 0, 0, 2, 4);
-    hildon_color_button_set_color(
-            HILDON_COLOR_BUTTON(cdi.col_poi), &_color_poi);
-
-    gtk_widget_show_all(dialog);
+static void rcvr_connect_later(); /* Forward declaration. */
 
-    while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
-    {
-        GdkColor *color;
+/**
+ * Connect to the receiver.
+ * This method assumes that _fd is -1 and _channel is NULL.  If unsure, call
+ * rcvr_disconnect() first.
+ * Since this is an idle function, this function returns whether or not it
+ * should be called again, which is always FALSE.
+ */
+static gboolean
+rcvr_connect_now()
+{
+    printf("%s(%d)\n", __PRETTY_FUNCTION__, _conn_state);
 
-        color = hildon_color_button_get_color(
-                HILDON_COLOR_BUTTON(cdi.col_mark));
-        _color_mark = *color;
+    if(_conn_state == RCVR_DOWN && _rcvr_mac) {
+#ifndef DEBUG
+        /* Create the file descriptor. */
+        if(*_rcvr_mac == '/')
+            _fd = open(_rcvr_mac, O_RDONLY);
+        else
+            _fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
 
-        color = hildon_color_button_get_color(
-                HILDON_COLOR_BUTTON(cdi.col_mark_velocity));
-        _color_mark_velocity = *color;
+        /* If file descriptor creation failed, try again later.  Note that
+         * there is no need to call rcvr_disconnect() because the file
+         * descriptor creation is the first step, so if it fails, there's
+         * nothing to clean up. */
+        if(_fd == -1)
+            rcvr_connect_later();
+        else
+        {
+            /* Reset GPS read buffer */
+            _gps_read_buf_curr = _gps_read_buf;
+            *_gps_read_buf_curr = '\0';
 
-        color = hildon_color_button_get_color(
-                HILDON_COLOR_BUTTON(cdi.col_mark_old));
-        _color_mark_old = *color;
+            /* Create channel and add watches. */
+            _channel = g_io_channel_unix_new(_fd);
+            g_io_channel_set_flags(_channel, G_IO_FLAG_NONBLOCK, NULL);
+            _error_sid = g_io_add_watch_full(_channel, G_PRIORITY_HIGH_IDLE,
+                    G_IO_ERR | G_IO_HUP, channel_cb_error, NULL, NULL);
+            _connect_sid = g_io_add_watch_full(_channel, G_PRIORITY_HIGH_IDLE,
+                    G_IO_OUT, channel_cb_connect, NULL, NULL);
+            if(*_rcvr_mac != '/'
+                    && connect(_fd, (struct sockaddr*)&_rcvr_addr,
+                        sizeof(_rcvr_addr))
+                    && errno != EAGAIN)
+            {
+                /* Connection failed.  Disconnect and try again later. */
+                rcvr_disconnect();
+                rcvr_connect_later();
+            }
+        }
+#else
+        /* We're in DEBUG mode, so instead of connecting, skip to FIXED. */
+        set_conn_state(RCVR_FIXED);
+#endif
+    }
 
-        color = hildon_color_button_get_color(
-                HILDON_COLOR_BUTTON(cdi.col_track));
-        _color_track = *color;
+    _clater_sid = 0;
 
-        color = hildon_color_button_get_color(
-                HILDON_COLOR_BUTTON(cdi.col_track_break));
-        _color_track_break = *color;
+    vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
+    return FALSE;
+}
 
-        color = hildon_color_button_get_color(
-                HILDON_COLOR_BUTTON(cdi.col_route));
-        _color_route = *color;
+/**
+ * Place a request to connect about 1 second after the function is called.
+ */
+static void
+rcvr_connect_later()
+{
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-        color = hildon_color_button_get_color(
-                HILDON_COLOR_BUTTON(cdi.col_route_way));
-        _color_route_way = *color;
+    _clater_sid = g_timeout_add(1000, (GSourceFunc)rcvr_connect_now, NULL);
 
-        color = hildon_color_button_get_color(
-                HILDON_COLOR_BUTTON(cdi.col_route_nextway));
-        _color_route_nextway = *color;
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
-        color = hildon_color_button_get_color(
-                HILDON_COLOR_BUTTON(cdi.col_poi));
-        _color_poi = *color;
+/**
+ * Convert the float lat/lon/speed/heading data into integer units.
+ */
+static void
+integerize_data()
+{
+    gfloat tmp;
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-        update_gcs();
-        break;
-    }
+    latlon2unit(_pos_lat, _pos_lon, _pos.unitx, _pos.unity);
 
-    gtk_widget_destroy(dialog);
+    tmp = (_heading * (1.f / 180.f)) * PI;
+    _vel_offsetx = (gint)(floorf(_speed * sinf(tmp) + 0.5f));
+    _vel_offsety = -(gint)(floorf(_speed * cosf(tmp) + 0.5f));
 
-    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
-    return TRUE;
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
 }
 
 /**
- * Bring up the Settings dialog.  Return TRUE if and only if the recever
- * information has changed (MAC or channel).
+ * Update all GdkGC objects to reflect the current _draw_line_width.
  */
-static gboolean
-settings_dialog()
+#define UPDATE_GC(gc) \
+    gdk_gc_set_line_attributes(gc, \
+            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
+static void
+update_gcs()
 {
-    GtkWidget *dialog;
-    GtkWidget *notebook;
-    GtkWidget *table;
-    GtkWidget *hbox;
-    GtkWidget *hbox2;
-    GtkWidget *label;
-    GtkWidget *txt_rcvr_mac;
-    GtkWidget *num_rcvr_chan;
-    GtkWidget *num_center_ratio;
-    GtkWidget *num_lead_ratio;
-    GtkWidget *num_announce_notice;
-    GtkWidget *chk_enable_voice;
-    GtkWidget *num_voice_speed;
-    GtkWidget *num_voice_pitch;
-    GtkWidget *num_draw_line_width;
-    GtkWidget *chk_always_keep_on;
-    GtkWidget *cmb_units;
-    GtkWidget *cmb_escape_key;
-    GtkWidget *btn_scan;
-    GtkWidget *btn_colors;
-
-    GtkWidget *txt_poi_db;
-    GtkWidget *btn_browsepoi;
-    GtkWidget *num_poi_zoom;
-
-    BrowseInfo browse_info = {0, 0};
-    ScanInfo scan_info = {0};
-    gboolean rcvr_changed = FALSE;
-    guint i;
     printf("%s()\n", __PRETTY_FUNCTION__);
 
-    dialog = gtk_dialog_new_with_buttons(_("Maemo Mapper Settings"),
-            GTK_WINDOW(_window), GTK_DIALOG_MODAL,
-            GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
-            NULL);
+    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
+            &_color_mark);
+    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
+            &_color_mark_velocity);
+    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
+            &_color_mark_old);
+    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
+            &_color_track);
+    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
+            &_color_track_break);
+    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
+            &_color_route);
+    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
+            &_color_route_way);
+    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
+            &_color_route_nextway);
+    gdk_color_alloc(gtk_widget_get_colormap(_map_widget),
+            &_color_poi);
 
-    gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
-            btn_colors = gtk_button_new_with_label(_("Colors...")));
+    if(_gc_mark)
+    {
+        g_object_unref(_gc_mark);
+        g_object_unref(_gc_mark_velocity);
+        g_object_unref(_gc_mark_old);
+        g_object_unref(_gc_track);
+        g_object_unref(_gc_track_break);
+        g_object_unref(_gc_route);
+        g_object_unref(_gc_route_way);
+        g_object_unref(_gc_route_nextway);
+        g_object_unref(_gc_poi);
+    }
 
-    gtk_dialog_add_button(GTK_DIALOG(dialog),
-            GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
+    /* _gc_mark is used to draw the mark when data is current. */
+    _gc_mark = gdk_gc_new(_map_pixmap);
+    gdk_gc_set_foreground(_gc_mark, &_color_mark);
+    gdk_gc_set_line_attributes(_gc_mark,
+            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
 
-    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
-            notebook = gtk_notebook_new(), TRUE, TRUE, 0);
+    /* _gc_mark_old is used to draw the mark when data is old. */
+    _gc_mark_old = gdk_gc_new(_map_pixmap);
+    gdk_gc_set_foreground(_gc_mark_old, &_color_mark_old);
+    gdk_gc_set_line_attributes(_gc_mark_old,
+            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
 
-    /* Receiver page. */
-    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
-            table = gtk_table_new(2, 3, FALSE),
-            label = gtk_label_new(_("GPS")));
+    /* _gc_mark_velocity is used to draw the vel_current line. */
+    _gc_mark_velocity = gdk_gc_new(_map_pixmap);
+    gdk_gc_set_foreground(_gc_mark_velocity, &_color_mark_velocity);
+    gdk_gc_set_line_attributes(_gc_mark_velocity,
+            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
 
-    /* Receiver MAC Address. */
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("MAC")),
-            0, 1, 0, 1, GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            hbox = gtk_hbox_new(FALSE, 4),
-            1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_box_pack_start(GTK_BOX(hbox),
-            txt_rcvr_mac = gtk_entry_new(),
-            TRUE, TRUE, 0);
-    gtk_box_pack_start(GTK_BOX(hbox),
-            btn_scan = gtk_button_new_with_label(_("Scan...")),
-            FALSE, FALSE, 0);
+    /* _gc_track is used to draw the track line. */
+    _gc_track = gdk_gc_new(_map_pixmap);
+    gdk_gc_set_foreground(_gc_track, &_color_track);
+    gdk_gc_set_line_attributes(_gc_track,
+            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
 
-    /* Receiver Channel. */
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Channel")),
-            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),
-            label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
-            1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_container_add(GTK_CONTAINER(label),
-            num_rcvr_chan = hildon_number_editor_new(0, 255));
+    /* _gc_track_break is used to draw the track_break dots. */
+    _gc_track_break = gdk_gc_new(_map_pixmap);
+    gdk_gc_set_foreground(_gc_track_break, &_color_track_break);
+    gdk_gc_set_line_attributes(_gc_track_break,
+            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
 
-    /* Note!. */
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(
-                _("Note: \"Channel\" refers to the device side!")),
-            0, 2, 2, 3, GTK_FILL, 0, 2, 4);
-    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
-    gtk_misc_set_alignment(GTK_MISC(label), 0.5f, 0.5f);
+    /* _gc_route is used to draw the route line. */
+    _gc_route = gdk_gc_new(_map_pixmap);
+    gdk_gc_set_foreground(_gc_route, &_color_route);
+    gdk_gc_set_line_attributes(_gc_route,
+            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
 
+    /* _way_gc is used to draw the waypoint dots. */
+    _gc_route_way = gdk_gc_new(_map_pixmap);
+    gdk_gc_set_foreground(_gc_route_way, &_color_route_way);
+    gdk_gc_set_line_attributes(_gc_route_way,
+            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
 
-    /* Auto-Center page. */
-    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
-            table = gtk_table_new(2, 2, FALSE),
-            label = gtk_label_new(_("Auto-Center")));
+    /* _gc_route_nextway is used to draw the next_way labels. */
+    _gc_route_nextway = gdk_gc_new(_map_pixmap);
+    gdk_gc_set_foreground(_gc_route_nextway, &_color_route_nextway);
+    gdk_gc_set_line_attributes(_gc_route_nextway,
+            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
 
-    /* Auto-Center Sensitivity. */
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Sensitivity")),
-            0, 1, 0, 1, GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
-            1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_container_add(GTK_CONTAINER(label),
-            num_center_ratio = hildon_controlbar_new());
-    hildon_controlbar_set_range(HILDON_CONTROLBAR(num_center_ratio), 1, 10);
-    force_min_visible_bars(HILDON_CONTROLBAR(num_center_ratio), 1);
+    /* _gc_poi is used to draw the default POI icon. */
+    _gc_poi = gdk_gc_new(_map_pixmap);
+    gdk_gc_set_foreground(_gc_poi, &_color_poi);
+    gdk_gc_set_background(_gc_poi, &_color_poi);
+    gdk_gc_set_line_attributes(_gc_poi,
+            _draw_line_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
 
-    /* Lead Amount. */
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Lead Amount")),
-            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),
-            label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
-            1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_container_add(GTK_CONTAINER(label),
-            num_lead_ratio = hildon_controlbar_new());
-    hildon_controlbar_set_range(HILDON_CONTROLBAR(num_lead_ratio), 1, 10);
-    force_min_visible_bars(HILDON_CONTROLBAR(num_lead_ratio), 1);
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
-    /* Announcement. */
-    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
-            table = gtk_table_new(2, 3, FALSE),
-            label = gtk_label_new(_("Announce")));
+/**
+ * Save all configuration data to GCONF.
+ */
+static void
+config_save()
+{
+    GConfClient *gconf_client = gconf_client_get_default();
+    gchar buffer[16];
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    /* Announcement Advance Notice. */
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Advance Notice")),
-            0, 1, 0, 1, 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);
-    hildon_controlbar_set_range(HILDON_CONTROLBAR(num_announce_notice), 1, 20);
-    force_min_visible_bars(HILDON_CONTROLBAR(num_announce_notice), 1);
+    if(!gconf_client)
+    {
+        popup_error(_window,
+                _("Failed to initialize GConf.  Settings were not saved."));
+        return;
+    }
 
-    /* Enable Voice. */
-    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_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk_enable_voice),
-            _enable_voice);
+    /* Save Receiver MAC from GConf. */
+    if(_rcvr_mac)
+        gconf_client_set_string(gconf_client,
+                GCONF_KEY_RCVR_MAC, _rcvr_mac, NULL);
+    else
+        gconf_client_unset(gconf_client,
+                GCONF_KEY_RCVR_MAC, NULL);
 
-    /* Voice Speed and Pitch. */
-    gtk_table_attach(GTK_TABLE(table),
-            hbox = gtk_hbox_new(FALSE, 12),
-            0, 2, 2, 3, 0, 0, 2, 6);
-    gtk_box_pack_start(GTK_BOX(hbox),
-            hbox2 = gtk_hbox_new(FALSE, 4),
-            TRUE, TRUE, 4);
-    gtk_box_pack_start(GTK_BOX(hbox2),
-            label = gtk_label_new(_("Speed")),
-            TRUE, TRUE, 0);
-    gtk_box_pack_start(GTK_BOX(hbox2),
-            num_voice_speed = hildon_controlbar_new(),
-            TRUE, TRUE, 0);
-    hildon_controlbar_set_range(HILDON_CONTROLBAR(num_voice_speed), 1, 10);
-    force_min_visible_bars(HILDON_CONTROLBAR(num_voice_speed), 1);
+    /* Save Receiver Channel to GConf. */
+    gconf_client_set_int(gconf_client,
+            GCONF_KEY_RCVR_CHAN, _rcvr_addr.rc_channel, NULL);
 
-    gtk_box_pack_start(GTK_BOX(hbox),
-            hbox2 = gtk_hbox_new(FALSE, 4),
-            TRUE, TRUE, 4);
-    gtk_box_pack_start(GTK_BOX(hbox2),
-            label = gtk_label_new(_("Pitch")),
-            TRUE, TRUE, 0);
-    gtk_box_pack_start(GTK_BOX(hbox2),
-            num_voice_pitch = hildon_controlbar_new(),
-            TRUE, TRUE, 0);
-    hildon_controlbar_set_range(HILDON_CONTROLBAR(num_voice_pitch), -2, 8);
-    force_min_visible_bars(HILDON_CONTROLBAR(num_voice_pitch), 1);
+    /* Save Map Download URI Format. */
+    gconf_client_set_string(gconf_client,
+            GCONF_KEY_MAP_URI_FORMAT, _curr_repo->url, NULL);
 
-    /* Misc. page. */
-    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
-            table = gtk_table_new(2, 3, FALSE),
-            label = gtk_label_new(_("Misc.")));
+    /* Save Map Download Zoom Steps. */
+    gconf_client_set_int(gconf_client,
+            GCONF_KEY_MAP_ZOOM_STEPS, _curr_repo->dl_zoom_steps, NULL);
 
-    /* Line Width. */
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Line Width")),
-            0, 1, 0, 1, GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            num_draw_line_width = hildon_controlbar_new(),
-            1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    hildon_controlbar_set_range(HILDON_CONTROLBAR(num_draw_line_width), 1, 20);
-    force_min_visible_bars(HILDON_CONTROLBAR(num_draw_line_width), 1);
+    /* Save Map Cache Directory. */
+    if(_curr_repo->cache_dir)
+        gconf_client_set_string(gconf_client,
+            GCONF_KEY_MAP_DIR_NAME, _curr_repo->cache_dir, NULL);
 
-    /* Keep Display On Only When Fullscreen. */
-    gtk_table_attach(GTK_TABLE(table),
-            chk_always_keep_on = gtk_check_button_new_with_label(
-                _("Keep Display On Only in Fullscreen Mode")),
-            0, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    /* Save Auto-Download. */
+    gconf_client_set_bool(gconf_client,
+            GCONF_KEY_AUTO_DOWNLOAD, _auto_download, NULL);
 
-    /* Units. */
-    gtk_table_attach(GTK_TABLE(table),
-            hbox = gtk_hbox_new(FALSE, 4),
-            0, 2, 2, 3, GTK_FILL, 0, 2, 4);
-    gtk_box_pack_start(GTK_BOX(hbox),
-            label = gtk_label_new(_("Units")),
-            FALSE, FALSE, 0);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_box_pack_start(GTK_BOX(hbox),
-            label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
-            TRUE, TRUE, 0);
-    gtk_container_add(GTK_CONTAINER(label),
-            cmb_units = gtk_combo_box_new_text());
-    for(i = 0; i < UNITS_ENUM_COUNT; i++)
-        gtk_combo_box_append_text(GTK_COMBO_BOX(cmb_units), UNITS_TEXT[i]);
+    /* Save Auto-Center Sensitivity. */
+    gconf_client_set_int(gconf_client,
+            GCONF_KEY_CENTER_SENSITIVITY, _center_ratio, NULL);
 
-    /* Escape Key. */
-    gtk_box_pack_start(GTK_BOX(hbox),
-            label = gtk_label_new(_("Escape Key")),
-            FALSE, FALSE, 0);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_box_pack_start(GTK_BOX(hbox),
-            label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
-            TRUE, TRUE, 0);
-    gtk_container_add(GTK_CONTAINER(label),
-            cmb_escape_key = gtk_combo_box_new_text());
-    for(i = 0; i < ESCAPE_KEY_ENUM_COUNT; i++)
-        gtk_combo_box_append_text(GTK_COMBO_BOX(cmb_escape_key),
-                ESCAPE_KEY_TEXT[i]);
+    /* Save Auto-Center Lead Amount. */
+    gconf_client_set_int(gconf_client,
+            GCONF_KEY_LEAD_AMOUNT, _lead_ratio, NULL);
 
-    /* POI page */
-    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
-            table = gtk_table_new(2, 3, FALSE),
-            label = gtk_label_new(_("POI")));
+    /* Save Draw Line Width. */
+    gconf_client_set_int(gconf_client,
+            GCONF_KEY_DRAW_LINE_WIDTH, _draw_line_width, NULL);
 
-    /* POI database. */
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("POI database")),
-            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),
-            hbox = gtk_hbox_new(FALSE, 4),
-            1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_box_pack_start(GTK_BOX(hbox),
-            txt_poi_db = gtk_entry_new(),
-            TRUE, TRUE, 0);
-    gtk_box_pack_start(GTK_BOX(hbox),
-            btn_browsepoi = gtk_button_new_with_label(_("Browse...")),
-            FALSE, FALSE, 0);
+    /* Save Announce Advance Notice Ratio. */
+    gconf_client_set_int(gconf_client,
+            GCONF_KEY_ANNOUNCE_NOTICE, _announce_notice_ratio, NULL);
 
-    /* Show POI below zoom. */
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_label_new(_("Show POI below zoom")),
-            0, 1, 2, 3, GTK_FILL, 0, 2, 4);
-    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
-    gtk_table_attach(GTK_TABLE(table),
-            label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
-            1, 2, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 4);
-    gtk_container_add(GTK_CONTAINER(label),
-            num_poi_zoom = hildon_number_editor_new(0, MAX_ZOOM));
+    /* Save Enable Voice flag. */
+    gconf_client_set_bool(gconf_client,
+            GCONF_KEY_ENABLE_VOICE, _enable_voice, NULL);
 
+    /* Save Keep On When Fullscreen flag. */
+    gconf_client_set_bool(gconf_client,
+            GCONF_KEY_ALWAYS_KEEP_ON, _always_keep_on, NULL);
 
-    /* Connect signals. */
-    scan_info.settings_dialog = dialog;
-    scan_info.txt_rcvr_mac = txt_rcvr_mac;
-    g_signal_connect(G_OBJECT(btn_scan), "clicked",
-                      G_CALLBACK(scan_bluetooth), &scan_info);
-    g_signal_connect(G_OBJECT(btn_colors), "clicked",
-                      G_CALLBACK(settings_dialog_colors), dialog);
+    /* Save Units. */
+    gconf_client_set_string(gconf_client,
+            GCONF_KEY_UNITS, UNITS_TEXT[_units], NULL);
 
-    browse_info.dialog = dialog;
-    browse_info.txt = txt_poi_db;
-    g_signal_connect(G_OBJECT(btn_browsepoi), "clicked",
-                      G_CALLBACK(settings_dialog_browse_forfile), &browse_info);
+    /* Save Escape Key Function. */
+    gconf_client_set_string(gconf_client,
+            GCONF_KEY_ESCAPE_KEY, ESCAPE_KEY_TEXT[_escape_key], NULL);
 
-    /* Initialize fields. */
-    if(_rcvr_mac)
-        gtk_entry_set_text(GTK_ENTRY(txt_rcvr_mac), _rcvr_mac);
-    hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(num_rcvr_chan),
-            _rcvr_addr.rc_channel);
-    if(_poi_db)
-        gtk_entry_set_text(GTK_ENTRY(txt_poi_db), _poi_db);
-    hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(num_poi_zoom),
-            _poi_zoom);
-    hildon_controlbar_set_value(HILDON_CONTROLBAR(num_center_ratio),
-            _center_ratio);
-    hildon_controlbar_set_value(HILDON_CONTROLBAR(num_lead_ratio),
-            _lead_ratio);
-    hildon_controlbar_set_value(HILDON_CONTROLBAR(num_announce_notice),
-            _announce_notice_ratio);
-    hildon_controlbar_set_value(HILDON_CONTROLBAR(num_voice_speed),
-            (gint)(_voice_speed * 3 + 0.5));
-    hildon_controlbar_set_value(HILDON_CONTROLBAR(num_voice_pitch),
-            _voice_pitch);
-    hildon_controlbar_set_value(HILDON_CONTROLBAR(num_draw_line_width),
-            _draw_line_width);
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk_always_keep_on),
-            !_always_keep_on);
-    gtk_combo_box_set_active(GTK_COMBO_BOX(cmb_units), _units);
-    gtk_combo_box_set_active(GTK_COMBO_BOX(cmb_escape_key), _escape_key);
+    /* Save last saved latitude. */
+    gconf_client_set_float(gconf_client,
+            GCONF_KEY_LAT, _pos_lat, NULL);
 
-    gtk_widget_show_all(dialog);
+    /* Save last saved longitude. */
+    gconf_client_set_float(gconf_client,
+            GCONF_KEY_LON, _pos_lon, NULL);
 
-    while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
+    /* Save last center point. */
     {
-        /* Set _rcvr_mac if necessary. */
-        if(!*gtk_entry_get_text(GTK_ENTRY(txt_rcvr_mac)))
-        {
-            /* User specified no rcvr mac - set _rcvr_mac to NULL. */
-            if(_rcvr_mac)
-            {
-                g_free(_rcvr_mac);
-                _rcvr_mac = NULL;
-                rcvr_changed = TRUE;
-                gtk_widget_set_sensitive(
-                        GTK_WIDGET(_menu_gps_details_item), FALSE);
-            }
-            if(_enable_gps)
-            {
-                gtk_check_menu_item_set_active(
-                        GTK_CHECK_MENU_ITEM(_menu_enable_gps_item), FALSE);
-                popup_error(dialog, _("No GPS Receiver MAC Provided.\n"
-                        "GPS Disabled."));
-                rcvr_changed = TRUE;
-                gtk_widget_set_sensitive(GTK_WIDGET(_menu_gps_details_item),
-                        FALSE);
-                gtk_widget_set_sensitive(GTK_WIDGET(_menu_gps_reset_item),
-                        FALSE);
-            }
-        }
-        else if(!_rcvr_mac || strcmp(_rcvr_mac,
-                      gtk_entry_get_text(GTK_ENTRY(txt_rcvr_mac))))
-        {
-            /* User specified a new rcvr mac. */
-            g_free(_rcvr_mac);
-            _rcvr_mac = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_rcvr_mac)));
-            str2ba(_rcvr_mac, &_rcvr_addr.rc_bdaddr);
-            rcvr_changed = TRUE;
-        }
+        gfloat center_lat, center_lon;
+        unit2latlon(_center.unitx, _center.unity, center_lat, center_lon);
 
-        if(_rcvr_addr.rc_channel != hildon_number_editor_get_value(
-                    HILDON_NUMBER_EDITOR(num_rcvr_chan)))
-        {
-            _rcvr_addr.rc_channel = hildon_number_editor_get_value(
-                    HILDON_NUMBER_EDITOR(num_rcvr_chan));
-            rcvr_changed = TRUE;
-        }
+        /* Save last center latitude. */
+        gconf_client_set_float(gconf_client,
+                GCONF_KEY_CENTER_LAT, center_lat, NULL);
 
-        _center_ratio = hildon_controlbar_get_value(
-                HILDON_CONTROLBAR(num_center_ratio));
+        /* Save last center longitude. */
+        gconf_client_set_float(gconf_client,
+                GCONF_KEY_CENTER_LON, center_lon, NULL);
+    }
 
-        _lead_ratio = hildon_controlbar_get_value(
-                HILDON_CONTROLBAR(num_lead_ratio));
+    /* Save last Zoom Level. */
+    gconf_client_set_int(gconf_client,
+            GCONF_KEY_ZOOM, _zoom, NULL);
 
-        _draw_line_width = hildon_controlbar_get_value(
-                HILDON_CONTROLBAR(num_draw_line_width));
+    /* Save Route Directory. */
+    if(_route_dir_uri)
+        gconf_client_set_string(gconf_client,
+                GCONF_KEY_ROUTEDIR, _route_dir_uri, NULL);
 
-        _always_keep_on = !gtk_toggle_button_get_active(
-                GTK_TOGGLE_BUTTON(chk_always_keep_on));
+    /* Save the repositories. */
+    {
+        GList *curr = _repo_list;
+        GSList *temp_list = NULL;
+        gint curr_repo_index = 0;
 
-        _units = gtk_combo_box_get_active(GTK_COMBO_BOX(cmb_units));
-        _escape_key = gtk_combo_box_get_active(GTK_COMBO_BOX(cmb_escape_key));
+        for(curr = _repo_list; curr != NULL; curr = curr->next)
+        {
+            /* Build from each part of a repo, delimited by newline characters:
+             * 1. url
+             * 2. cache_dir
+             * 3. dl_zoom_steps
+             * 4. view_zoom_steps
+             */
+            RepoData *rd = curr->data;
+            gchar buffer[1024];
+            sprintf(buffer, "%s\n%s\n%s\n%d\n%d\n",
+                    rd->name,
+                    rd->url,
+                    rd->cache_dir,
+                    rd->dl_zoom_steps,
+                    rd->view_zoom_steps);
+            temp_list = g_slist_append(temp_list, g_strdup(buffer));
+            if(rd == _curr_repo)
+                gconf_client_set_int(gconf_client,
+                        GCONF_KEY_CURRREPO, curr_repo_index, NULL);
+            curr_repo_index++;
+        }
+        gconf_client_set_list(gconf_client,
+                GCONF_KEY_REPOSITORIES, GCONF_VALUE_STRING, temp_list, NULL);
+    }
 
-        _announce_notice_ratio = hildon_controlbar_get_value(
-                HILDON_CONTROLBAR(num_announce_notice));
+    /* Save Last Track File. */
+    if(_track_file_uri)
+        gconf_client_set_string(gconf_client,
+                GCONF_KEY_TRACKFILE, _track_file_uri, NULL);
 
-        _voice_speed = hildon_controlbar_get_value(
-                HILDON_CONTROLBAR(num_voice_speed)) / 3.0;
+    /* Save Auto-Center Mode. */
+    gconf_client_set_int(gconf_client,
+            GCONF_KEY_AUTOCENTER_MODE, _center_mode, NULL);
 
-        _voice_pitch = hildon_controlbar_get_value(
-                HILDON_CONTROLBAR(num_voice_pitch));
+    /* Save Show Tracks flag. */
+    gconf_client_set_bool(gconf_client,
+            GCONF_KEY_SHOWTRACKS, _show_tracks & TRACKS_MASK, NULL);
 
-        _enable_voice = gtk_toggle_button_get_active(
-                GTK_TOGGLE_BUTTON(chk_enable_voice));
+    /* Save Show Routes flag. */
+    gconf_client_set_bool(gconf_client,
+            GCONF_KEY_SHOWROUTES, _show_tracks & ROUTES_MASK, NULL);
 
-        if(_dbconn)
-        {
-            sqlite_close(_db);
-            _dbconn = FALSE;
-            gtk_widget_set_sensitive(_cmenu_add_poi, FALSE);
-            gtk_widget_set_sensitive(_cmenu_edit_poi, FALSE);
-            gtk_widget_set_sensitive(_menu_poi_item, FALSE);
-        }
-        g_free(_poi_db);
-        if(strlen(gtk_entry_get_text(GTK_ENTRY(txt_poi_db))))
-        {
-            _poi_db = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_poi_db)));
-            db_connect();
-            gtk_widget_set_sensitive(_cmenu_add_poi, _dbconn);
-            gtk_widget_set_sensitive(_cmenu_edit_poi, _dbconn);
-            gtk_widget_set_sensitive(_menu_poi_item, _dbconn);
-        }
-        else
-            _poi_db = NULL;
+    /* Save Show Velocity Vector flag. */
+    gconf_client_set_bool(gconf_client,
+            GCONF_KEY_SHOWVELVEC, _show_velvec, NULL);
 
-        _poi_zoom = hildon_number_editor_get_value(
-        HILDON_NUMBER_EDITOR(num_poi_zoom));
+    /* Save Enable GPS flag. */
+    gconf_client_set_bool(gconf_client,
+            GCONF_KEY_ENABLE_GPS, _enable_gps, NULL);
 
-        update_gcs();
+    /* Save Route Locations. */
+    gconf_client_set_list(gconf_client,
+            GCONF_KEY_ROUTE_LOCATIONS, GCONF_VALUE_STRING, _loc_list, NULL);
 
-        config_save();
-        break;
-    }
+    /* Save GPS Info flag. */
+    gconf_client_set_bool(gconf_client,
+            GCONF_KEY_GPS_INFO, _gps_info, NULL);
 
-    gtk_widget_hide(dialog); /* Destroying causes a crash (!?!?!??!) */
+    /* Save Route Download Radius. */
+    gconf_client_set_int(gconf_client,
+            GCONF_KEY_ROUTE_DL_RADIUS, _route_dl_radius, NULL);
 
-    vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, rcvr_changed);
-    return rcvr_changed;
-}
+    /* Save Colors. */
+    sprintf(buffer, "#%02x%02x%02x",
+            _color_mark.red >> 8,
+            _color_mark.green >> 8,
+            _color_mark.blue >> 8);
+    gconf_client_set_string(gconf_client,
+            GCONF_KEY_COLOR_MARK, buffer, NULL);
 
-/**
- * Initialize all configuration from GCONF.  This should not be called more
- * than once during execution.
- */
-static void
-config_init()
-{
-    GConfValue *value;
-    GConfClient *gconf_client = gconf_client_get_default();
-    gchar *str;
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    sprintf(buffer, "#%02x%02x%02x",
+            _color_mark_velocity.red >> 8,
+            _color_mark_velocity.green >> 8,
+            _color_mark_velocity.blue >> 8);
+    gconf_client_set_string(gconf_client,
+            GCONF_KEY_COLOR_MARK_VELOCITY, buffer, NULL);
 
-    if(!gconf_client)
-    {
-        popup_error(_window, _("Failed to initialize GConf.  Quitting."));
-        exit(1);
-    }
+    sprintf(buffer, "#%02x%02x%02x",
+            _color_mark_old.red >> 8,
+            _color_mark_old.green >> 8,
+            _color_mark_old.blue >> 8);
+    gconf_client_set_string(gconf_client,
+            GCONF_KEY_COLOR_MARK_OLD, buffer, NULL);
 
-    /* Get Receiver MAC from GConf.  Default is scanned via hci_inquiry. */
-    {
-        _rcvr_mac = gconf_client_get_string(
-                gconf_client, GCONF_KEY_RCVR_MAC, NULL);
-        if(_rcvr_mac)
-            str2ba(_rcvr_mac, &_rcvr_addr.rc_bdaddr);
-    }
+    sprintf(buffer, "#%02x%02x%02x",
+            _color_track.red >> 8,
+            _color_track.green >> 8,
+            _color_track.blue >> 8);
+    gconf_client_set_string(gconf_client,
+            GCONF_KEY_COLOR_TRACK, buffer, NULL);
 
-    /* Get Receiver Channel from GConf.  Default is 1. */
-    _rcvr_addr.rc_family = AF_BLUETOOTH;
-    _rcvr_addr.rc_channel = gconf_client_get_int(gconf_client,
-            GCONF_KEY_RCVR_CHAN, NULL);
-    if(_rcvr_addr.rc_channel < 1)
-        _rcvr_addr.rc_channel = 1;
+    sprintf(buffer, "#%02x%02x%02x",
+            _color_track_break.red >> 8,
+            _color_track_break.green >> 8,
+            _color_track_break.blue >> 8);
+    gconf_client_set_string(gconf_client,
+            GCONF_KEY_COLOR_TRACK_BREAK, buffer, NULL);
 
-    /* Get Auto-Download.  Default is FALSE. */
-    _auto_download = gconf_client_get_bool(gconf_client,
-            GCONF_KEY_AUTO_DOWNLOAD, NULL);
+    sprintf(buffer, "#%02x%02x%02x",
+            _color_route.red >> 8,
+            _color_route.green >> 8,
+            _color_route.blue >> 8);
+    gconf_client_set_string(gconf_client,
+            GCONF_KEY_COLOR_ROUTE, buffer, NULL);
 
-    /* Get Center Ratio - Default is 3. */
-    _center_ratio = gconf_client_get_int(gconf_client,
-            GCONF_KEY_CENTER_SENSITIVITY, NULL);
-    if(!_center_ratio)
-        _center_ratio = 7;
+    sprintf(buffer, "#%02x%02x%02x",
+            _color_route_way.red >> 8,
+            _color_route_way.green >> 8,
+            _color_route_way.blue >> 8);
+    gconf_client_set_string(gconf_client,
+            GCONF_KEY_COLOR_ROUTE_WAY, buffer, NULL);
 
-    /* Get Lead Ratio - Default is 5. */
-    _lead_ratio = gconf_client_get_int(gconf_client,
-            GCONF_KEY_LEAD_AMOUNT, NULL);
-    if(!_lead_ratio)
-        _lead_ratio = 5;
+    sprintf(buffer, "#%02x%02x%02x",
+            _color_route_nextway.red >> 8,
+            _color_route_nextway.green >> 8,
+            _color_route_nextway.blue >> 8);
+    gconf_client_set_string(gconf_client,
+            GCONF_KEY_COLOR_ROUTE_NEXTWAY, buffer, NULL);
 
-    /* Get Draw Line Width- Default is 5. */
-    _draw_line_width = gconf_client_get_int(gconf_client,
-            GCONF_KEY_DRAW_LINE_WIDTH, NULL);
-    if(!_draw_line_width)
-        _draw_line_width = 5;
+    sprintf(buffer, "#%02x%02x%02x",
+            _color_poi.red >> 8,
+            _color_poi.green >> 8,
+            _color_poi.blue >> 8);
+    gconf_client_set_string(gconf_client,
+            GCONF_KEY_COLOR_POI, buffer, NULL);
 
-    /* Get Announce Advance Notice - Default is 30. */
-    value = gconf_client_get(gconf_client, GCONF_KEY_ANNOUNCE_NOTICE, NULL);
-    if(value)
-    {
-        _announce_notice_ratio = gconf_value_get_int(value);
-        gconf_value_free(value);
-    }
+    /* Save POI database. */
+    if(_poi_db)
+        gconf_client_set_string(gconf_client,
+                GCONF_KEY_POI_DB, _poi_db, NULL);
     else
-        _announce_notice_ratio = 8;
+        gconf_client_unset(gconf_client, GCONF_KEY_POI_DB, NULL);
 
-    /* Get Enable Voice flag.  Default is TRUE. */
-    value = gconf_client_get(gconf_client, GCONF_KEY_ENABLE_VOICE, NULL);
-    if(value)
-    {
-        _enable_voice = gconf_value_get_bool(value);
-        gconf_value_free(value);
-    }
-    else
-        _enable_voice = TRUE;
+    /* Save Show POI below zoom. */
+    gconf_client_set_int(gconf_client,
+            GCONF_KEY_POI_ZOOM, _poi_zoom, NULL);
 
-    /* Get Voice Speed - Default is 1.0. */
-    value = gconf_client_get(gconf_client, GCONF_KEY_VOICE_SPEED, NULL);
-    if(value)
-    {
-        _voice_speed = gconf_value_get_float(value);
-        gconf_value_free(value);
-    }
-    else
-        _voice_speed = 1.0;
+    g_object_unref(gconf_client);
 
-    /* Get Voice Speed - Default is 0. */
-    value = gconf_client_get(gconf_client, GCONF_KEY_VOICE_PITCH, NULL);
-    if(value)
+    /* Save route. */
     {
-        _voice_pitch = gconf_value_get_int(value);
-        gconf_value_free(value);
+        GnomeVFSHandle *handle;
+        gchar *route_file;
+        route_file = gnome_vfs_uri_make_full_from_relative(
+                _config_dir_uri, CONFIG_FILE_ROUTE);
+        if(GNOME_VFS_OK == gnome_vfs_create(&handle, route_file,
+                    GNOME_VFS_OPEN_WRITE, FALSE, 0600))
+        {
+            write_route_gpx(handle);
+            gnome_vfs_close(handle);
+        }
+        g_free(route_file);
     }
-    else
-        _voice_pitch = 3;
-
-    /* Get Always Keep On flag.  Default is FALSE. */
-    _always_keep_on = gconf_client_get_bool(gconf_client,
-            GCONF_KEY_ALWAYS_KEEP_ON, NULL);
 
-    /* Get Units.  Default is UNITS_KM. */
+    /* Save track. */
     {
-        gchar *units_str = gconf_client_get_string(gconf_client,
-                GCONF_KEY_UNITS, NULL);
-        guint i;
-        for(i = UNITS_ENUM_COUNT - 1; i > 0; i--)
-            if(!strcmp(units_str, UNITS_TEXT[i]))
-                break;
-        _units = i;
+        GnomeVFSHandle *handle;
+        gchar *track_file;
+        track_file = gnome_vfs_uri_make_full_from_relative(
+                _config_dir_uri, CONFIG_FILE_TRACK);
+        if(GNOME_VFS_OK == gnome_vfs_create(&handle, track_file,
+                    GNOME_VFS_OPEN_WRITE, FALSE, 0600))
+        {
+            write_track_gpx(handle);
+            gnome_vfs_close(handle);
+        }
+        g_free(track_file);
     }
 
-    /* Get Escape Key.  Default is ESCAPE_KEY_TOGGLE_TRACKS. */
-    {
-        gchar *escape_key_str = gconf_client_get_string(gconf_client,
-                GCONF_KEY_ESCAPE_KEY, NULL);
-        guint i;
-        for(i = ESCAPE_KEY_ENUM_COUNT - 1; i > 0; i--)
-            if(!strcmp(escape_key_str, ESCAPE_KEY_TEXT[i]))
-                break;
-        _escape_key = i;
-    }
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
-    /* Get last saved latitude.  Default is 0. */
-    _pos_lat = gconf_client_get_float(gconf_client, GCONF_KEY_LAT, NULL);
+static void
+force_min_visible_bars(HildonControlbar *control_bar, gint num_bars)
+{
+    GValue val;
+    memset(&val, 0, sizeof(val));
+    g_value_init(&val, G_TYPE_INT);
+    g_value_set_int(&val, num_bars);
+    g_object_set_property(G_OBJECT(control_bar), "minimum-visible-bars", &val);
+}
 
-    /* Get last saved longitude.  Default is somewhere in Midwest. */
-    value = gconf_client_get(gconf_client, GCONF_KEY_LON, NULL);
-    _pos_lon = gconf_client_get_float(gconf_client, GCONF_KEY_LON, NULL);
 
-    /* Get last center point. */
-    {
-        gfloat center_lat, center_lon;
+typedef struct _ScanInfo ScanInfo;
+struct _ScanInfo {
+    GtkWidget *settings_dialog;
+    GtkWidget *txt_rcvr_mac;
+    GtkWidget *scan_dialog;
+    GtkWidget *banner;
+    GtkListStore *store;
+    guint sid;
+};
 
-        /* Get last saved latitude.  Default is last saved latitude. */
-        value = gconf_client_get(gconf_client, GCONF_KEY_CENTER_LAT, NULL);
-        if(value)
-        {
-            center_lat = gconf_value_get_float(value);
-            gconf_value_free(value);
-        }
-        else
-            center_lat = _pos_lat;
+static gboolean
+scan_bluetooth_idle(ScanInfo *scan_info)
+{
+    gint devid, num_rsp;
+    GtkTreeIter iter;
+    inquiry_info *ii = NULL;
 
-        /* Get last saved longitude.  Default is last saved longitude. */
-        value = gconf_client_get(gconf_client, GCONF_KEY_CENTER_LON, NULL);
-        if(value)
-        {
-            center_lon = gconf_value_get_float(value);
-            gconf_value_free(value);
-        }
-        else
-            center_lon = _pos_lon;
+    devid = hci_get_route(NULL);
 
-        latlon2unit(center_lat, center_lon, _center.unitx, _center.unity);
-    }
+    ii = (inquiry_info*)malloc(255 * sizeof(inquiry_info));
+    num_rsp = hci_inquiry(devid, 4, 255, NULL, &ii, IREQ_CACHE_FLUSH);
 
-    /* Load the repositories. */
+    if(num_rsp < 0)
     {
-        GSList *list, *curr;
-        guint curr_repo_index = gconf_client_get_int(gconf_client,
-            GCONF_KEY_CURRREPO, NULL);
-        list = gconf_client_get_list(gconf_client,
-            GCONF_KEY_REPOSITORIES, GCONF_VALUE_STRING, NULL);
-
-        for(curr = list; curr != NULL; curr = curr->next)
-        {
-            /* Parse each part of a repo, delimited by newline characters:
-             * 1. url
-             * 2. cache_dir
-             * 3. dl_zoom_steps
-             * 4. view_zoom_steps
-             */
-            gchar *str = curr->data;
-            RepoData *rd = g_new(RepoData, 1);
-            rd->name = g_strdup(strsep(&str, "\n"));
-            rd->url = g_strdup(strsep(&str, "\n"));
-            rd->cache_dir = g_strdup(strsep(&str, "\n"));
-            if(!(rd->dl_zoom_steps = atoi(strsep(&str, "\n"))))
-                rd->dl_zoom_steps = 2;
-            if(!(rd->view_zoom_steps = atoi(strsep(&str, "\n"))))
-                rd->view_zoom_steps = 1;
-
-            _repo_list = g_list_append(_repo_list, rd);
-            if(!curr_repo_index--)
-                _curr_repo = rd;
-            g_free(curr->data);
-        }
-        g_slist_free(list);
+        gtk_widget_destroy(scan_info->banner);
+        gtk_widget_hide(scan_info->scan_dialog);
+        popup_error(scan_info->settings_dialog,
+                _("An error occurred while scanning."));
     }
-
-    if(_repo_list == NULL)
+    else if(num_rsp == 0)
     {
-        /* We have no repositories - create a default one. */
-        _curr_repo = g_new(RepoData, 1);
-
-        /* Many fields can be retrieved from the "old" gconf keys. */
-
-        /* Get Map Cache Dir.  Default is ~/MyDocs/.documents/Maps. */
-        _curr_repo->cache_dir = gconf_client_get_string(gconf_client,
-                GCONF_KEY_MAP_DIR_NAME, NULL);
-
-        if(!_curr_repo->cache_dir)
-            _curr_repo->cache_dir = gnome_vfs_expand_initial_tilde(
-                    "~/MyDocs/.documents/Maps");
-
-        /* Get Map Download URI Format.  Default is "". */
-        _curr_repo->url = gconf_client_get_string(gconf_client,
-                GCONF_KEY_MAP_URI_FORMAT, NULL);
-        if(!_curr_repo->url)
-            _curr_repo->url = g_strdup("");
+        gtk_widget_destroy(scan_info->banner);
+        gtk_widget_hide(scan_info->scan_dialog);
+        popup_error(scan_info->settings_dialog,
+                _("No bluetooth devices found."));
+    }
+    else
+    {
+        guint i;
+        gint sock = hci_open_dev(devid);
+        for(i = 0; i < num_rsp; i++)
+        {
+            gchar addr[19] = { 0 };
+            gchar name[256] = { 0 };
 
-        /* Get Map Download Zoom Steps.  Default is 2. */
-        _curr_repo->dl_zoom_steps = gconf_client_get_int(gconf_client,
-                GCONF_KEY_MAP_ZOOM_STEPS, NULL);
-        if(!_curr_repo->dl_zoom_steps)
-            _curr_repo->dl_zoom_steps = 2;
+            ba2str(&ii[i].bdaddr, addr);
+            memset(name, 0, sizeof(name));
+            if(hci_read_remote_name(sock, &ii[i].bdaddr, sizeof(name), name, 0))
+                strcpy(name, _("Unknown"));
 
-        /* Other fields are brand new. */
-        _curr_repo->name = g_strdup("Default");
-        _curr_repo->view_zoom_steps = 1;
-        _repo_list = g_list_append(_repo_list, _curr_repo);
+            gtk_list_store_append(scan_info->store, &iter);
+            gtk_list_store_set(scan_info->store, &iter,
+                    0, g_strdup(addr),
+                    1, g_strdup(name),
+                    -1);
+        }
+        close(sock);
+        gtk_widget_destroy(scan_info->banner);
     }
+    free(ii);
+    scan_info->sid = 0;
+    return FALSE;
+}
 
-    /* Get last Zoom Level.  Default is 16. */
-    value = gconf_client_get(gconf_client, GCONF_KEY_ZOOM, NULL);
-    if(value)
-    {
-        _zoom = gconf_value_get_int(value) / _curr_repo->view_zoom_steps
-            * _curr_repo->view_zoom_steps;
-        gconf_value_free(value);
-    }
-    else
-        _zoom = 16 / _curr_repo->view_zoom_steps
-            * _curr_repo->view_zoom_steps;
-    BOUND(_zoom, 0, MAX_ZOOM - 1);
-    _world_size_tiles = unit2tile(WORLD_SIZE_UNITS);
+/**
+ * Scan for all bluetooth devices.  This method can take a few seconds,
+ * during which the UI will freeze.
+ */
+static gboolean
+scan_bluetooth(GtkWidget *widget, ScanInfo *scan_info)
+{
+    /* Do an hci_inquiry for our boy. */
+    GtkWidget *dialog;
+    GtkWidget *lst_devices;
+    GtkTreeViewColumn *column;
+    GtkCellRenderer *renderer;
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    /* Speed and Heading are always initialized as 0. */
-    _speed = 0.f;
-    _heading = 0.f;
+    dialog = gtk_dialog_new_with_buttons(_("Select Bluetooth Device"),
+            GTK_WINDOW(scan_info->settings_dialog), GTK_DIALOG_MODAL,
+            GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+            GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+            NULL);
 
-    /* Get Route Directory.  Default is NULL. */
-    _route_dir_uri = gconf_client_get_string(gconf_client,
-            GCONF_KEY_ROUTEDIR, NULL);
+    scan_info->scan_dialog = dialog;
 
-    /* Get Last Track File.  Default is NULL. */
-    _track_file_uri = gconf_client_get_string(gconf_client,
-            GCONF_KEY_TRACKFILE, NULL);
+    scan_info->banner = hildon_banner_show_animation(dialog, NULL,
+            _("Scanning Bluetooth Devices"));
 
-    /* Get Auto-Center Mode.  Default is CENTER_LEAD. */
-    value = gconf_client_get(gconf_client, GCONF_KEY_AUTOCENTER_MODE, NULL);
-    if(value)
-    {
-        _center_mode = gconf_value_get_int(value);
-        gconf_value_free(value);
-    }
-    else
-        _center_mode = CENTER_LEAD;
+    scan_info->store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
 
-    /* Get Show Tracks flag.  Default is TRUE. */
-    value = gconf_client_get(gconf_client, GCONF_KEY_SHOWTRACKS, NULL);
-    if(value)
-    {
-        _show_tracks |= (gconf_value_get_bool(value) ? TRACKS_MASK : 0);
-        gconf_value_free(value);
-    }
-    else
-        _show_tracks |= TRACKS_MASK;
+    scan_info->sid = g_idle_add((GSourceFunc)scan_bluetooth_idle, scan_info);
 
-    /* Get Show Routes flag.  Default is TRUE. */
-    value = gconf_client_get(gconf_client, GCONF_KEY_SHOWROUTES, NULL);
-    if(value)
-    {
-        _show_tracks |= (gconf_value_get_bool(value) ? ROUTES_MASK : 0);
-        gconf_value_free(value);
-    }
-    else
-        _show_tracks |= ROUTES_MASK;
+    gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300);
 
-    /* Get Show Velocity Vector flag.  Default is TRUE. */
-    value = gconf_client_get(gconf_client, GCONF_KEY_SHOWVELVEC, NULL);
-    if(value)
-    {
-        _show_velvec = gconf_value_get_bool(value);
-        gconf_value_free(value);
-    }
-    else
-        _show_velvec = TRUE;
+    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
+            lst_devices = gtk_tree_view_new_with_model(
+                GTK_TREE_MODEL(scan_info->store)), TRUE, TRUE, 0);
 
-    /* Get Enable GPS flag.  Default is TRUE. */
-    value = gconf_client_get(gconf_client, GCONF_KEY_ENABLE_GPS, NULL);
-    if(value)
-    {
-        _enable_gps = gconf_value_get_bool(value);
-        gconf_value_free(value);
-    }
-    else
-        _enable_gps = TRUE;
+    g_object_unref(G_OBJECT(scan_info->store));
 
-    /* Initialize _conn_state based on _enable_gps. */
-    _conn_state = (_enable_gps ? RCVR_DOWN : RCVR_OFF);
+    gtk_tree_selection_set_mode(
+            gtk_tree_view_get_selection(GTK_TREE_VIEW(lst_devices)),
+            GTK_SELECTION_SINGLE);
+    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(lst_devices), TRUE);
 
-    /* Load the route locations. */
+    renderer = gtk_cell_renderer_text_new();
+    column = gtk_tree_view_column_new_with_attributes(
+            _("MAC"), renderer, "text", 0);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(lst_devices), column);
+
+    renderer = gtk_cell_renderer_text_new();
+    column = gtk_tree_view_column_new_with_attributes(
+            _("Description"), renderer, "text", 1);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(lst_devices), column);
+
+    gtk_widget_show_all(dialog);
+
+    while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
     {
-        GSList *curr;
-        _loc_list = gconf_client_get_list(gconf_client,
-            GCONF_KEY_ROUTE_LOCATIONS, GCONF_VALUE_STRING, NULL);
-        _loc_model = gtk_list_store_new(1, G_TYPE_STRING);
-        for(curr = _loc_list; curr != NULL; curr = curr->next)
+        GtkTreeIter iter;
+        if(gtk_tree_selection_get_selected(
+                    gtk_tree_view_get_selection(GTK_TREE_VIEW(lst_devices)),
+                    NULL, &iter))
         {
-            GtkTreeIter iter;
-            gtk_list_store_insert_with_values(_loc_model, &iter, INT_MAX,
-                    0, curr->data, -1);
+            gchar *mac;
+            gtk_tree_model_get(GTK_TREE_MODEL(scan_info->store),
+                    &iter, 0, &mac, -1);
+            gtk_entry_set_text(GTK_ENTRY(scan_info->txt_rcvr_mac), mac);
+            break;
         }
+        else
+            popup_error(dialog,
+                    _("Please select a bluetooth device from the list."));
     }
 
-    /* Get POI Database.  Default is in ~/MyDocs/.documents/Maps */
-    _poi_db = gconf_client_get_string(gconf_client,
-            GCONF_KEY_POI_DB, NULL);
-    if(_poi_db == NULL)
-        _poi_db = gnome_vfs_make_uri_full_from_relative(
-                _curr_repo->cache_dir, "poi.db");
-    db_connect();
+    if(scan_info->sid)
+        g_source_remove(scan_info->sid);
+    gtk_widget_destroy(dialog);
 
-    _poi_zoom = gconf_client_get_int(gconf_client,
-            GCONF_KEY_POI_ZOOM, NULL);
-    if(!_poi_zoom)
-    _poi_zoom = 6;
+    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
+    return TRUE;
+}
 
+typedef struct _BrowseInfo BrowseInfo;
+struct _BrowseInfo {
+    GtkWidget *dialog;
+    GtkWidget *txt;
+};
 
-    /* Get GPS Info flag.  Default is FALSE. */
-    value = gconf_client_get(gconf_client, GCONF_KEY_GPS_INFO, NULL);
-    if(value)
-    {
-        _gps_info = gconf_value_get_bool(value);
-        gconf_value_free(value);
-    }
-    else
-        _gps_info = FALSE;
+static gboolean
+settings_dialog_browse_forfile(GtkWidget *widget, BrowseInfo *browse_info)
+{
+    GtkWidget *dialog;
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    /* Initialize colors. */
-    str = gconf_client_get_string(gconf_client,
-            GCONF_KEY_COLOR_MARK, NULL);
-    if(!str || !gdk_color_parse(str, &_color_mark))
-        _color_mark = DEFAULT_COLOR_MARK;
+    dialog = GTK_WIDGET(
+            hildon_file_chooser_dialog_new(GTK_WINDOW(browse_info->dialog),
+            GTK_FILE_CHOOSER_ACTION_OPEN));
 
-    str = gconf_client_get_string(gconf_client,
-            GCONF_KEY_COLOR_MARK_VELOCITY, NULL);
-    if(!str || !gdk_color_parse(str, &_color_mark_velocity))
-        _color_mark_velocity = DEFAULT_COLOR_MARK_VELOCITY;
+    gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dialog), TRUE);
+    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
+            gtk_entry_get_text(GTK_ENTRY(browse_info->txt)));
 
-    str = gconf_client_get_string(gconf_client,
-            GCONF_KEY_COLOR_MARK_OLD, NULL);
-    if(!str || !gdk_color_parse(str, &_color_mark_old))
-        _color_mark_old = DEFAULT_COLOR_MARK_OLD;
+    if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(dialog)))
+    {
+        gchar *filename = gtk_file_chooser_get_filename(
+                GTK_FILE_CHOOSER(dialog));
+        gtk_entry_set_text(GTK_ENTRY(browse_info->txt), filename);
+        g_free(filename);
+    }
 
-    str = gconf_client_get_string(gconf_client,
-            GCONF_KEY_COLOR_TRACK, NULL);
-    if(!str || !gdk_color_parse(str, &_color_track))
-        _color_track = DEFAULT_COLOR_TRACK;
+    gtk_widget_destroy(dialog);
 
-    str = gconf_client_get_string(gconf_client,
-            GCONF_KEY_COLOR_TRACK_BREAK, NULL);
-    if(!str || !gdk_color_parse(str, &_color_track_break))
-        _color_track_break = DEFAULT_COLOR_TRACK_BREAK;
+    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
+    return TRUE;
+}
 
-    str = gconf_client_get_string(gconf_client,
-            GCONF_KEY_COLOR_ROUTE, NULL);
-    if(!str || !gdk_color_parse(str, &_color_route))
-        _color_route = DEFAULT_COLOR_ROUTE;
 
-    str = gconf_client_get_string(gconf_client,
-            GCONF_KEY_COLOR_ROUTE_WAY, NULL);
-    if(!str || !gdk_color_parse(str, &_color_route_way))
-        _color_route_way = DEFAULT_COLOR_ROUTE_WAY;
+typedef struct _ColorsDialogInfo ColorsDialogInfo;
+struct _ColorsDialogInfo {
+    GtkWidget *col_mark;
+    GtkWidget *col_mark_velocity;
+    GtkWidget *col_mark_old;
+    GtkWidget *col_track;
+    GtkWidget *col_track_break;
+    GtkWidget *col_route;
+    GtkWidget *col_route_way;
+    GtkWidget *col_route_nextway;
+    GtkWidget *col_poi;
+};
 
-    str = gconf_client_get_string(gconf_client,
-            GCONF_KEY_COLOR_ROUTE_NEXTWAY, NULL);
-    if(!str || !gdk_color_parse(str, &_color_route_nextway))
-        _color_route_nextway = DEFAULT_COLOR_ROUTE_NEXTWAY;
+static gboolean
+settings_dialog_colors_reset(GtkWidget *widget, ColorsDialogInfo *cdi)
+{
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi->col_mark),
+            &DEFAULT_COLOR_MARK);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi->col_mark_velocity),
+            &DEFAULT_COLOR_MARK_VELOCITY);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi->col_mark_old),
+            &DEFAULT_COLOR_MARK_OLD);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi->col_track),
+            &DEFAULT_COLOR_TRACK);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi->col_track_break),
+            &DEFAULT_COLOR_TRACK_BREAK);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi->col_route),
+            &DEFAULT_COLOR_ROUTE);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi->col_route_way),
+            &DEFAULT_COLOR_ROUTE_WAY);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi->col_route_nextway),
+            &DEFAULT_COLOR_ROUTE_NEXTWAY);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi->col_poi),
+            &DEFAULT_COLOR_POI);
+    return TRUE;
+}
 
-    str = gconf_client_get_string(gconf_client,
-            GCONF_KEY_COLOR_POI, NULL);
-    if(!str || !gdk_color_parse(str, &_color_poi))
-        _color_poi = DEFAULT_COLOR_POI;
+static gboolean
+settings_dialog_colors(GtkWidget *widget, GtkWidget *parent)
+{
+    GtkWidget *dialog;
+    GtkWidget *table;
+    GtkWidget *label;
+    GtkWidget *btn_defaults;
+    ColorsDialogInfo cdi;
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
+    dialog = gtk_dialog_new_with_buttons(_("Colors"),
+            GTK_WINDOW(parent), GTK_DIALOG_MODAL,
+            GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+            NULL);
 
-    g_object_unref(gconf_client);
+    gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
+            btn_defaults = gtk_button_new_with_label(_("Defaults")));
+    g_signal_connect(G_OBJECT(btn_defaults), "clicked",
+                      G_CALLBACK(settings_dialog_colors_reset), &cdi);
 
-    /* GPS data init */
-    _gps.fix = 1;
-    _gps.satinuse = 0;
-    _gps.satinview = 0;
+    gtk_dialog_add_button(GTK_DIALOG(dialog),
+            GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
+    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
+            table = gtk_table_new(4, 3, FALSE), TRUE, TRUE, 0);
 
-static void
-menu_maps_remove_repos()
-{
-    GList *curr;
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    /* Mark. */
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("GPS Mark")),
+            0, 1, 0, 1, GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            cdi.col_mark = hildon_color_button_new(),
+            1, 2, 0, 1, 0, 0, 2, 4);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi.col_mark), &_color_mark);
+    gtk_table_attach(GTK_TABLE(table),
+            cdi.col_mark_velocity = hildon_color_button_new(),
+            2, 3, 0, 1, 0, 0, 2, 4);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi.col_mark_velocity), &_color_mark_velocity);
+    gtk_table_attach(GTK_TABLE(table),
+            cdi.col_mark_old = hildon_color_button_new(),
+            3, 4, 0, 1, 0, 0, 2, 4);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi.col_mark_old), &_color_mark_old);
 
-    /* Delete one menu item for each repo. */
-    for(curr = _repo_list; curr; curr = curr->next)
-    {
-        gtk_widget_destroy(gtk_container_get_children(
-                    GTK_CONTAINER(_menu_maps_submenu))->data);
-    }
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
+    /* Track. */
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Track")),
+            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),
+            cdi.col_track = hildon_color_button_new(),
+            1, 2, 1, 2, 0, 0, 2, 4);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi.col_track), &_color_track);
+    gtk_table_attach(GTK_TABLE(table),
+            cdi.col_track_break = hildon_color_button_new(),
+            2, 3, 1, 2, 0, 0, 2, 4);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi.col_track_break), &_color_track_break);
 
-static void
-menu_maps_add_repos()
-{
-    GList *curr;
-    GtkWidget *last_repo = NULL;
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    /* Route. */
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Route")),
+            0, 1, 2, 3, GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            cdi.col_route = hildon_color_button_new(),
+            1, 2, 2, 3, 0, 0, 2, 4);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi.col_route), &_color_route);
+    gtk_table_attach(GTK_TABLE(table),
+            cdi.col_route_way = hildon_color_button_new(),
+            2, 3, 2, 3, 0, 0, 2, 4);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi.col_route_way), &_color_route_way);
+    gtk_table_attach(GTK_TABLE(table),
+            cdi.col_route_nextway = hildon_color_button_new(),
+            3, 4, 2, 3, 0, 0, 2, 4);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi.col_route_nextway), &_color_route_nextway);
 
-    for(curr = g_list_last(_repo_list); curr; curr = curr->prev)
-    {
-        RepoData *rd = (RepoData*)curr->data;
-        GtkWidget *menu_item;
-        if(last_repo)
-            gtk_menu_prepend(_menu_maps_submenu, menu_item
-                    = gtk_radio_menu_item_new_with_label_from_widget(
-                        GTK_RADIO_MENU_ITEM(last_repo), rd->name));
-        else
-        {
-            gtk_menu_prepend(_menu_maps_submenu, menu_item
-                    = gtk_radio_menu_item_new_with_label(NULL, rd->name));
-            last_repo = menu_item;
-        }
-        gtk_check_menu_item_set_active(
-                GTK_CHECK_MENU_ITEM(menu_item),
-                rd == _curr_repo);
-        rd->menu_item = menu_item;
-    }
+    /* POI. */
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("POI")),
+            0, 1, 3, 4, GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            cdi.col_poi = hildon_color_button_new(),
+            1, 2, 3, 4, 0, 0, 2, 4);
+    hildon_color_button_set_color(
+            HILDON_COLOR_BUTTON(cdi.col_poi), &_color_poi);
 
-    /* Add signals (must be after entire menu is built). */
+    gtk_widget_show_all(dialog);
+
+    while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
     {
-        GList *currmi = gtk_container_get_children(
-                GTK_CONTAINER(_menu_maps_submenu));
-        for(curr = _repo_list; curr; curr = curr->next, currmi = currmi->next)
-        {
-            g_signal_connect(G_OBJECT(currmi->data), "activate",
-                             G_CALLBACK(menu_cb_maps_select), curr->data);
-        }
+        GdkColor *color;
+
+        color = hildon_color_button_get_color(
+                HILDON_COLOR_BUTTON(cdi.col_mark));
+        _color_mark = *color;
+
+        color = hildon_color_button_get_color(
+                HILDON_COLOR_BUTTON(cdi.col_mark_velocity));
+        _color_mark_velocity = *color;
+
+        color = hildon_color_button_get_color(
+                HILDON_COLOR_BUTTON(cdi.col_mark_old));
+        _color_mark_old = *color;
+
+        color = hildon_color_button_get_color(
+                HILDON_COLOR_BUTTON(cdi.col_track));
+        _color_track = *color;
+
+        color = hildon_color_button_get_color(
+                HILDON_COLOR_BUTTON(cdi.col_track_break));
+        _color_track_break = *color;
+
+        color = hildon_color_button_get_color(
+                HILDON_COLOR_BUTTON(cdi.col_route));
+        _color_route = *color;
+
+        color = hildon_color_button_get_color(
+                HILDON_COLOR_BUTTON(cdi.col_route_way));
+        _color_route_way = *color;
+
+        color = hildon_color_button_get_color(
+                HILDON_COLOR_BUTTON(cdi.col_route_nextway));
+        _color_route_nextway = *color;
+
+        color = hildon_color_button_get_color(
+                HILDON_COLOR_BUTTON(cdi.col_poi));
+        _color_poi = *color;
+
+        update_gcs();
+        break;
     }
 
-    gtk_widget_show_all(_menu_maps_submenu);
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+    gtk_widget_destroy(dialog);
+
+    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
+    return TRUE;
 }
 
 /**
- * Create the menu items needed for the drop down menu.
+ * Bring up the Settings dialog.  Return TRUE if and only if the recever
+ * information has changed (MAC or channel).
  */
-static void
-menu_init()
+static gboolean
+settings_dialog()
 {
-    /* Create needed handles. */
-    GtkMenu *menu;
-    GtkWidget *submenu;
-    GtkWidget *menu_item;
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    GtkWidget *dialog;
+    GtkWidget *notebook;
+    GtkWidget *table;
+    GtkWidget *hbox;
+    GtkWidget *hbox2;
+    GtkWidget *label;
+    GtkWidget *txt_rcvr_mac;
+    GtkWidget *num_rcvr_chan;
+    GtkWidget *num_center_ratio;
+    GtkWidget *num_lead_ratio;
+    GtkWidget *num_announce_notice;
+    GtkWidget *chk_enable_voice;
+    GtkWidget *num_voice_speed;
+    GtkWidget *num_voice_pitch;
+    GtkWidget *num_draw_line_width;
+    GtkWidget *chk_always_keep_on;
+    GtkWidget *cmb_units;
+    GtkWidget *cmb_escape_key;
+    GtkWidget *btn_scan;
+    GtkWidget *btn_colors;
 
-    /* Get the menu of our view. */
-    menu = GTK_MENU(gtk_menu_new());
+    GtkWidget *txt_poi_db;
+    GtkWidget *btn_browsepoi;
+    GtkWidget *num_poi_zoom;
 
-    /* Create the menu items. */
+    BrowseInfo browse_info = {0, 0};
+    ScanInfo scan_info = {0};
+    gboolean rcvr_changed = FALSE;
+    guint i;
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    /* The "Routes" submenu. */
-    gtk_menu_append(menu, menu_item
-            = gtk_menu_item_new_with_label(_("Route")));
-    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
-            submenu = gtk_menu_new());
-    gtk_menu_append(submenu, _menu_route_open_item
-            = gtk_menu_item_new_with_label(_("Open...")));
-    gtk_menu_append(submenu, _menu_route_download_item
-            = gtk_menu_item_new_with_label(_("Download...")));
-    gtk_menu_append(submenu, _menu_route_save_item
-            = gtk_menu_item_new_with_label(_("Save...")));
-    gtk_menu_append(submenu, _menu_route_reset_item
-        = gtk_menu_item_new_with_label(_("Reset")));
-    gtk_menu_append(submenu, _menu_route_clear_item
-        = gtk_menu_item_new_with_label(_("Clear")));
+    dialog = gtk_dialog_new_with_buttons(_("Maemo Mapper Settings"),
+            GTK_WINDOW(_window), GTK_DIALOG_MODAL,
+            GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+            NULL);
 
-    /* The "Track" submenu. */
-    gtk_menu_append(menu, menu_item
-            = gtk_menu_item_new_with_label(_("Track")));
-    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
-            submenu = gtk_menu_new());
-    gtk_menu_append(submenu, _menu_track_open_item
-            = gtk_menu_item_new_with_label(_("Open...")));
-    gtk_menu_append(submenu, _menu_track_save_item
-            = gtk_menu_item_new_with_label(_("Save...")));
-    gtk_menu_append(submenu, _menu_track_mark_way_item
-            = gtk_menu_item_new_with_label(_("Insert Breakpoint")));
-    gtk_menu_append(submenu, _menu_track_clear_item
-            = gtk_menu_item_new_with_label(_("Clear")));
+    gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
+            btn_colors = gtk_button_new_with_label(_("Colors...")));
 
-    gtk_menu_append(menu, menu_item
-            = gtk_menu_item_new_with_label(_("Maps")));
-    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
-            _menu_maps_submenu = gtk_menu_new());
-    gtk_menu_append(_menu_maps_submenu, gtk_separator_menu_item_new());
-    gtk_menu_append(_menu_maps_submenu, _menu_maps_mapman_item
-            = gtk_menu_item_new_with_label(_("Manage Maps...")));
-    gtk_menu_append(_menu_maps_submenu, _menu_maps_repoman_item
-            = gtk_menu_item_new_with_label(_("Manage Repositories...")));
-    gtk_menu_append(_menu_maps_submenu, _menu_auto_download_item
-            = gtk_check_menu_item_new_with_label(_("Auto-Download")));
-    gtk_check_menu_item_set_active(
-            GTK_CHECK_MENU_ITEM(_menu_auto_download_item), _auto_download);
-    menu_maps_add_repos(_curr_repo);
+    gtk_dialog_add_button(GTK_DIALOG(dialog),
+            GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
 
-    gtk_menu_append(menu, gtk_separator_menu_item_new());
+    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
+            notebook = gtk_notebook_new(), TRUE, TRUE, 0);
 
-    gtk_menu_append(menu, menu_item
-            = gtk_menu_item_new_with_label(_("View")));
-    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
-            submenu = gtk_menu_new());
-    gtk_menu_append(submenu, _menu_fullscreen_item
-            = gtk_check_menu_item_new_with_label(_("Full Screen")));
-    gtk_check_menu_item_set_active(
-            GTK_CHECK_MENU_ITEM(_menu_fullscreen_item), _fullscreen);
-    gtk_menu_append(submenu, _menu_show_routes_item
-            = gtk_check_menu_item_new_with_label(_("Route")));
-    gtk_check_menu_item_set_active(
-            GTK_CHECK_MENU_ITEM(_menu_show_routes_item),
-            _show_tracks & ROUTES_MASK);
-    gtk_menu_append(submenu, _menu_show_tracks_item
-            = gtk_check_menu_item_new_with_label(_("Track")));
-    gtk_check_menu_item_set_active(
-            GTK_CHECK_MENU_ITEM(_menu_show_tracks_item),
-            _show_tracks & TRACKS_MASK);
-    gtk_menu_append(submenu, _menu_show_velvec_item
-            = gtk_check_menu_item_new_with_label(_("Velocity Vector")));
-    gtk_check_menu_item_set_active(
-            GTK_CHECK_MENU_ITEM(_menu_show_velvec_item), _show_velvec);
-    gtk_menu_append(submenu, _menu_poi_item
-            = gtk_menu_item_new_with_label(_("POI Categories...")));
-    gtk_widget_set_sensitive(_menu_poi_item, _dbconn);
+    /* Receiver page. */
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+            table = gtk_table_new(2, 3, FALSE),
+            label = gtk_label_new(_("GPS")));
 
+    /* Receiver MAC Address. */
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("MAC")),
+            0, 1, 0, 1, GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            hbox = gtk_hbox_new(FALSE, 4),
+            1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_box_pack_start(GTK_BOX(hbox),
+            txt_rcvr_mac = gtk_entry_new(),
+            TRUE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(hbox),
+            btn_scan = gtk_button_new_with_label(_("Scan...")),
+            FALSE, FALSE, 0);
 
-    gtk_menu_append(menu, menu_item
-            = gtk_menu_item_new_with_label(_("Auto-Center")));
-    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
-            submenu = gtk_menu_new());
-    gtk_menu_append(submenu, _menu_ac_latlon_item
-            = gtk_radio_menu_item_new_with_label(NULL, _("Lat/Lon")));
-    gtk_check_menu_item_set_active(
-            GTK_CHECK_MENU_ITEM(_menu_ac_latlon_item),
-            _center_mode == CENTER_LATLON);
-    gtk_menu_append(submenu, _menu_ac_lead_item
-            = gtk_radio_menu_item_new_with_label_from_widget(
-                GTK_RADIO_MENU_ITEM(_menu_ac_latlon_item), _("Lead")));
-    gtk_check_menu_item_set_active(
-            GTK_CHECK_MENU_ITEM(_menu_ac_lead_item),
-            _center_mode == CENTER_LEAD);
-    gtk_menu_append(submenu, _menu_ac_none_item
-            = gtk_radio_menu_item_new_with_label_from_widget(
-                GTK_RADIO_MENU_ITEM(_menu_ac_latlon_item), _("None")));
-    gtk_check_menu_item_set_active(
-            GTK_CHECK_MENU_ITEM(_menu_ac_none_item),
-            _center_mode < 0);
+    /* Receiver Channel. */
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Channel")),
+            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),
+            label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
+            1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_container_add(GTK_CONTAINER(label),
+            num_rcvr_chan = hildon_number_editor_new(0, 255));
 
-    gtk_menu_append(menu, menu_item
-            = gtk_menu_item_new_with_label(_("GPS")));
-    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
-            submenu = gtk_menu_new());
-    gtk_menu_append(submenu, _menu_enable_gps_item
-            = gtk_check_menu_item_new_with_label(_("Enable GPS")));
-    gtk_check_menu_item_set_active(
-            GTK_CHECK_MENU_ITEM(_menu_enable_gps_item), _enable_gps);
-    gtk_menu_append(submenu, _menu_gps_show_info_item
-            = gtk_check_menu_item_new_with_label(_("Show Information")));
-    gtk_check_menu_item_set_active(
-            GTK_CHECK_MENU_ITEM(_menu_gps_show_info_item), _gps_info);
-    gtk_menu_append(submenu, _menu_gps_details_item
-            = gtk_menu_item_new_with_label(_("Details...")));
-    gtk_widget_set_sensitive(GTK_WIDGET(_menu_gps_details_item), _enable_gps);
-    gtk_menu_append(submenu, _menu_gps_reset_item
-        = gtk_menu_item_new_with_label(_("Reset Bluetooth")));
-    gtk_widget_set_sensitive(GTK_WIDGET(_menu_gps_reset_item), _enable_gps);
+    /* Note!. */
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(
+                _("Note: \"Channel\" refers to the device side!")),
+            0, 2, 2, 3, GTK_FILL, 0, 2, 4);
+    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
+    gtk_misc_set_alignment(GTK_MISC(label), 0.5f, 0.5f);
 
-    gtk_menu_append(menu, gtk_separator_menu_item_new());
 
-    gtk_menu_append(menu, _menu_settings_item
-        = gtk_menu_item_new_with_label(_("Settings...")));
+    /* Auto-Center page. */
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+            table = gtk_table_new(2, 2, FALSE),
+            label = gtk_label_new(_("Auto-Center")));
 
-    gtk_menu_append(menu, gtk_separator_menu_item_new());
+    /* Auto-Center Sensitivity. */
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Sensitivity")),
+            0, 1, 0, 1, GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
+            1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_container_add(GTK_CONTAINER(label),
+            num_center_ratio = hildon_controlbar_new());
+    hildon_controlbar_set_range(HILDON_CONTROLBAR(num_center_ratio), 1, 10);
+    force_min_visible_bars(HILDON_CONTROLBAR(num_center_ratio), 1);
 
-    gtk_menu_append(menu, _menu_help_item
-        = gtk_menu_item_new_with_label(_("Help")));
+    /* Lead Amount. */
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Lead Amount")),
+            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),
+            label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
+            1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_container_add(GTK_CONTAINER(label),
+            num_lead_ratio = hildon_controlbar_new());
+    hildon_controlbar_set_range(HILDON_CONTROLBAR(num_lead_ratio), 1, 10);
+    force_min_visible_bars(HILDON_CONTROLBAR(num_lead_ratio), 1);
 
-    gtk_menu_append(menu, _menu_close_item
-        = gtk_menu_item_new_with_label(_("Close")));
+    /* Announcement. */
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+            table = gtk_table_new(2, 3, FALSE),
+            label = gtk_label_new(_("Announce")));
 
-    /* We need to show menu items. */
-    gtk_widget_show_all(GTK_WIDGET(menu));
+    /* Announcement Advance Notice. */
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Advance Notice")),
+            0, 1, 0, 1, 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);
+    hildon_controlbar_set_range(HILDON_CONTROLBAR(num_announce_notice), 1, 20);
+    force_min_visible_bars(HILDON_CONTROLBAR(num_announce_notice), 1);
 
-    hildon_window_set_menu(HILDON_WINDOW(_window), menu);
+    /* Enable Voice. */
+    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_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk_enable_voice),
+            _enable_voice);
 
-    /* Connect the signals. */
-    g_signal_connect(G_OBJECT(_menu_route_open_item), "activate",
-                      G_CALLBACK(menu_cb_route_open), NULL);
-    g_signal_connect(G_OBJECT(_menu_route_download_item), "activate",
-                      G_CALLBACK(menu_cb_route_download), NULL);
-    g_signal_connect(G_OBJECT(_menu_route_save_item), "activate",
-                      G_CALLBACK(menu_cb_route_save), NULL);
-    g_signal_connect(G_OBJECT(_menu_route_reset_item), "activate",
-                      G_CALLBACK(menu_cb_route_reset), NULL);
-    g_signal_connect(G_OBJECT(_menu_route_clear_item), "activate",
-                      G_CALLBACK(menu_cb_route_clear), NULL);
-    g_signal_connect(G_OBJECT(_menu_track_open_item), "activate",
-                      G_CALLBACK(menu_cb_track_open), NULL);
-    g_signal_connect(G_OBJECT(_menu_track_save_item), "activate",
-                      G_CALLBACK(menu_cb_track_save), NULL);
-    g_signal_connect(G_OBJECT(_menu_track_mark_way_item), "activate",
-                      G_CALLBACK(menu_cb_track_mark_way), NULL);
-    g_signal_connect(G_OBJECT(_menu_track_clear_item), "activate",
-                      G_CALLBACK(menu_cb_track_clear), NULL);
-    g_signal_connect(G_OBJECT(_menu_show_tracks_item), "toggled",
-                      G_CALLBACK(menu_cb_show_tracks), NULL);
-    g_signal_connect(G_OBJECT(_menu_show_routes_item), "toggled",
-                      G_CALLBACK(menu_cb_show_routes), NULL);
-    g_signal_connect(G_OBJECT(_menu_show_velvec_item), "toggled",
-                      G_CALLBACK(menu_cb_show_velvec), NULL);
-    g_signal_connect(G_OBJECT(_menu_poi_item), "activate",
-                      G_CALLBACK(menu_cb_category), NULL);
+    /* Voice Speed and Pitch. */
+    gtk_table_attach(GTK_TABLE(table),
+            hbox = gtk_hbox_new(FALSE, 12),
+            0, 2, 2, 3, 0, 0, 2, 6);
+    gtk_box_pack_start(GTK_BOX(hbox),
+            hbox2 = gtk_hbox_new(FALSE, 4),
+            TRUE, TRUE, 4);
+    gtk_box_pack_start(GTK_BOX(hbox2),
+            label = gtk_label_new(_("Speed")),
+            TRUE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(hbox2),
+            num_voice_speed = hildon_controlbar_new(),
+            TRUE, TRUE, 0);
+    hildon_controlbar_set_range(HILDON_CONTROLBAR(num_voice_speed), 1, 10);
+    force_min_visible_bars(HILDON_CONTROLBAR(num_voice_speed), 1);
 
-    g_signal_connect(G_OBJECT(_menu_maps_repoman_item), "activate",
-                      G_CALLBACK(menu_cb_maps_repoman), NULL);
-    g_signal_connect(G_OBJECT(_menu_maps_mapman_item), "activate",
-                      G_CALLBACK(menu_cb_mapman), NULL);
-    g_signal_connect(G_OBJECT(_menu_ac_latlon_item), "toggled",
-                      G_CALLBACK(menu_cb_ac_latlon), NULL);
-    g_signal_connect(G_OBJECT(_menu_ac_lead_item), "toggled",
-                      G_CALLBACK(menu_cb_ac_lead), NULL);
-    g_signal_connect(G_OBJECT(_menu_ac_none_item), "toggled",
-                      G_CALLBACK(menu_cb_ac_none), NULL);
-    g_signal_connect(G_OBJECT(_menu_fullscreen_item), "toggled",
-                      G_CALLBACK(menu_cb_fullscreen), NULL);
-    g_signal_connect(G_OBJECT(_menu_enable_gps_item), "toggled",
-                      G_CALLBACK(menu_cb_enable_gps), NULL);
-    g_signal_connect(G_OBJECT(_menu_gps_show_info_item), "toggled",
-                      G_CALLBACK(menu_cb_gps_show_info), NULL);
-    g_signal_connect(G_OBJECT(_menu_gps_details_item), "activate",
-                      G_CALLBACK(menu_cb_gps_details), NULL);
-    g_signal_connect(G_OBJECT(_menu_gps_reset_item), "activate",
-                      G_CALLBACK(menu_cb_gps_reset), NULL);
-    g_signal_connect(G_OBJECT(_menu_auto_download_item), "toggled",
-                      G_CALLBACK(menu_cb_auto_download), NULL);
-    g_signal_connect(G_OBJECT(_menu_settings_item), "activate",
-                      G_CALLBACK(menu_cb_settings), NULL);
-    g_signal_connect(G_OBJECT(_menu_help_item), "activate",
-                      G_CALLBACK(menu_cb_help), NULL);
-    g_signal_connect(G_OBJECT(_menu_close_item), "activate",
-                      G_CALLBACK(gtk_main_quit), NULL);
+    gtk_box_pack_start(GTK_BOX(hbox),
+            hbox2 = gtk_hbox_new(FALSE, 4),
+            TRUE, TRUE, 4);
+    gtk_box_pack_start(GTK_BOX(hbox2),
+            label = gtk_label_new(_("Pitch")),
+            TRUE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(hbox2),
+            num_voice_pitch = hildon_controlbar_new(),
+            TRUE, TRUE, 0);
+    hildon_controlbar_set_range(HILDON_CONTROLBAR(num_voice_pitch), -2, 8);
+    force_min_visible_bars(HILDON_CONTROLBAR(num_voice_pitch), 1);
 
-    /* Setup the context menu. */
-    menu = GTK_MENU(gtk_menu_new());
+    /* Misc. page. */
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+            table = gtk_table_new(2, 3, FALSE),
+            label = gtk_label_new(_("Misc.")));
 
-    /* Setup the map context menu. */
-    gtk_menu_append(menu, menu_item
-            = gtk_menu_item_new_with_label(_("Location")));
-    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
-            submenu = gtk_menu_new());
+    /* Line Width. */
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Line Width")),
+            0, 1, 0, 1, GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            num_draw_line_width = hildon_controlbar_new(),
+            1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    hildon_controlbar_set_range(HILDON_CONTROLBAR(num_draw_line_width), 1, 20);
+    force_min_visible_bars(HILDON_CONTROLBAR(num_draw_line_width), 1);
 
-    /* Setup the map context menu. */
-    gtk_menu_append(submenu, _cmenu_loc_show_latlon_item
-            = gtk_menu_item_new_with_label(_("Show Lat/Lon")));
-    gtk_menu_append(submenu, _cmenu_loc_clip_latlon_item
-            = gtk_menu_item_new_with_label(_("Copy Lat/Lon to Clipboard")));
-    gtk_menu_append(submenu, gtk_separator_menu_item_new());
-    gtk_menu_append(submenu, _cmenu_loc_route_to_item
-            = gtk_menu_item_new_with_label(_("Download Route to...")));
-    gtk_menu_append(submenu, _cmenu_loc_distance_to_item
-            = gtk_menu_item_new_with_label(_("Show Distance to")));
-    gtk_menu_append(submenu, gtk_separator_menu_item_new());
-    gtk_menu_append(submenu, _cmenu_add_poi
-                = gtk_menu_item_new_with_label(_("Add POI")));
-    gtk_widget_set_sensitive(_cmenu_add_poi, _dbconn);
-    gtk_menu_append(submenu, _cmenu_edit_poi
-                = gtk_menu_item_new_with_label(_("Edit POI")));
-    gtk_widget_set_sensitive(_cmenu_edit_poi, _dbconn);
+    /* Keep Display On Only When Fullscreen. */
+    gtk_table_attach(GTK_TABLE(table),
+            chk_always_keep_on = gtk_check_button_new_with_label(
+                _("Keep Display On Only in Fullscreen Mode")),
+            0, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
 
-    /* Setup the waypoint context menu. */
-    gtk_menu_append(menu, menu_item
-            = gtk_menu_item_new_with_label(_("Waypoint")));
-    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
-            submenu = gtk_menu_new());
+    /* Units. */
+    gtk_table_attach(GTK_TABLE(table),
+            hbox = gtk_hbox_new(FALSE, 4),
+            0, 2, 2, 3, GTK_FILL, 0, 2, 4);
+    gtk_box_pack_start(GTK_BOX(hbox),
+            label = gtk_label_new(_("Units")),
+            FALSE, FALSE, 0);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_box_pack_start(GTK_BOX(hbox),
+            label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
+            TRUE, TRUE, 0);
+    gtk_container_add(GTK_CONTAINER(label),
+            cmb_units = gtk_combo_box_new_text());
+    for(i = 0; i < UNITS_ENUM_COUNT; i++)
+        gtk_combo_box_append_text(GTK_COMBO_BOX(cmb_units), UNITS_TEXT[i]);
 
-    gtk_menu_append(submenu, _cmenu_way_show_latlon_item
-            = gtk_menu_item_new_with_label(_("Show Lat/Lon")));
-    gtk_menu_append(submenu, _cmenu_way_show_desc_item
-            = gtk_menu_item_new_with_label(_("Show Description")));
-    gtk_menu_append(submenu, _cmenu_way_clip_latlon_item
-            = gtk_menu_item_new_with_label(_("Copy Lat/Lon to Clipboard")));
-    gtk_menu_append(submenu, _cmenu_way_clip_desc_item
-            = gtk_menu_item_new_with_label(_("Copy Description to Clipboard")));
-    gtk_menu_append(submenu, gtk_separator_menu_item_new());
-    gtk_menu_append(submenu, _cmenu_way_route_to_item
-            = gtk_menu_item_new_with_label(_("Download Route to...")));
-    gtk_menu_append(submenu, _cmenu_way_distance_to_item
-            = gtk_menu_item_new_with_label(_("Show Distance to")));
-    gtk_menu_append(submenu, _cmenu_way_delete_item
-            = gtk_menu_item_new_with_label(_("Delete")));
+    /* Escape Key. */
+    gtk_box_pack_start(GTK_BOX(hbox),
+            label = gtk_label_new(_("Escape Key")),
+            FALSE, FALSE, 0);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_box_pack_start(GTK_BOX(hbox),
+            label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
+            TRUE, TRUE, 0);
+    gtk_container_add(GTK_CONTAINER(label),
+            cmb_escape_key = gtk_combo_box_new_text());
+    for(i = 0; i < ESCAPE_KEY_ENUM_COUNT; i++)
+        gtk_combo_box_append_text(GTK_COMBO_BOX(cmb_escape_key),
+                ESCAPE_KEY_TEXT[i]);
 
-    /* Connect signals for context menu. */
-    g_signal_connect(G_OBJECT(_cmenu_loc_show_latlon_item), "activate",
-                      G_CALLBACK(cmenu_cb_loc_show_latlon), NULL);
-    g_signal_connect(G_OBJECT(_cmenu_loc_clip_latlon_item), "activate",
-                      G_CALLBACK(cmenu_cb_loc_clip_latlon), NULL);
-    g_signal_connect(G_OBJECT(_cmenu_loc_route_to_item), "activate",
-                      G_CALLBACK(cmenu_cb_loc_route_to), NULL);
-    g_signal_connect(G_OBJECT(_cmenu_loc_distance_to_item), "activate",
-                      G_CALLBACK(cmenu_cb_loc_distance_to), NULL);
-    g_signal_connect(G_OBJECT(_cmenu_add_poi), "activate",
-                        G_CALLBACK(cmenu_cb_add_poi), NULL);
-    g_signal_connect(G_OBJECT(_cmenu_edit_poi), "activate",
-                        G_CALLBACK(cmenu_cb_edit_poi), NULL);
-    g_signal_connect(G_OBJECT(_cmenu_way_show_latlon_item), "activate",
-                      G_CALLBACK(cmenu_cb_way_show_latlon), NULL);
-    g_signal_connect(G_OBJECT(_cmenu_way_show_desc_item), "activate",
-                      G_CALLBACK(cmenu_cb_way_show_desc), NULL);
-    g_signal_connect(G_OBJECT(_cmenu_way_clip_latlon_item), "activate",
-                      G_CALLBACK(cmenu_cb_way_clip_latlon), NULL);
-    g_signal_connect(G_OBJECT(_cmenu_way_clip_desc_item), "activate",
-                      G_CALLBACK(cmenu_cb_way_clip_desc), NULL);
-    g_signal_connect(G_OBJECT(_cmenu_way_route_to_item), "activate",
-                      G_CALLBACK(cmenu_cb_way_route_to), NULL);
-    g_signal_connect(G_OBJECT(_cmenu_way_distance_to_item), "activate",
-                      G_CALLBACK(cmenu_cb_way_distance_to), NULL);
-    g_signal_connect(G_OBJECT(_cmenu_way_delete_item), "activate",
-                      G_CALLBACK(cmenu_cb_way_delete), NULL);
+    /* POI page */
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+            table = gtk_table_new(2, 3, FALSE),
+            label = gtk_label_new(_("POI")));
 
-    gtk_widget_show_all(GTK_WIDGET(menu));
+    /* POI database. */
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("POI database")),
+            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),
+            hbox = gtk_hbox_new(FALSE, 4),
+            1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_box_pack_start(GTK_BOX(hbox),
+            txt_poi_db = gtk_entry_new(),
+            TRUE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(hbox),
+            btn_browsepoi = gtk_button_new_with_label(_("Browse...")),
+            FALSE, FALSE, 0);
 
-    gtk_widget_tap_and_hold_setup(_map_widget, GTK_WIDGET(menu), NULL, 0);
+    /* Show POI below zoom. */
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_label_new(_("Show POI below zoom")),
+            0, 1, 2, 3, GTK_FILL, 0, 2, 4);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
+    gtk_table_attach(GTK_TABLE(table),
+            label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
+            1, 2, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 4);
+    gtk_container_add(GTK_CONTAINER(label),
+            num_poi_zoom = hildon_number_editor_new(0, MAX_ZOOM));
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
 
-/**
- * Call gtk_window_present() on Maemo Mapper.  This also checks the
- * configuration and brings up the Settings dialog if the GPS Receiver is
- * not set up, the first time it is called.
- */
-static gboolean
-window_present()
-{
-    static gint been_here = 0;
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    /* Connect signals. */
+    scan_info.settings_dialog = dialog;
+    scan_info.txt_rcvr_mac = txt_rcvr_mac;
+    g_signal_connect(G_OBJECT(btn_scan), "clicked",
+                      G_CALLBACK(scan_bluetooth), &scan_info);
+    g_signal_connect(G_OBJECT(btn_colors), "clicked",
+                      G_CALLBACK(settings_dialog_colors), dialog);
 
-    if(!been_here++)
-    {
-        /* Set connection state first, to avoid going into this if twice. */
-        if(_rcvr_mac || !_enable_gps || settings_dialog())
-        {
-            gtk_widget_show_all(_window);
-            gps_show_info();
+    browse_info.dialog = dialog;
+    browse_info.txt = txt_poi_db;
+    g_signal_connect(G_OBJECT(btn_browsepoi), "clicked",
+                      G_CALLBACK(settings_dialog_browse_forfile), &browse_info);
 
-            /* Connect to receiver. */
-            if(_enable_gps)
-                rcvr_connect_now();
-        }
-        else
-            gtk_main_quit();
-    }
-    gtk_window_present(GTK_WINDOW(_window));
-
-    /* Re-enable any banners that might have been up. */
-    {
-        ConnState old_state = _conn_state;
-        set_conn_state(RCVR_OFF);
-        set_conn_state(old_state);
-    }
+    /* Initialize fields. */
+    if(_rcvr_mac)
+        gtk_entry_set_text(GTK_ENTRY(txt_rcvr_mac), _rcvr_mac);
+    hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(num_rcvr_chan),
+            _rcvr_addr.rc_channel);
+    if(_poi_db)
+        gtk_entry_set_text(GTK_ENTRY(txt_poi_db), _poi_db);
+    hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(num_poi_zoom),
+            _poi_zoom);
+    hildon_controlbar_set_value(HILDON_CONTROLBAR(num_center_ratio),
+            _center_ratio);
+    hildon_controlbar_set_value(HILDON_CONTROLBAR(num_lead_ratio),
+            _lead_ratio);
+    hildon_controlbar_set_value(HILDON_CONTROLBAR(num_announce_notice),
+            _announce_notice_ratio);
+    hildon_controlbar_set_value(HILDON_CONTROLBAR(num_voice_speed),
+            (gint)(_voice_speed * 3 + 0.5));
+    hildon_controlbar_set_value(HILDON_CONTROLBAR(num_voice_pitch),
+            _voice_pitch);
+    hildon_controlbar_set_value(HILDON_CONTROLBAR(num_draw_line_width),
+            _draw_line_width);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk_always_keep_on),
+            !_always_keep_on);
+    gtk_combo_box_set_active(GTK_COMBO_BOX(cmb_units), _units);
+    gtk_combo_box_set_active(GTK_COMBO_BOX(cmb_escape_key), _escape_key);
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-    return FALSE;
-}
+    gtk_widget_show_all(dialog);
 
-/**
- * Get the hash value of a ProgressUpdateInfo object.  This is trivial, since
- * the hash is generated and stored when the object is created.
- */
-static guint
-download_hashfunc(ProgressUpdateInfo *pui)
-{
-    vprintf("%s()\n", __PRETTY_FUNCTION__);
+    while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
+    {
+        /* Set _rcvr_mac if necessary. */
+        if(!*gtk_entry_get_text(GTK_ENTRY(txt_rcvr_mac)))
+        {
+            /* User specified no rcvr mac - set _rcvr_mac to NULL. */
+            if(_rcvr_mac)
+            {
+                g_free(_rcvr_mac);
+                _rcvr_mac = NULL;
+                rcvr_changed = TRUE;
+                gtk_widget_set_sensitive(
+                        GTK_WIDGET(_menu_gps_details_item), FALSE);
+            }
+            if(_enable_gps)
+            {
+                gtk_check_menu_item_set_active(
+                        GTK_CHECK_MENU_ITEM(_menu_enable_gps_item), FALSE);
+                popup_error(dialog, _("No GPS Receiver MAC Provided.\n"
+                        "GPS Disabled."));
+                rcvr_changed = TRUE;
+                gtk_widget_set_sensitive(GTK_WIDGET(_menu_gps_details_item),
+                        FALSE);
+                gtk_widget_set_sensitive(GTK_WIDGET(_menu_gps_reset_item),
+                        FALSE);
+            }
+        }
+        else if(!_rcvr_mac || strcmp(_rcvr_mac,
+                      gtk_entry_get_text(GTK_ENTRY(txt_rcvr_mac))))
+        {
+            /* User specified a new rcvr mac. */
+            g_free(_rcvr_mac);
+            _rcvr_mac = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_rcvr_mac)));
+            str2ba(_rcvr_mac, &_rcvr_addr.rc_bdaddr);
+            rcvr_changed = TRUE;
+        }
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-    return pui->hash;
-}
+        if(_rcvr_addr.rc_channel != hildon_number_editor_get_value(
+                    HILDON_NUMBER_EDITOR(num_rcvr_chan)))
+        {
+            _rcvr_addr.rc_channel = hildon_number_editor_get_value(
+                    HILDON_NUMBER_EDITOR(num_rcvr_chan));
+            rcvr_changed = TRUE;
+        }
 
-/**
- * Return whether or not two ProgressUpdateInfo objects are equal.  They
- * are equal if they are downloading the same tile.
- */
-static gboolean
-download_equalfunc(
-        ProgressUpdateInfo *pui1, ProgressUpdateInfo *pui2)
-{
-    vprintf("%s()\n", __PRETTY_FUNCTION__);
+        _center_ratio = hildon_controlbar_get_value(
+                HILDON_CONTROLBAR(num_center_ratio));
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-    return pui1->tilex == pui2->tilex && pui1->tiley == pui2->tiley
-        && pui1->zoom == pui2->zoom;
-}
+        _lead_ratio = hildon_controlbar_get_value(
+                HILDON_CONTROLBAR(num_lead_ratio));
 
-/**
- * Draw the current mark (representing the current GPS location) onto
- * _map_widget.  This method does not queue the draw area.
- */
-static void
-map_draw_mark()
-{
-    printf("%s()\n", __PRETTY_FUNCTION__);
+        _draw_line_width = hildon_controlbar_get_value(
+                HILDON_CONTROLBAR(num_draw_line_width));
 
-    if(_enable_gps)
-    {
-        gdk_draw_arc(
-                _map_widget->window,
-                _conn_state == RCVR_FIXED ? _gc_mark : _gc_mark_old,
-                FALSE, /* not filled. */
-                _mark_x1 - _draw_line_width, _mark_y1 - _draw_line_width,
-                2 * _draw_line_width, 2 * _draw_line_width,
-                0, 360 * 64);
-        gdk_draw_line(
-                _map_widget->window,
-                _conn_state == RCVR_FIXED
-                    ? (_show_velvec ? _gc_mark_velocity : _gc_mark)
-                    : _gc_mark_old,
-                _mark_x1, _mark_y1, _mark_x2, _mark_y2);
-    }
+        _always_keep_on = !gtk_toggle_button_get_active(
+                GTK_TOGGLE_BUTTON(chk_always_keep_on));
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
+        _units = gtk_combo_box_get_active(GTK_COMBO_BOX(cmb_units));
+        _escape_key = gtk_combo_box_get_active(GTK_COMBO_BOX(cmb_escape_key));
 
-/**
- * "Set" the mark, which translates the current GPS position into on-screen
- * units in preparation for drawing the mark with map_draw_mark().
- */
-static void map_set_mark()
-{
-    printf("%s()\n", __PRETTY_FUNCTION__);
+        _announce_notice_ratio = hildon_controlbar_get_value(
+                HILDON_CONTROLBAR(num_announce_notice));
 
-    _mark_x1 = unit2x(_pos.unitx);
-    _mark_y1 = unit2y(_pos.unity);
-    _mark_x2 = _mark_x1 + (_show_velvec ? _vel_offsetx : 0);
-    _mark_y2 = _mark_y1 + (_show_velvec ? _vel_offsety : 0);
-    _mark_minx = MIN(_mark_x1, _mark_x2) - (2 * _draw_line_width);
-    _mark_miny = MIN(_mark_y1, _mark_y2) - (2 * _draw_line_width);
-    _mark_width = abs(_mark_x1 - _mark_x2) + (4 * _draw_line_width);
-    _mark_height = abs(_mark_y1 - _mark_y2) + (4 * _draw_line_width);
+        _voice_speed = hildon_controlbar_get_value(
+                HILDON_CONTROLBAR(num_voice_speed)) / 3.0;
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
+        _voice_pitch = hildon_controlbar_get_value(
+                HILDON_CONTROLBAR(num_voice_pitch));
 
-/**
- * Do an in-place scaling of a pixbuf's pixels at the given ratio from the
- * given source location.  It would have been nice if gdk_pixbuf provided
- * this method, but I guess it's not general-purpose enough.
- */
-static void
-map_pixbuf_scale_inplace(guchar *pixels, guint ratio_p2,
-        guint src_x, guint src_y)
-{
-    guint dest_x = 0, dest_y = 0, dest_dim = TILE_SIZE_PIXELS;
-    vprintf("%s(%d, %d, %d)\n", __PRETTY_FUNCTION__, ratio_p2, src_x, src_y);
+        _enable_voice = gtk_toggle_button_get_active(
+                GTK_TOGGLE_BUTTON(chk_enable_voice));
 
-    /* Sweep through the entire dest area, copying as necessary, but
-     * DO NOT OVERWRITE THE SOURCE AREA.  We'll copy it afterward. */
-    do {
-        guint src_dim = dest_dim >> ratio_p2;
-        guint src_endx = src_x - dest_x + src_dim;
-        gint x, y;
-        for(y = dest_dim - 1; y >= 0; y--)
+        if(_dbconn)
         {
-            guint src_offset_y, dest_offset_y;
-            src_offset_y = (src_y + (y >> ratio_p2)) * TILE_PIXBUF_STRIDE;
-            dest_offset_y = (dest_y + y) * TILE_PIXBUF_STRIDE;
-            x = dest_dim - 1;
-            if((unsigned)(dest_y + y - src_y) < src_dim
-                    && (unsigned)(dest_x + x - src_x) < src_dim)
-                x -= src_dim;
-            for(; x >= 0; x--)
-            {
-                guint src_offset, dest_offset;
-                src_offset = src_offset_y + (src_x + (x >> ratio_p2)) * 3;
-                dest_offset = dest_offset_y + (dest_x + x) * 3;
-                pixels[dest_offset + 0] = pixels[src_offset + 0];
-                pixels[dest_offset + 1] = pixels[src_offset + 1];
-                pixels[dest_offset + 2] = pixels[src_offset + 2];
-                if((unsigned)(dest_y + y - src_y) < src_dim && x == src_endx)
-                    x -= src_dim;
-            }
+            sqlite_close(_db);
+            _dbconn = FALSE;
+            gtk_widget_set_sensitive(_cmenu_add_poi, FALSE);
+            gtk_widget_set_sensitive(_cmenu_edit_poi, FALSE);
+            gtk_widget_set_sensitive(_menu_poi_item, FALSE);
         }
-        /* Reuse src_dim and src_endx to store new src_x and src_y. */
-        src_dim = src_x + ((src_x - dest_x) >> ratio_p2);
-        src_endx = src_y + ((src_y - dest_y) >> ratio_p2);
-        dest_x = src_x;
-        dest_y = src_y;
-        src_x = src_dim;
-        src_y = src_endx;
-    }
-    while((dest_dim >>= ratio_p2) > 1);
+        g_free(_poi_db);
+        if(strlen(gtk_entry_get_text(GTK_ENTRY(txt_poi_db))))
+        {
+            _poi_db = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_poi_db)));
+            db_connect();
+            gtk_widget_set_sensitive(_cmenu_add_poi, _dbconn);
+            gtk_widget_set_sensitive(_cmenu_edit_poi, _dbconn);
+            gtk_widget_set_sensitive(_menu_poi_item, _dbconn);
+        }
+        else
+            _poi_db = NULL;
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
+        _poi_zoom = hildon_number_editor_get_value(
+        HILDON_NUMBER_EDITOR(num_poi_zoom));
 
-/**
- * Free a ProgressUpdateInfo data structure that was allocated during the
- * auto-map-download process.
- */
-static void
-progress_update_info_free(ProgressUpdateInfo *pui)
-{
-    vprintf("%s()\n", __PRETTY_FUNCTION__);
+        update_gcs();
 
-    gnome_vfs_uri_unref((GnomeVFSURI*)pui->src_list->data);
-    g_list_free(pui->src_list);
-    gnome_vfs_uri_unref((GnomeVFSURI*)pui->dest_list->data);
-    g_list_free(pui->dest_list);
-    g_free(pui);
+        config_save();
+        break;
+    }
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+    gtk_widget_hide(dialog); /* Destroying causes a crash (!?!?!??!) */
+
+    vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, rcvr_changed);
+    return rcvr_changed;
 }
 
 /**
- * Given the xyz coordinates of our map coordinate system, write the qrst
- * quadtree coordinates to buffer.
+ * Initialize all configuration from GCONF.  This should not be called more
+ * than once during execution.
  */
 static void
-map_convert_coords_to_quadtree_string(int x, int y, int zoomlevel,gchar *buffer)
+config_init()
 {
-    static const gchar *const quadrant = "qrts";
-    gchar *ptr = buffer;
-    int n;
-    *ptr++ = 't';
-    for(n = 16 - zoomlevel; n >= 0; n--)
+    GConfValue *value;
+    GConfClient *gconf_client = gconf_client_get_default();
+    gchar *str;
+    printf("%s()\n", __PRETTY_FUNCTION__);
+
+    if(!gconf_client)
     {
-        int xbit = (x >> n) & 1;
-        int ybit = (y >> n) & 1;
-        *ptr++ = quadrant[xbit + 2 * ybit];
+        popup_error(_window, _("Failed to initialize GConf.  Quitting."));
+        exit(1);
     }
-    *ptr++ = '\0';
-}
 
-/**
- * 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 void
-map_construct_url(gchar *buffer, guint tilex, guint tiley, guint zoom)
-{
-    if(strstr(_curr_repo->url, "%s"))
+    /* Initialize _config_dir. */
     {
-        /* This is a satellite-map URI. */
-        gchar location[MAX_ZOOM + 2];
-        map_convert_coords_to_quadtree_string(tilex, tiley, zoom, location);
-        sprintf(buffer, _curr_repo->url, location);
+        gchar *config_dir;
+        config_dir = gnome_vfs_expand_initial_tilde(CONFIG_DIR_NAME);
+        _config_dir_uri = gnome_vfs_make_uri_from_input(config_dir);
+        gnome_vfs_make_directory(_config_dir_uri, 0700);
+        g_free(config_dir);
     }
-    else
-        /* This is a street-map URI. */
-        sprintf(buffer, _curr_repo->url, tilex, tiley, zoom);
-}
 
+    /* Retrieve route. */
+    {
+        gchar *route_file;
+        gchar *bytes;
+        gint size;
 
-/**
- * Initiate a download of the given xyz coordinates using the given buffer
- * as the URL.  If the map already exists on disk, or if we are already
- * downloading the map, then this method does nothing.
- */
-static gboolean
-map_initiate_download(guint tilex, guint tiley, guint zoom, gint retries)
-{
-    gchar buffer[1024];
-    GnomeVFSURI *src, *dest;
-    GList *src_list, *dest_list;
-    gint priority;
-    ProgressUpdateInfo *pui;
-    vprintf("%s(%u, %u, %u, %d)\n", __PRETTY_FUNCTION__, tilex, tiley, zoom,
-            retries);
+        route_file = gnome_vfs_uri_make_full_from_relative(
+                _config_dir_uri, CONFIG_FILE_ROUTE);
+        if(GNOME_VFS_OK == gnome_vfs_read_entire_file(
+                    route_file, &size, &bytes))
+            parse_route_gpx(bytes, size, 0); /* 0 to replace route. */
+        g_free(route_file);
+    }
 
-    pui = g_new(ProgressUpdateInfo, 1);
-    pui->hash = tilex + (tiley << 12) + (zoom << 24);
-    pui->tilex = tilex;
-    pui->tiley = tiley;
-    pui->zoom = zoom;
-    if(g_hash_table_lookup(_downloads_hash, pui))
+    /* Retrieve track. */
     {
-        /* Already downloading - return FALSE. */
-        g_free(pui);
-        return FALSE;
+        gchar *track_file;
+        gchar *bytes;
+        gint size;
+
+        track_file = gnome_vfs_uri_make_full_from_relative(
+                _config_dir_uri, CONFIG_FILE_TRACK);
+        if(GNOME_VFS_OK == gnome_vfs_read_entire_file(
+                    track_file, &size, &bytes))
+            parse_track_gpx(bytes, size, 0); /* 0 to replace track. */
+        g_free(track_file);
     }
-    sprintf(buffer, "%s/%u/%u/%u.jpg", _curr_repo->cache_dir,
-            zoom, tilex, tiley);
-    dest = gnome_vfs_uri_new(buffer);
-    if(retries > 0 && gnome_vfs_uri_exists(dest))
+
+    /* Get Receiver MAC from GConf.  Default is scanned via hci_inquiry. */
     {
-        /* Already downloaded and not overwriting - return FALSE. */
-        gnome_vfs_uri_unref(dest);
-        g_free(pui);
-        return FALSE;
+        _rcvr_mac = gconf_client_get_string(
+                gconf_client, GCONF_KEY_RCVR_MAC, NULL);
+        if(_rcvr_mac)
+            str2ba(_rcvr_mac, &_rcvr_addr.rc_bdaddr);
     }
 
-    /* Priority is based on proximity to _center.unitx - lower number means
-     * higher priority, so the further we are, the higher the number. */
-    priority = GNOME_VFS_PRIORITY_MIN
-        + unit2ptile(abs(tile2punit(tilex, zoom) - _center.unitx)
-                + abs(tile2punit(tiley, zoom) - _center.unity));
-    BOUND(priority, GNOME_VFS_PRIORITY_MIN, GNOME_VFS_PRIORITY_MAX);
+    /* Get Receiver Channel from GConf.  Default is 1. */
+    _rcvr_addr.rc_family = AF_BLUETOOTH;
+    _rcvr_addr.rc_channel = gconf_client_get_int(gconf_client,
+            GCONF_KEY_RCVR_CHAN, NULL);
+    if(_rcvr_addr.rc_channel < 1)
+        _rcvr_addr.rc_channel = 1;
 
-    map_construct_url(buffer, tilex, tiley, zoom);
-    src = gnome_vfs_uri_new(buffer);
+    /* Get Auto-Download.  Default is FALSE. */
+    _auto_download = gconf_client_get_bool(gconf_client,
+            GCONF_KEY_AUTO_DOWNLOAD, NULL);
 
-    src_list = g_list_prepend(src_list = NULL, src);
-    dest_list = g_list_prepend(dest_list = NULL, dest);
+    /* Get Center Ratio - Default is 3. */
+    _center_ratio = gconf_client_get_int(gconf_client,
+            GCONF_KEY_CENTER_SENSITIVITY, NULL);
+    if(!_center_ratio)
+        _center_ratio = 7;
 
-    pui->src_list = src_list;
-    pui->dest_list = dest_list;
-    pui->retries_left = retries;
+    /* Get Lead Ratio - Default is 5. */
+    _lead_ratio = gconf_client_get_int(gconf_client,
+            GCONF_KEY_LEAD_AMOUNT, NULL);
+    if(!_lead_ratio)
+        _lead_ratio = 5;
 
-    /* Initiate asynchronous download. */
-    if(retries)
+    /* Get Draw Line Width- Default is 5. */
+    _draw_line_width = gconf_client_get_int(gconf_client,
+            GCONF_KEY_DRAW_LINE_WIDTH, NULL);
+    if(!_draw_line_width)
+        _draw_line_width = 5;
+
+    /* Get Announce Advance Notice - Default is 30. */
+    value = gconf_client_get(gconf_client, GCONF_KEY_ANNOUNCE_NOTICE, NULL);
+    if(value)
     {
-        /* This is a download; if retries < 0, then this is an overwrite */
-        if(GNOME_VFS_OK != gnome_vfs_async_xfer(
-                    &pui->handle,
-                    src_list, dest_list,
-                    retries < 0 ? GNOME_VFS_XFER_DEFAULT
-                                : GNOME_VFS_XFER_USE_UNIQUE_NAMES,
-                    GNOME_VFS_XFER_ERROR_MODE_QUERY,
-                    retries < 0 ? GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE
-                                : GNOME_VFS_XFER_OVERWRITE_MODE_QUERY,
-                    priority,
-                    (GnomeVFSAsyncXferProgressCallback)map_download_cb_async,
-                    pui,
-                    (GnomeVFSXferProgressCallback)gtk_true,
-                    NULL))
-        {
-            progress_update_info_free(pui);
-            return FALSE;
-        }
+        _announce_notice_ratio = gconf_value_get_int(value);
+        gconf_value_free(value);
     }
     else
+        _announce_notice_ratio = 8;
+
+    /* Get Enable Voice flag.  Default is TRUE. */
+    value = gconf_client_get(gconf_client, GCONF_KEY_ENABLE_VOICE, NULL);
+    if(value)
     {
-        /* This is a deletion. */
-        if(GNOME_VFS_OK != gnome_vfs_async_xfer(
-                    &pui->handle,
-                    dest_list, NULL,
-                    GNOME_VFS_XFER_DELETE_ITEMS,
-                    GNOME_VFS_XFER_ERROR_MODE_QUERY,
-                    GNOME_VFS_XFER_OVERWRITE_MODE_QUERY,
-                    priority,
-                    (GnomeVFSAsyncXferProgressCallback)map_download_cb_async,
-                    pui,
-                    (GnomeVFSXferProgressCallback)gtk_true,
-                    NULL))
-        {
-            progress_update_info_free(pui);
-            return FALSE;
-        }
+        _enable_voice = gconf_value_get_bool(value);
+        gconf_value_free(value);
     }
+    else
+        _enable_voice = TRUE;
 
-    g_hash_table_insert(_downloads_hash, pui, pui);
-    if(!_num_downloads++ && !_download_banner)
-        _download_banner = hildon_banner_show_progress(
-                _window, NULL, _("Downloading maps"));
+    /* Get Voice Speed - Default is 1.0. */
+    value = gconf_client_get(gconf_client, GCONF_KEY_VOICE_SPEED, NULL);
+    if(value)
+    {
+        _voice_speed = gconf_value_get_float(value);
+        gconf_value_free(value);
+    }
+    else
+        _voice_speed = 1.0;
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-    return TRUE;
-}
+    /* Get Voice Speed - Default is 0. */
+    value = gconf_client_get(gconf_client, GCONF_KEY_VOICE_PITCH, NULL);
+    if(value)
+    {
+        _voice_pitch = gconf_value_get_int(value);
+        gconf_value_free(value);
+    }
+    else
+        _voice_pitch = 3;
 
-static void
-map_render_poi()
-{
-    guint unitx, unity;
-    gfloat lat1, lat2, lon1, lon2, tmp;
-    gchar slat1[10], slat2[10], slon1[10], slon2[10];
-    gchar buffer[100];
-    gchar **pszResult;
-    gint nRow, nColumn, row, poix, poiy;
-    GdkPixbuf *pixbuf = NULL;
-    GError *error = NULL;
+    /* Get Always Keep On flag.  Default is FALSE. */
+    _always_keep_on = gconf_client_get_bool(gconf_client,
+            GCONF_KEY_ALWAYS_KEEP_ON, NULL);
 
-    if(_db && _poi_zoom > _zoom)
+    /* Get Units.  Default is UNITS_KM. */
     {
-        unitx = x2unit(1);
-        unity = y2unit(1);
-        unit2latlon(unitx, unity, lat1, lon1);
-        unitx = x2unit(BUF_WIDTH_PIXELS);
-        unity = y2unit(BUF_HEIGHT_PIXELS);
-        unit2latlon(unitx, unity, lat2, lon2);
-        if(lat1 > lat2)
-        {
-            tmp = lat2;
-            lat2 = lat1;
-            lat1 = tmp;
-        }
-        if(lon1 > lon2)
+        gchar *units_str = gconf_client_get_string(gconf_client,
+                GCONF_KEY_UNITS, NULL);
+        guint i = 0;
+        if(units_str)
+            for(i = UNITS_ENUM_COUNT - 1; i > 0; i--)
+                if(!strcmp(units_str, UNITS_TEXT[i]))
+                    break;
+        _units = i;
+    }
+
+    /* Get Escape Key.  Default is ESCAPE_KEY_TOGGLE_TRACKS. */
+    {
+        gchar *escape_key_str = gconf_client_get_string(gconf_client,
+                GCONF_KEY_ESCAPE_KEY, NULL);
+        guint i = 0;
+        if(escape_key_str)
+            for(i = ESCAPE_KEY_ENUM_COUNT - 1; i > 0; i--)
+                if(!strcmp(escape_key_str, ESCAPE_KEY_TEXT[i]))
+                    break;
+        _escape_key = i;
+    }
+
+    /* Get last saved latitude.  Default is 0. */
+    _pos_lat = gconf_client_get_float(gconf_client, GCONF_KEY_LAT, NULL);
+
+    /* Get last saved longitude.  Default is somewhere in Midwest. */
+    value = gconf_client_get(gconf_client, GCONF_KEY_LON, NULL);
+    _pos_lon = gconf_client_get_float(gconf_client, GCONF_KEY_LON, NULL);
+
+    /* Get last center point. */
+    {
+        gfloat center_lat, center_lon;
+
+        /* Get last saved latitude.  Default is last saved latitude. */
+        value = gconf_client_get(gconf_client, GCONF_KEY_CENTER_LAT, NULL);
+        if(value)
         {
-            tmp = lon2;
-            lon2 = lon1;
-            lon1 = tmp;
+            center_lat = gconf_value_get_float(value);
+            gconf_value_free(value);
         }
+        else
+            center_lat = _pos_lat;
+
+        /* Get last saved longitude.  Default is last saved longitude. */
+        value = gconf_client_get(gconf_client, GCONF_KEY_CENTER_LON, NULL);
+        if(value)
+        {
+            center_lon = gconf_value_get_float(value);
+            gconf_value_free(value);
+        }
+        else
+            center_lon = _pos_lon;
+
+        latlon2unit(center_lat, center_lon, _center.unitx, _center.unity);
+    }
+
+    /* Load the repositories. */
+    {
+        GSList *list, *curr;
+        guint curr_repo_index = gconf_client_get_int(gconf_client,
+            GCONF_KEY_CURRREPO, NULL);
+        list = gconf_client_get_list(gconf_client,
+            GCONF_KEY_REPOSITORIES, GCONF_VALUE_STRING, NULL);
+
+        for(curr = list; curr != NULL; curr = curr->next)
+        {
+            /* Parse each part of a repo, delimited by newline characters:
+             * 1. url
+             * 2. cache_dir
+             * 3. dl_zoom_steps
+             * 4. view_zoom_steps
+             */
+            gchar *str = curr->data;
+            RepoData *rd = g_new(RepoData, 1);
+            rd->name = g_strdup(strsep(&str, "\n"));
+            rd->url = g_strdup(strsep(&str, "\n"));
+            rd->cache_dir = g_strdup(strsep(&str, "\n"));
+            if(!(rd->dl_zoom_steps = atoi(strsep(&str, "\n"))))
+                rd->dl_zoom_steps = 2;
+            if(!(rd->view_zoom_steps = atoi(strsep(&str, "\n"))))
+                rd->view_zoom_steps = 1;
+
+            _repo_list = g_list_append(_repo_list, rd);
+            if(!curr_repo_index--)
+                _curr_repo = rd;
+            g_free(curr->data);
+        }
+        g_slist_free(list);
+    }
+
+    if(_repo_list == NULL)
+    {
+        /* We have no repositories - create a default one. */
+        _curr_repo = g_new(RepoData, 1);
+
+        /* Many fields can be retrieved from the "old" gconf keys. */
+
+        /* Get Map Cache Dir.  Default is ~/MyDocs/.documents/Maps. */
+        _curr_repo->cache_dir = gconf_client_get_string(gconf_client,
+                GCONF_KEY_MAP_DIR_NAME, NULL);
+
+        if(!_curr_repo->cache_dir)
+            _curr_repo->cache_dir = gnome_vfs_expand_initial_tilde(
+                    "~/MyDocs/.documents/Maps");
+
+        /* Get Map Download URI Format.  Default is "". */
+        _curr_repo->url = gconf_client_get_string(gconf_client,
+                GCONF_KEY_MAP_URI_FORMAT, NULL);
+        if(!_curr_repo->url)
+            _curr_repo->url = g_strdup("");
+
+        /* Get Map Download Zoom Steps.  Default is 2. */
+        _curr_repo->dl_zoom_steps = gconf_client_get_int(gconf_client,
+                GCONF_KEY_MAP_ZOOM_STEPS, NULL);
+        if(!_curr_repo->dl_zoom_steps)
+            _curr_repo->dl_zoom_steps = 2;
+
+        /* Other fields are brand new. */
+        _curr_repo->name = g_strdup("Default");
+        _curr_repo->view_zoom_steps = 1;
+        _repo_list = g_list_append(_repo_list, _curr_repo);
+    }
+
+    /* Get last Zoom Level.  Default is 16. */
+    value = gconf_client_get(gconf_client, GCONF_KEY_ZOOM, NULL);
+    if(value)
+    {
+        _zoom = gconf_value_get_int(value) / _curr_repo->view_zoom_steps
+            * _curr_repo->view_zoom_steps;
+        gconf_value_free(value);
+    }
+    else
+        _zoom = 16 / _curr_repo->view_zoom_steps
+            * _curr_repo->view_zoom_steps;
+    BOUND(_zoom, 0, MAX_ZOOM - 1);
+    _world_size_tiles = unit2tile(WORLD_SIZE_UNITS);
+
+    /* Speed and Heading are always initialized as 0. */
+    _speed = 0.f;
+    _heading = 0.f;
+
+    /* Get Route Directory.  Default is NULL. */
+    _route_dir_uri = gconf_client_get_string(gconf_client,
+            GCONF_KEY_ROUTEDIR, NULL);
+
+    /* Get Last Track File.  Default is NULL. */
+    _track_file_uri = gconf_client_get_string(gconf_client,
+            GCONF_KEY_TRACKFILE, NULL);
+
+    /* Get Auto-Center Mode.  Default is CENTER_LEAD. */
+    value = gconf_client_get(gconf_client, GCONF_KEY_AUTOCENTER_MODE, NULL);
+    if(value)
+    {
+        _center_mode = gconf_value_get_int(value);
+        gconf_value_free(value);
+    }
+    else
+        _center_mode = CENTER_LEAD;
+
+    /* Get Show Tracks flag.  Default is TRUE. */
+    value = gconf_client_get(gconf_client, GCONF_KEY_SHOWTRACKS, NULL);
+    if(value)
+    {
+        _show_tracks |= (gconf_value_get_bool(value) ? TRACKS_MASK : 0);
+        gconf_value_free(value);
+    }
+    else
+        _show_tracks |= TRACKS_MASK;
+
+    /* Get Show Routes flag.  Default is TRUE. */
+    value = gconf_client_get(gconf_client, GCONF_KEY_SHOWROUTES, NULL);
+    if(value)
+    {
+        _show_tracks |= (gconf_value_get_bool(value) ? ROUTES_MASK : 0);
+        gconf_value_free(value);
+    }
+    else
+        _show_tracks |= ROUTES_MASK;
+
+    /* Get Show Velocity Vector flag.  Default is TRUE. */
+    value = gconf_client_get(gconf_client, GCONF_KEY_SHOWVELVEC, NULL);
+    if(value)
+    {
+        _show_velvec = gconf_value_get_bool(value);
+        gconf_value_free(value);
+    }
+    else
+        _show_velvec = TRUE;
+
+    /* Get Enable GPS flag.  Default is TRUE. */
+    value = gconf_client_get(gconf_client, GCONF_KEY_ENABLE_GPS, NULL);
+    if(value)
+    {
+        _enable_gps = gconf_value_get_bool(value);
+        gconf_value_free(value);
+    }
+    else
+        _enable_gps = TRUE;
+
+    /* Initialize _conn_state based on _enable_gps. */
+    _conn_state = (_enable_gps ? RCVR_DOWN : RCVR_OFF);
+
+    /* Load the route locations. */
+    {
+        GSList *curr;
+        _loc_list = gconf_client_get_list(gconf_client,
+            GCONF_KEY_ROUTE_LOCATIONS, GCONF_VALUE_STRING, NULL);
+        _loc_model = gtk_list_store_new(1, G_TYPE_STRING);
+        for(curr = _loc_list; curr != NULL; curr = curr->next)
+        {
+            GtkTreeIter iter;
+            gtk_list_store_insert_with_values(_loc_model, &iter, INT_MAX,
+                    0, curr->data, -1);
+        }
+    }
+
+    /* Get POI Database.  Default is in ~/MyDocs/.documents/Maps */
+    _poi_db = gconf_client_get_string(gconf_client,
+            GCONF_KEY_POI_DB, NULL);
+    if(_poi_db == NULL)
+        _poi_db = gnome_vfs_make_uri_full_from_relative(
+                _curr_repo->cache_dir, "poi.db");
+    db_connect();
+
+    _poi_zoom = gconf_client_get_int(gconf_client,
+            GCONF_KEY_POI_ZOOM, NULL);
+    if(!_poi_zoom)
+    _poi_zoom = 6;
+
+
+    /* Get GPS Info flag.  Default is FALSE. */
+    value = gconf_client_get(gconf_client, GCONF_KEY_GPS_INFO, NULL);
+    if(value)
+    {
+        _gps_info = gconf_value_get_bool(value);
+        gconf_value_free(value);
+    }
+    else
+        _gps_info = FALSE;
+
+    /* Get Route Download Radius.  Default is 4. */
+    value = gconf_client_get(gconf_client, GCONF_KEY_ROUTE_DL_RADIUS, NULL);
+    if(value)
+    {
+        _route_dl_radius = gconf_value_get_int(value);
+        gconf_value_free(value);
+    }
+    else
+        _route_dl_radius = 4;
+
+    /* Initialize colors. */
+    str = gconf_client_get_string(gconf_client,
+            GCONF_KEY_COLOR_MARK, NULL);
+    if(!str || !gdk_color_parse(str, &_color_mark))
+        _color_mark = DEFAULT_COLOR_MARK;
+
+    str = gconf_client_get_string(gconf_client,
+            GCONF_KEY_COLOR_MARK_VELOCITY, NULL);
+    if(!str || !gdk_color_parse(str, &_color_mark_velocity))
+        _color_mark_velocity = DEFAULT_COLOR_MARK_VELOCITY;
+
+    str = gconf_client_get_string(gconf_client,
+            GCONF_KEY_COLOR_MARK_OLD, NULL);
+    if(!str || !gdk_color_parse(str, &_color_mark_old))
+        _color_mark_old = DEFAULT_COLOR_MARK_OLD;
+
+    str = gconf_client_get_string(gconf_client,
+            GCONF_KEY_COLOR_TRACK, NULL);
+    if(!str || !gdk_color_parse(str, &_color_track))
+        _color_track = DEFAULT_COLOR_TRACK;
+
+    str = gconf_client_get_string(gconf_client,
+            GCONF_KEY_COLOR_TRACK_BREAK, NULL);
+    if(!str || !gdk_color_parse(str, &_color_track_break))
+        _color_track_break = DEFAULT_COLOR_TRACK_BREAK;
+
+    str = gconf_client_get_string(gconf_client,
+            GCONF_KEY_COLOR_ROUTE, NULL);
+    if(!str || !gdk_color_parse(str, &_color_route))
+        _color_route = DEFAULT_COLOR_ROUTE;
+
+    str = gconf_client_get_string(gconf_client,
+            GCONF_KEY_COLOR_ROUTE_WAY, NULL);
+    if(!str || !gdk_color_parse(str, &_color_route_way))
+        _color_route_way = DEFAULT_COLOR_ROUTE_WAY;
+
+    str = gconf_client_get_string(gconf_client,
+            GCONF_KEY_COLOR_ROUTE_NEXTWAY, NULL);
+    if(!str || !gdk_color_parse(str, &_color_route_nextway))
+        _color_route_nextway = DEFAULT_COLOR_ROUTE_NEXTWAY;
+
+    str = gconf_client_get_string(gconf_client,
+            GCONF_KEY_COLOR_POI, NULL);
+    if(!str || !gdk_color_parse(str, &_color_poi))
+        _color_poi = DEFAULT_COLOR_POI;
+
+
+    g_object_unref(gconf_client);
+
+    /* GPS data init */
+    _gps.fix = 1;
+    _gps.satinuse = 0;
+    _gps.satinview = 0;
+
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
+
+static void
+menu_maps_remove_repos()
+{
+    GList *curr;
+    printf("%s()\n", __PRETTY_FUNCTION__);
+
+    /* Delete one menu item for each repo. */
+    for(curr = _repo_list; curr; curr = curr->next)
+    {
+        gtk_widget_destroy(gtk_container_get_children(
+                    GTK_CONTAINER(_menu_maps_submenu))->data);
+    }
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
+
+static void
+menu_maps_add_repos()
+{
+    GList *curr;
+    GtkWidget *last_repo = NULL;
+    printf("%s()\n", __PRETTY_FUNCTION__);
+
+    for(curr = g_list_last(_repo_list); curr; curr = curr->prev)
+    {
+        RepoData *rd = (RepoData*)curr->data;
+        GtkWidget *menu_item;
+        if(last_repo)
+            gtk_menu_prepend(_menu_maps_submenu, menu_item
+                    = gtk_radio_menu_item_new_with_label_from_widget(
+                        GTK_RADIO_MENU_ITEM(last_repo), rd->name));
+        else
+        {
+            gtk_menu_prepend(_menu_maps_submenu, menu_item
+                    = gtk_radio_menu_item_new_with_label(NULL, rd->name));
+            last_repo = menu_item;
+        }
+        gtk_check_menu_item_set_active(
+                GTK_CHECK_MENU_ITEM(menu_item),
+                rd == _curr_repo);
+        rd->menu_item = menu_item;
+    }
+
+    /* Add signals (must be after entire menu is built). */
+    {
+        GList *currmi = gtk_container_get_children(
+                GTK_CONTAINER(_menu_maps_submenu));
+        for(curr = _repo_list; curr; curr = curr->next, currmi = currmi->next)
+        {
+            g_signal_connect(G_OBJECT(currmi->data), "activate",
+                             G_CALLBACK(menu_cb_maps_select), curr->data);
+        }
+    }
+
+    gtk_widget_show_all(_menu_maps_submenu);
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
+
+/**
+ * Create the menu items needed for the drop down menu.
+ */
+static void
+menu_init()
+{
+    /* Create needed handles. */
+    GtkMenu *menu;
+    GtkWidget *submenu;
+    GtkWidget *menu_item;
+    printf("%s()\n", __PRETTY_FUNCTION__);
+
+    /* Get the menu of our view. */
+    menu = GTK_MENU(gtk_menu_new());
+
+    /* Create the menu items. */
+
+    /* The "Routes" submenu. */
+    gtk_menu_append(menu, menu_item
+            = gtk_menu_item_new_with_label(_("Route")));
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
+            submenu = gtk_menu_new());
+    gtk_menu_append(submenu, _menu_route_open_item
+            = gtk_menu_item_new_with_label(_("Open...")));
+    gtk_menu_append(submenu, _menu_route_download_item
+            = gtk_menu_item_new_with_label(_("Download...")));
+    gtk_menu_append(submenu, _menu_route_save_item
+            = gtk_menu_item_new_with_label(_("Save...")));
+    gtk_menu_append(submenu, _menu_route_reset_item
+        = gtk_menu_item_new_with_label(_("Reset")));
+    gtk_menu_append(submenu, _menu_route_clear_item
+        = gtk_menu_item_new_with_label(_("Clear")));
 
-        g_ascii_dtostr(slat1, sizeof(slat1), lat1);
-        g_ascii_dtostr(slat2, sizeof(slat2), lat2);
-        g_ascii_dtostr(slon1, sizeof(slon1), lon1);
-        g_ascii_dtostr(slon2, sizeof(slon2), lon2);
+    /* The "Track" submenu. */
+    gtk_menu_append(menu, menu_item
+            = gtk_menu_item_new_with_label(_("Track")));
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
+            submenu = gtk_menu_new());
+    gtk_menu_append(submenu, _menu_track_open_item
+            = gtk_menu_item_new_with_label(_("Open...")));
+    gtk_menu_append(submenu, _menu_track_save_item
+            = gtk_menu_item_new_with_label(_("Save...")));
+    gtk_menu_append(submenu, _menu_track_mark_way_item
+            = gtk_menu_item_new_with_label(_("Insert Breakpoint")));
+    gtk_menu_append(submenu, _menu_track_clear_item
+            = gtk_menu_item_new_with_label(_("Clear")));
+
+    gtk_menu_append(menu, menu_item
+            = gtk_menu_item_new_with_label(_("Maps")));
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
+            _menu_maps_submenu = gtk_menu_new());
+    gtk_menu_append(_menu_maps_submenu, gtk_separator_menu_item_new());
+    gtk_menu_append(_menu_maps_submenu, _menu_maps_mapman_item
+            = gtk_menu_item_new_with_label(_("Manage Maps...")));
+    gtk_menu_append(_menu_maps_submenu, _menu_maps_repoman_item
+            = gtk_menu_item_new_with_label(_("Manage Repositories...")));
+    gtk_menu_append(_menu_maps_submenu, _menu_auto_download_item
+            = gtk_check_menu_item_new_with_label(_("Auto-Download")));
+    gtk_check_menu_item_set_active(
+            GTK_CHECK_MENU_ITEM(_menu_auto_download_item), _auto_download);
+    menu_maps_add_repos(_curr_repo);
+
+    gtk_menu_append(menu, gtk_separator_menu_item_new());
+
+    gtk_menu_append(menu, menu_item
+            = gtk_menu_item_new_with_label(_("View")));
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
+            submenu = gtk_menu_new());
+    gtk_menu_append(submenu, _menu_fullscreen_item
+            = gtk_check_menu_item_new_with_label(_("Full Screen")));
+    gtk_check_menu_item_set_active(
+            GTK_CHECK_MENU_ITEM(_menu_fullscreen_item), _fullscreen);
+    gtk_menu_append(submenu, _menu_show_routes_item
+            = gtk_check_menu_item_new_with_label(_("Route")));
+    gtk_check_menu_item_set_active(
+            GTK_CHECK_MENU_ITEM(_menu_show_routes_item),
+            _show_tracks & ROUTES_MASK);
+    gtk_menu_append(submenu, _menu_show_tracks_item
+            = gtk_check_menu_item_new_with_label(_("Track")));
+    gtk_check_menu_item_set_active(
+            GTK_CHECK_MENU_ITEM(_menu_show_tracks_item),
+            _show_tracks & TRACKS_MASK);
+    gtk_menu_append(submenu, _menu_show_velvec_item
+            = gtk_check_menu_item_new_with_label(_("Velocity Vector")));
+    gtk_check_menu_item_set_active(
+            GTK_CHECK_MENU_ITEM(_menu_show_velvec_item), _show_velvec);
+    gtk_menu_append(submenu, _menu_poi_item
+            = gtk_menu_item_new_with_label(_("POI Categories...")));
+    gtk_widget_set_sensitive(_menu_poi_item, _dbconn);
+
+
+    gtk_menu_append(menu, menu_item
+            = gtk_menu_item_new_with_label(_("Auto-Center")));
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
+            submenu = gtk_menu_new());
+    gtk_menu_append(submenu, _menu_ac_latlon_item
+            = gtk_radio_menu_item_new_with_label(NULL, _("Lat/Lon")));
+    gtk_check_menu_item_set_active(
+            GTK_CHECK_MENU_ITEM(_menu_ac_latlon_item),
+            _center_mode == CENTER_LATLON);
+    gtk_menu_append(submenu, _menu_ac_lead_item
+            = gtk_radio_menu_item_new_with_label_from_widget(
+                GTK_RADIO_MENU_ITEM(_menu_ac_latlon_item), _("Lead")));
+    gtk_check_menu_item_set_active(
+            GTK_CHECK_MENU_ITEM(_menu_ac_lead_item),
+            _center_mode == CENTER_LEAD);
+    gtk_menu_append(submenu, _menu_ac_none_item
+            = gtk_radio_menu_item_new_with_label_from_widget(
+                GTK_RADIO_MENU_ITEM(_menu_ac_latlon_item), _("None")));
+    gtk_check_menu_item_set_active(
+            GTK_CHECK_MENU_ITEM(_menu_ac_none_item),
+            _center_mode < 0);
+
+    gtk_menu_append(menu, menu_item
+            = gtk_menu_item_new_with_label(_("GPS")));
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
+            submenu = gtk_menu_new());
+    gtk_menu_append(submenu, _menu_enable_gps_item
+            = gtk_check_menu_item_new_with_label(_("Enable GPS")));
+    gtk_check_menu_item_set_active(
+            GTK_CHECK_MENU_ITEM(_menu_enable_gps_item), _enable_gps);
+    gtk_menu_append(submenu, _menu_gps_show_info_item
+            = gtk_check_menu_item_new_with_label(_("Show Information")));
+    gtk_check_menu_item_set_active(
+            GTK_CHECK_MENU_ITEM(_menu_gps_show_info_item), _gps_info);
+    gtk_menu_append(submenu, _menu_gps_details_item
+            = gtk_menu_item_new_with_label(_("Details...")));
+    gtk_widget_set_sensitive(GTK_WIDGET(_menu_gps_details_item), _enable_gps);
+    gtk_menu_append(submenu, _menu_gps_reset_item
+        = gtk_menu_item_new_with_label(_("Reset Bluetooth")));
+    gtk_widget_set_sensitive(GTK_WIDGET(_menu_gps_reset_item), _enable_gps);
+
+    gtk_menu_append(menu, gtk_separator_menu_item_new());
+
+    gtk_menu_append(menu, _menu_settings_item
+        = gtk_menu_item_new_with_label(_("Settings...")));
+
+    gtk_menu_append(menu, gtk_separator_menu_item_new());
+
+    gtk_menu_append(menu, _menu_help_item
+        = gtk_menu_item_new_with_label(_("Help")));
+
+    gtk_menu_append(menu, _menu_close_item
+        = gtk_menu_item_new_with_label(_("Close")));
+
+    /* We need to show menu items. */
+    gtk_widget_show_all(GTK_WIDGET(menu));
+
+    hildon_window_set_menu(HILDON_WINDOW(_window), menu);
+
+    /* Connect the signals. */
+    g_signal_connect(G_OBJECT(_menu_route_open_item), "activate",
+                      G_CALLBACK(menu_cb_route_open), NULL);
+    g_signal_connect(G_OBJECT(_menu_route_download_item), "activate",
+                      G_CALLBACK(menu_cb_route_download), NULL);
+    g_signal_connect(G_OBJECT(_menu_route_save_item), "activate",
+                      G_CALLBACK(menu_cb_route_save), NULL);
+    g_signal_connect(G_OBJECT(_menu_route_reset_item), "activate",
+                      G_CALLBACK(menu_cb_route_reset), NULL);
+    g_signal_connect(G_OBJECT(_menu_route_clear_item), "activate",
+                      G_CALLBACK(menu_cb_route_clear), NULL);
+    g_signal_connect(G_OBJECT(_menu_track_open_item), "activate",
+                      G_CALLBACK(menu_cb_track_open), NULL);
+    g_signal_connect(G_OBJECT(_menu_track_save_item), "activate",
+                      G_CALLBACK(menu_cb_track_save), NULL);
+    g_signal_connect(G_OBJECT(_menu_track_mark_way_item), "activate",
+                      G_CALLBACK(menu_cb_track_mark_way), NULL);
+    g_signal_connect(G_OBJECT(_menu_track_clear_item), "activate",
+                      G_CALLBACK(menu_cb_track_clear), NULL);
+    g_signal_connect(G_OBJECT(_menu_show_tracks_item), "toggled",
+                      G_CALLBACK(menu_cb_show_tracks), NULL);
+    g_signal_connect(G_OBJECT(_menu_show_routes_item), "toggled",
+                      G_CALLBACK(menu_cb_show_routes), NULL);
+    g_signal_connect(G_OBJECT(_menu_show_velvec_item), "toggled",
+                      G_CALLBACK(menu_cb_show_velvec), NULL);
+    g_signal_connect(G_OBJECT(_menu_poi_item), "activate",
+                      G_CALLBACK(menu_cb_category), NULL);
+
+    g_signal_connect(G_OBJECT(_menu_maps_repoman_item), "activate",
+                      G_CALLBACK(menu_cb_maps_repoman), NULL);
+    g_signal_connect(G_OBJECT(_menu_maps_mapman_item), "activate",
+                      G_CALLBACK(menu_cb_mapman), NULL);
+    g_signal_connect(G_OBJECT(_menu_ac_latlon_item), "toggled",
+                      G_CALLBACK(menu_cb_ac_latlon), NULL);
+    g_signal_connect(G_OBJECT(_menu_ac_lead_item), "toggled",
+                      G_CALLBACK(menu_cb_ac_lead), NULL);
+    g_signal_connect(G_OBJECT(_menu_ac_none_item), "toggled",
+                      G_CALLBACK(menu_cb_ac_none), NULL);
+    g_signal_connect(G_OBJECT(_menu_fullscreen_item), "toggled",
+                      G_CALLBACK(menu_cb_fullscreen), NULL);
+    g_signal_connect(G_OBJECT(_menu_enable_gps_item), "toggled",
+                      G_CALLBACK(menu_cb_enable_gps), NULL);
+    g_signal_connect(G_OBJECT(_menu_gps_show_info_item), "toggled",
+                      G_CALLBACK(menu_cb_gps_show_info), NULL);
+    g_signal_connect(G_OBJECT(_menu_gps_details_item), "activate",
+                      G_CALLBACK(menu_cb_gps_details), NULL);
+    g_signal_connect(G_OBJECT(_menu_gps_reset_item), "activate",
+                      G_CALLBACK(menu_cb_gps_reset), NULL);
+    g_signal_connect(G_OBJECT(_menu_auto_download_item), "toggled",
+                      G_CALLBACK(menu_cb_auto_download), NULL);
+    g_signal_connect(G_OBJECT(_menu_settings_item), "activate",
+                      G_CALLBACK(menu_cb_settings), NULL);
+    g_signal_connect(G_OBJECT(_menu_help_item), "activate",
+                      G_CALLBACK(menu_cb_help), NULL);
+    g_signal_connect(G_OBJECT(_menu_close_item), "activate",
+                      G_CALLBACK(gtk_main_quit), NULL);
+
+    /* Setup the context menu. */
+    menu = GTK_MENU(gtk_menu_new());
+
+    /* Setup the map context menu. */
+    gtk_menu_append(menu, menu_item
+            = gtk_menu_item_new_with_label(_("Location")));
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
+            submenu = gtk_menu_new());
+
+    /* Setup the map context menu. */
+    gtk_menu_append(submenu, _cmenu_loc_show_latlon_item
+            = gtk_menu_item_new_with_label(_("Show Lat/Lon")));
+    gtk_menu_append(submenu, _cmenu_loc_clip_latlon_item
+            = gtk_menu_item_new_with_label(_("Copy Lat/Lon to Clipboard")));
+    gtk_menu_append(submenu, gtk_separator_menu_item_new());
+    gtk_menu_append(submenu, _cmenu_loc_route_to_item
+            = gtk_menu_item_new_with_label(_("Download Route to...")));
+    gtk_menu_append(submenu, _cmenu_loc_distance_to_item
+            = gtk_menu_item_new_with_label(_("Show Distance to")));
+    gtk_menu_append(submenu, gtk_separator_menu_item_new());
+    gtk_menu_append(submenu, _cmenu_add_poi
+                = gtk_menu_item_new_with_label(_("Add POI")));
+    gtk_widget_set_sensitive(_cmenu_add_poi, _dbconn);
+    gtk_menu_append(submenu, _cmenu_edit_poi
+                = gtk_menu_item_new_with_label(_("Edit POI")));
+    gtk_widget_set_sensitive(_cmenu_edit_poi, _dbconn);
+
+    /* Setup the waypoint context menu. */
+    gtk_menu_append(menu, menu_item
+            = gtk_menu_item_new_with_label(_("Waypoint")));
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
+            submenu = gtk_menu_new());
+
+    gtk_menu_append(submenu, _cmenu_way_show_latlon_item
+            = gtk_menu_item_new_with_label(_("Show Lat/Lon")));
+    gtk_menu_append(submenu, _cmenu_way_show_desc_item
+            = gtk_menu_item_new_with_label(_("Show Description")));
+    gtk_menu_append(submenu, _cmenu_way_clip_latlon_item
+            = gtk_menu_item_new_with_label(_("Copy Lat/Lon to Clipboard")));
+    gtk_menu_append(submenu, _cmenu_way_clip_desc_item
+            = gtk_menu_item_new_with_label(_("Copy Description to Clipboard")));
+    gtk_menu_append(submenu, gtk_separator_menu_item_new());
+    gtk_menu_append(submenu, _cmenu_way_route_to_item
+            = gtk_menu_item_new_with_label(_("Download Route to...")));
+    gtk_menu_append(submenu, _cmenu_way_distance_to_item
+            = gtk_menu_item_new_with_label(_("Show Distance to")));
+    gtk_menu_append(submenu, _cmenu_way_delete_item
+            = gtk_menu_item_new_with_label(_("Delete")));
+
+    /* Connect signals for context menu. */
+    g_signal_connect(G_OBJECT(_cmenu_loc_show_latlon_item), "activate",
+                      G_CALLBACK(cmenu_cb_loc_show_latlon), NULL);
+    g_signal_connect(G_OBJECT(_cmenu_loc_clip_latlon_item), "activate",
+                      G_CALLBACK(cmenu_cb_loc_clip_latlon), NULL);
+    g_signal_connect(G_OBJECT(_cmenu_loc_route_to_item), "activate",
+                      G_CALLBACK(cmenu_cb_loc_route_to), NULL);
+    g_signal_connect(G_OBJECT(_cmenu_loc_distance_to_item), "activate",
+                      G_CALLBACK(cmenu_cb_loc_distance_to), NULL);
+    g_signal_connect(G_OBJECT(_cmenu_add_poi), "activate",
+                        G_CALLBACK(cmenu_cb_add_poi), NULL);
+    g_signal_connect(G_OBJECT(_cmenu_edit_poi), "activate",
+                        G_CALLBACK(cmenu_cb_edit_poi), NULL);
+    g_signal_connect(G_OBJECT(_cmenu_way_show_latlon_item), "activate",
+                      G_CALLBACK(cmenu_cb_way_show_latlon), NULL);
+    g_signal_connect(G_OBJECT(_cmenu_way_show_desc_item), "activate",
+                      G_CALLBACK(cmenu_cb_way_show_desc), NULL);
+    g_signal_connect(G_OBJECT(_cmenu_way_clip_latlon_item), "activate",
+                      G_CALLBACK(cmenu_cb_way_clip_latlon), NULL);
+    g_signal_connect(G_OBJECT(_cmenu_way_clip_desc_item), "activate",
+                      G_CALLBACK(cmenu_cb_way_clip_desc), NULL);
+    g_signal_connect(G_OBJECT(_cmenu_way_route_to_item), "activate",
+                      G_CALLBACK(cmenu_cb_way_route_to), NULL);
+    g_signal_connect(G_OBJECT(_cmenu_way_distance_to_item), "activate",
+                      G_CALLBACK(cmenu_cb_way_distance_to), NULL);
+    g_signal_connect(G_OBJECT(_cmenu_way_delete_item), "activate",
+                      G_CALLBACK(cmenu_cb_way_delete), NULL);
 
-        if(SQLITE_OK == sqlite_get_table_printf(_db,
-                    "select p.lat, p.lon, lower(p.label), lower(c.label)"
-                    " from poi p, category c "
-                    " where p.lat between %s and %s "
-                    " and p.lon  between %s and %s "
-                    " and c.enabled = 1 and p.cat_id = c.cat_id",
-                    &pszResult, &nRow, &nColumn, NULL,
-                    slat1, slat2, slon1, slon2))
-        {
-            for(row=1; row<nRow+1; row++)
-            {
-                lat1 = g_ascii_strtod(pszResult[row*nColumn+0], NULL);
-                lon1 = g_ascii_strtod(pszResult[row*nColumn+1], NULL);
-                latlon2unit(lat1, lon1, unitx, unity);
-                poix = unit2bufx(unitx);
-                poiy = unit2bufy(unity);
+    gtk_widget_show_all(GTK_WIDGET(menu));
 
-                /* Try to get icon for specific POI first. */
-                sprintf(buffer, "%s/poi/%s.jpg", _curr_repo->cache_dir,
-                    pszResult[row*nColumn+2]);
-                pixbuf = gdk_pixbuf_new_from_file(buffer, &error);
-                if(error)
-                {
-                    /* No icon for specific POI - try for category. */
-                    error = NULL;
-                    sprintf(buffer, "%s/poi/%s.jpg", _curr_repo->cache_dir,
-                        pszResult[row*nColumn+3]);
-                    pixbuf = gdk_pixbuf_new_from_file(buffer, &error);
-                }
-                if(error)
-                {
-                    /* No icon for POI or for category - draw default. */
-                    error = NULL;
-                    gdk_draw_rectangle(_map_pixmap, _gc_poi, TRUE,
-                        poix - (int)(0.5f * _draw_line_width),
-                        poiy - (int)(0.5f * _draw_line_width),
-                        3 * _draw_line_width,
-                        3 * _draw_line_width);
-                }
-                else
-                {
-                    gdk_draw_pixbuf(
-                            _map_pixmap,
-                            _gc_poi,
-                            pixbuf,
-                            0, 0,
-                            poix - gdk_pixbuf_get_width(pixbuf) / 2,
-                            poiy - gdk_pixbuf_get_height(pixbuf) / 2,
-                            -1,-1,
-                            GDK_RGB_DITHER_NONE, 0, 0);
-                    g_object_unref(pixbuf);
-                }
-             }
-            sqlite_free_table(pszResult);
-        }
-    }
+    gtk_widget_tap_and_hold_setup(_map_widget, GTK_WIDGET(menu), NULL, 0);
 
     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
 }
 
-static void
-map_render_tile(guint tilex, guint tiley, guint destx, guint desty,
-        gboolean fast_fail) {
-    gchar buffer[1024];
-    GdkPixbuf *pixbuf = NULL;
-    GError *error = NULL;
-    guint zoff;
+/**
+ * Call gtk_window_present() on Maemo Mapper.  This also checks the
+ * configuration and brings up the Settings dialog if the GPS Receiver is
+ * not set up, the first time it is called.
+ */
+static gboolean
+window_present()
+{
+    static gint been_here = 0;
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    if(tilex < _world_size_tiles && tiley < _world_size_tiles)
+    if(!been_here++)
     {
-        /* The tile is possible. */
-        vprintf("%s(%u, %u, %u, %u)\n", __PRETTY_FUNCTION__,
-                tilex, tiley, destx, desty);
-        sprintf(buffer, "%s/%u/%u/%u.jpg",
-            _curr_repo->cache_dir, _zoom, tilex, tiley);
-        pixbuf = gdk_pixbuf_new_from_file(buffer, &error);
-
-        if(error)
-        {
-            pixbuf = NULL;
-            error = NULL;
-        }
-
-        if(!pixbuf && !fast_fail && _auto_download && *_curr_repo->url
-                && !(_zoom % _curr_repo->dl_zoom_steps))
+        /* Set connection state first, to avoid going into this if twice. */
+        if(_rcvr_mac || !_enable_gps || settings_dialog())
         {
-            map_initiate_download(tilex, tiley, _zoom,
-                    INITIAL_DOWNLOAD_RETRIES);
-            fast_fail = TRUE;
-        }
+            gtk_widget_show_all(_window);
+            gps_show_info();
 
-        for(zoff = 1; !pixbuf && (_zoom + zoff) <= MAX_ZOOM
-                && zoff <= TILE_SIZE_P2; zoff += 1)
-        {
-            /* Attempt to blit a wider map. */
-            sprintf(buffer, "%s/%u/%u/%u.jpg",
-                    _curr_repo->cache_dir, _zoom + zoff,
-                    (tilex >> zoff), (tiley >> zoff));
-            pixbuf = gdk_pixbuf_new_from_file(buffer, &error);
-            if(error)
-            {
-                pixbuf = NULL;
-                error = NULL;
-            }
-            if(pixbuf)
-            {
-                map_pixbuf_scale_inplace(gdk_pixbuf_get_pixels(pixbuf), zoff,
-                  (tilex - ((tilex >> zoff) << zoff)) << (TILE_SIZE_P2 - zoff),
-                  (tiley - ((tiley >> zoff) << zoff)) << (TILE_SIZE_P2 - zoff));
-            }
-            else
-            {
-                if(_auto_download && *_curr_repo->url
-                        && !((_zoom + zoff) % _curr_repo->dl_zoom_steps))
-                {
-                    if(!fast_fail)
-                        map_initiate_download(
-                                tilex >> zoff, tiley >> zoff, _zoom + zoff,
-                                INITIAL_DOWNLOAD_RETRIES);
-                    fast_fail = TRUE;
-                }
-            }
+            /* Connect to receiver. */
+            if(_enable_gps)
+                rcvr_connect_now();
         }
+        else
+            gtk_main_quit();
     }
-    if(!pixbuf)
-        pixbuf = gdk_pixbuf_new(
-                GDK_COLORSPACE_RGB,
-                FALSE, /* no alpha. */
-                8, /* 8 bits per sample. */
-                TILE_SIZE_PIXELS, TILE_SIZE_PIXELS);
-    if(pixbuf)
+    gtk_window_present(GTK_WINDOW(_window));
+
+    /* Re-enable any banners that might have been up. */
     {
-        gdk_draw_pixbuf(
-                _map_pixmap,
-                _gc_mark,
-                pixbuf,
-                0, 0,
-                destx, desty,
-                TILE_SIZE_PIXELS, TILE_SIZE_PIXELS,
-                GDK_RGB_DITHER_NONE, 0, 0);
-        g_object_unref(pixbuf);
+        ConnState old_state = _conn_state;
+        set_conn_state(RCVR_OFF);
+        set_conn_state(old_state);
     }
 
     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+    return FALSE;
 }
 
 /**
- * Force a redraw of the entire _map_pixmap, including fetching the
- * background maps from disk and redrawing the tracks on top of them.
+ * Get the hash value of a ProgressUpdateInfo object.  This is trivial, since
+ * the hash is generated and stored when the object is created.
  */
-void
-map_force_redraw()
+static guint
+download_hashfunc(ProgressUpdateInfo *pui)
 {
-    guint new_x, new_y;
-    printf("%s()\n", __PRETTY_FUNCTION__);
-
-    for(new_y = 0; new_y < BUF_HEIGHT_TILES; ++new_y)
-        for(new_x = 0; new_x < BUF_WIDTH_TILES; ++new_x)
-        {
-            map_render_tile(
-                    _base_tilex + new_x,
-                    _base_tiley + new_y,
-                    new_x * TILE_SIZE_PIXELS,
-                    new_y * TILE_SIZE_PIXELS,
-                    FALSE);
-        }
-    map_render_paths();
-    map_render_poi();
-    MACRO_QUEUE_DRAW_AREA();
+    vprintf("%s()\n", __PRETTY_FUNCTION__);
 
     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+    return pui->hash;
 }
 
 /**
- * Set the current zoom level.  If the given zoom level is the same as the
- * current zoom level, or if the new zoom is invalid
- * (not MIN_ZOOM <= new_zoom < MAX_ZOOM), then this method does nothing.
+ * Return whether or not two ProgressUpdateInfo objects are equal.  They
+ * are equal if they are downloading the same tile.
  */
-void
-map_set_zoom(guint new_zoom)
+static gboolean
+download_equalfunc(
+        ProgressUpdateInfo *pui1, ProgressUpdateInfo *pui2)
 {
-    printf("%s(%d)\n", __PRETTY_FUNCTION__, _zoom);
-
-    /* Note that, since new_zoom is a guint and MIN_ZOOM is 0, this if
-     * condition also checks for new_zoom >= MIN_ZOOM. */
-    if(new_zoom > (MAX_ZOOM - 1))
-        return;
-    _zoom = new_zoom / _curr_repo->view_zoom_steps
-                     * _curr_repo->view_zoom_steps;
-    _world_size_tiles = unit2tile(WORLD_SIZE_UNITS);
-
-    /* If we're leading, update the center to reflect new zoom level. */
-    MACRO_RECALC_CENTER(_center.unitx, _center.unity);
-
-    /* Update center bounds to reflect new zoom level. */
-    _min_center.unitx = pixel2unit(grid2pixel(_screen_grids_halfwidth));
-    _min_center.unity = pixel2unit(grid2pixel(_screen_grids_halfheight));
-    _max_center.unitx = WORLD_SIZE_UNITS-grid2unit(_screen_grids_halfwidth) - 1;
-    _max_center.unity = WORLD_SIZE_UNITS-grid2unit(_screen_grids_halfheight)- 1;
-
-    BOUND(_center.unitx, _min_center.unitx, _max_center.unitx);
-    BOUND(_center.unity, _min_center.unity, _max_center.unity);
-
-    _base_tilex = grid2tile((gint)pixel2grid(
-                (gint)unit2pixel((gint)_center.unitx))
-            - (gint)_screen_grids_halfwidth);
-    _base_tiley = grid2tile(pixel2grid(
-                unit2pixel(_center.unity))
-            - _screen_grids_halfheight);
-
-    /* New zoom level, so we can't reuse the old buffer's pixels. */
+    vprintf("%s()\n", __PRETTY_FUNCTION__);
 
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+    return pui1->tilex == pui2->tilex && pui1->tiley == pui2->tiley
+        && pui1->zoom == pui2->zoom;
+}
 
-    /* Update state variables. */
-    MACRO_RECALC_OFFSET();
-    MACRO_RECALC_FOCUS_BASE();
-    MACRO_RECALC_FOCUS_SIZE();
+/**
+ * Draw the current mark (representing the current GPS location) onto
+ * _map_widget.  This method does not queue the draw area.
+ */
+static void
+map_draw_mark()
+{
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    map_set_mark();
-    map_force_redraw();
+    if(_enable_gps)
+    {
+        gdk_draw_arc(
+                _map_widget->window,
+                _conn_state == RCVR_FIXED ? _gc_mark : _gc_mark_old,
+                FALSE, /* not filled. */
+                _mark_x1 - _draw_line_width, _mark_y1 - _draw_line_width,
+                2 * _draw_line_width, 2 * _draw_line_width,
+                0, 360 * 64);
+        gdk_draw_line(
+                _map_widget->window,
+                _conn_state == RCVR_FIXED
+                    ? (_show_velvec ? _gc_mark_velocity : _gc_mark)
+                    : _gc_mark_old,
+                _mark_x1, _mark_y1, _mark_x2, _mark_y2);
+    }
 
     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
 }
 
 /**
- * Center the view on the given unitx/unity.
+ * "Set" the mark, which translates the current GPS position into on-screen
+ * units in preparation for drawing the mark with map_draw_mark().
  */
-static void
-map_center_unit(guint new_center_unitx, guint new_center_unity)
+static void map_set_mark()
 {
-    gint new_base_tilex, new_base_tiley;
-    guint new_x, new_y;
-    guint j, k, base_new_x, base_old_x, old_x, old_y, iox, ioy;
-    printf("%s(%d, %d)\n", __PRETTY_FUNCTION__,
-            new_center_unitx, new_center_unity);
-
-    /* Assure that _center.unitx/y are bounded. */
-    BOUND(new_center_unitx, _min_center.unitx, _max_center.unitx);
-    BOUND(new_center_unity, _min_center.unity, _max_center.unity);
-
-    _center.unitx = new_center_unitx;
-    _center.unity = new_center_unity;
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    new_base_tilex = grid2tile((gint)pixel2grid(
-                (gint)unit2pixel((gint)_center.unitx))
-            - (gint)_screen_grids_halfwidth);
-    new_base_tiley = grid2tile(pixel2grid(
-                unit2pixel(_center.unity))
-            - _screen_grids_halfheight);
+    _mark_x1 = unit2x(_pos.unitx);
+    _mark_y1 = unit2y(_pos.unity);
+    _mark_x2 = _mark_x1 + (_show_velvec ? _vel_offsetx : 0);
+    _mark_y2 = _mark_y1 + (_show_velvec ? _vel_offsety : 0);
+    _mark_minx = MIN(_mark_x1, _mark_x2) - (2 * _draw_line_width);
+    _mark_miny = MIN(_mark_y1, _mark_y2) - (2 * _draw_line_width);
+    _mark_width = abs(_mark_x1 - _mark_x2) + (4 * _draw_line_width);
+    _mark_height = abs(_mark_y1 - _mark_y2) + (4 * _draw_line_width);
 
-    /* Same zoom level, so it's likely that we can reuse some of the old
-     * buffer's pixels. */
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
-    if(new_base_tilex != _base_tilex
-            || new_base_tiley != _base_tiley)
-    {
-        /* If copying from old parts to new parts, we need to make sure we
-         * don't overwrite the old parts when copying, so set up new_x,
-         * new_y, old_x, old_y, iox, and ioy with that in mind. */
-        if(new_base_tiley < _base_tiley)
-        {
-            /* New is lower than old - start at bottom and go up. */
-            new_y = BUF_HEIGHT_TILES - 1;
-            ioy = -1;
-        }
-        else
-        {
-            /* New is higher than old - start at top and go down. */
-            new_y = 0;
-            ioy = 1;
-        }
-        if(new_base_tilex < _base_tilex)
-        {
-            /* New is righter than old - start at right and go left. */
-            base_new_x = BUF_WIDTH_TILES - 1;
-            iox = -1;
-        }
-        else
-        {
-            /* New is lefter than old - start at left and go right. */
-            base_new_x = 0;
-            iox = 1;
-        }
+/**
+ * Do an in-place scaling of a pixbuf's pixels at the given ratio from the
+ * given source location.  It would have been nice if gdk_pixbuf provided
+ * this method, but I guess it's not general-purpose enough.
+ */
+static void
+map_pixbuf_scale_inplace(guchar *pixels, guint ratio_p2,
+        guint src_x, guint src_y)
+{
+    guint dest_x = 0, dest_y = 0, dest_dim = TILE_SIZE_PIXELS;
+    vprintf("%s(%d, %d, %d)\n", __PRETTY_FUNCTION__, ratio_p2, src_x, src_y);
 
-        /* Iterate over the y tile values. */
-        old_y = new_y + new_base_tiley - _base_tiley;
-        base_old_x = base_new_x + new_base_tilex - _base_tilex;
-        _base_tilex = new_base_tilex;
-        _base_tiley = new_base_tiley;
-        for(j = 0; j < BUF_HEIGHT_TILES; ++j, new_y += ioy, old_y += ioy)
+    /* Sweep through the entire dest area, copying as necessary, but
+     * DO NOT OVERWRITE THE SOURCE AREA.  We'll copy it afterward. */
+    do {
+        guint src_dim = dest_dim >> ratio_p2;
+        guint src_endx = src_x - dest_x + src_dim;
+        gint x, y;
+        for(y = dest_dim - 1; y >= 0; y--)
         {
-            new_x = base_new_x;
-            old_x = base_old_x;
-            /* Iterate over the x tile values. */
-            for(k = 0; k < BUF_WIDTH_TILES; ++k, new_x += iox, old_x += iox)
+            guint src_offset_y, dest_offset_y;
+            src_offset_y = (src_y + (y >> ratio_p2)) * TILE_PIXBUF_STRIDE;
+            dest_offset_y = (dest_y + y) * TILE_PIXBUF_STRIDE;
+            x = dest_dim - 1;
+            if((unsigned)(dest_y + y - src_y) < src_dim
+                    && (unsigned)(dest_x + x - src_x) < src_dim)
+                x -= src_dim;
+            for(; x >= 0; x--)
             {
-                /* Can we get this grid block from the old buffer?. */
-                if(old_x >= 0 && old_x < BUF_WIDTH_TILES
-                        && old_y >= 0 && old_y < BUF_HEIGHT_TILES)
-                {
-                    /* Copy from old buffer to new buffer. */
-                    gdk_draw_drawable(
-                            _map_pixmap,
-                            _gc_mark,
-                            _map_pixmap,
-                            old_x * TILE_SIZE_PIXELS,
-                            old_y * TILE_SIZE_PIXELS,
-                            new_x * TILE_SIZE_PIXELS,
-                            new_y * TILE_SIZE_PIXELS,
-                            TILE_SIZE_PIXELS, TILE_SIZE_PIXELS);
-                }
-                else
-                {
-                    map_render_tile(
-                            new_base_tilex + new_x,
-                            new_base_tiley + new_y,
-                            new_x * TILE_SIZE_PIXELS,
-                            new_y * TILE_SIZE_PIXELS,
-                            FALSE);
-                }
+                guint src_offset, dest_offset;
+                src_offset = src_offset_y + (src_x + (x >> ratio_p2)) * 3;
+                dest_offset = dest_offset_y + (dest_x + x) * 3;
+                pixels[dest_offset + 0] = pixels[src_offset + 0];
+                pixels[dest_offset + 1] = pixels[src_offset + 1];
+                pixels[dest_offset + 2] = pixels[src_offset + 2];
+                if((unsigned)(dest_y + y - src_y) < src_dim && x == src_endx)
+                    x -= src_dim;
             }
         }
-        map_render_paths();
-        map_render_poi();
+        /* Reuse src_dim and src_endx to store new src_x and src_y. */
+        src_dim = src_x + ((src_x - dest_x) >> ratio_p2);
+        src_endx = src_y + ((src_y - dest_y) >> ratio_p2);
+        dest_x = src_x;
+        dest_y = src_y;
+        src_x = src_dim;
+        src_y = src_endx;
     }
-
-    MACRO_RECALC_OFFSET();
-    MACRO_RECALC_FOCUS_BASE();
-
-    map_set_mark();
-    MACRO_QUEUE_DRAW_AREA();
+    while((dest_dim >>= ratio_p2) > 1);
 
     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
 }
 
 /**
- * Pan the view by the given number of units in the X and Y directions.
+ * Free a ProgressUpdateInfo data structure that was allocated during the
+ * auto-map-download process.
  */
-void
-map_pan(gint delta_unitx, gint delta_unity)
+static void
+progress_update_info_free(ProgressUpdateInfo *pui)
 {
-    printf("%s(%d, %d)\n", __PRETTY_FUNCTION__, delta_unitx, delta_unity);
+    vprintf("%s()\n", __PRETTY_FUNCTION__);
 
-    if(_center_mode > 0)
-        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(
-                    _menu_ac_none_item), TRUE);
-    map_center_unit(
-            _center.unitx + delta_unitx,
-            _center.unity + delta_unity);
+    gnome_vfs_uri_unref((GnomeVFSURI*)pui->src_list->data);
+    g_list_free(pui->src_list);
+    gnome_vfs_uri_unref((GnomeVFSURI*)pui->dest_list->data);
+    g_list_free(pui->dest_list);
+    g_free(pui);
 
     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
 }
 
 /**
- * Initiate a move of the mark from the old location to the current
- * location.  This function queues the draw area of the old mark (to force
- * drawing of the background map), then updates the mark, then queus the
- * draw area of the new mark.
+ * Given the xyz coordinates of our map coordinate system, write the qrst
+ * quadtree coordinates to buffer.
  */
 static void
-map_move_mark()
+map_convert_coords_to_quadtree_string(int x, int y, int zoomlevel,gchar *buffer)
 {
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    static const gchar *const quadrant = "qrts";
+    gchar *ptr = buffer;
+    int n;
+    *ptr++ = 't';
+    for(n = 16 - zoomlevel; n >= 0; n--)
+    {
+        int xbit = (x >> n) & 1;
+        int ybit = (y >> n) & 1;
+        *ptr++ = quadrant[xbit + 2 * ybit];
+    }
+    *ptr++ = '\0';
+}
 
-    /* Just queue the old and new draw areas. */
-    gtk_widget_queue_draw_area(_map_widget,
-            _mark_minx,
-            _mark_miny,
-            _mark_width,
-            _mark_height);
-    map_set_mark();
-    gtk_widget_queue_draw_area(_map_widget,
-            _mark_minx,
-            _mark_miny,
-            _mark_width,
-            _mark_height);
+/**
+ * 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 void
+map_construct_url(gchar *buffer, guint tilex, guint tiley, guint zoom)
+{
+    if(strstr(_curr_repo->url, "%s"))
+    {
+        /* This is a satellite-map URI. */
+        gchar location[MAX_ZOOM + 2];
+        map_convert_coords_to_quadtree_string(tilex, tiley, zoom, location);
+        sprintf(buffer, _curr_repo->url, location);
+    }
+    else
+        /* This is a street-map URI. */
+        sprintf(buffer, _curr_repo->url, tilex, tiley, zoom);
+}
+
+
+/**
+ * Initiate a download of the given xyz coordinates using the given buffer
+ * as the URL.  If the map already exists on disk, or if we are already
+ * downloading the map, then this method does nothing.
+ */
+static gboolean
+map_initiate_download(guint tilex, guint tiley, guint zoom, gint retries)
+{
+    gchar buffer[1024];
+    GnomeVFSURI *src, *dest;
+    GList *src_list, *dest_list;
+    gint priority;
+    ProgressUpdateInfo *pui;
+    vprintf("%s(%u, %u, %u, %d)\n", __PRETTY_FUNCTION__, tilex, tiley, zoom,
+            retries);
+
+    pui = g_new(ProgressUpdateInfo, 1);
+    pui->hash = tilex + (tiley << 12) + (zoom << 24);
+    pui->tilex = tilex;
+    pui->tiley = tiley;
+    pui->zoom = zoom;
+    if(g_hash_table_lookup(_downloads_hash, pui))
+    {
+        /* Already downloading - return FALSE. */
+        g_free(pui);
+        return FALSE;
+    }
+    sprintf(buffer, "%s/%u/%u/%u.jpg", _curr_repo->cache_dir,
+            zoom, tilex, tiley);
+    dest = gnome_vfs_uri_new(buffer);
+    if(retries > 0 && gnome_vfs_uri_exists(dest))
+    {
+        /* Already downloaded and not overwriting - return FALSE. */
+        gnome_vfs_uri_unref(dest);
+        g_free(pui);
+        return FALSE;
+    }
 
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-}
+    /* Priority is based on proximity to _center.unitx - lower number means
+     * higher priority, so the further we are, the higher the number. */
+    priority = GNOME_VFS_PRIORITY_MIN
+        + unit2ptile(abs(tile2punit(tilex, zoom) - _center.unitx)
+                + abs(tile2punit(tiley, zoom) - _center.unity));
+    BOUND(priority, GNOME_VFS_PRIORITY_MIN, GNOME_VFS_PRIORITY_MAX);
 
-/**
- * Make sure the mark is up-to-date.  This function triggers a panning of
- * the view if the mark is appropriately close to the edge of the view.
- */
-static void
-refresh_mark()
-{
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    map_construct_url(buffer, tilex, tiley, zoom);
+    src = gnome_vfs_uri_new(buffer);
 
-    guint new_center_unitx;
-    guint new_center_unity;
+    src_list = g_list_prepend(src_list = NULL, src);
+    dest_list = g_list_prepend(dest_list = NULL, dest);
 
-    MACRO_RECALC_CENTER(new_center_unitx, new_center_unity);
+    pui->src_list = src_list;
+    pui->dest_list = dest_list;
+    pui->retries_left = retries;
 
-    if((new_center_unitx - _focus.unitx) < _focus_unitwidth
-            && (new_center_unity - _focus.unity) < _focus_unitheight)
-        /* We're not changing the view - just move the mark. */
-        map_move_mark();
+    /* Initiate asynchronous download. */
+    if(retries)
+    {
+        /* This is a download; if retries < 0, then this is an overwrite */
+        if(GNOME_VFS_OK != gnome_vfs_async_xfer(
+                    &pui->handle,
+                    src_list, dest_list,
+                    retries < 0 ? GNOME_VFS_XFER_DEFAULT
+                                : GNOME_VFS_XFER_USE_UNIQUE_NAMES,
+                    GNOME_VFS_XFER_ERROR_MODE_QUERY,
+                    retries < 0 ? GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE
+                                : GNOME_VFS_XFER_OVERWRITE_MODE_QUERY,
+                    priority,
+                    (GnomeVFSAsyncXferProgressCallback)map_download_cb_async,
+                    pui,
+                    (GnomeVFSXferProgressCallback)gtk_true,
+                    NULL))
+        {
+            progress_update_info_free(pui);
+            return FALSE;
+        }
+    }
     else
-        map_center_unit(new_center_unitx, new_center_unity);
+    {
+        /* This is a deletion. */
+        if(GNOME_VFS_OK != gnome_vfs_async_xfer(
+                    &pui->handle,
+                    dest_list, NULL,
+                    GNOME_VFS_XFER_DELETE_ITEMS,
+                    GNOME_VFS_XFER_ERROR_MODE_QUERY,
+                    GNOME_VFS_XFER_OVERWRITE_MODE_QUERY,
+                    priority,
+                    (GnomeVFSAsyncXferProgressCallback)map_download_cb_async,
+                    pui,
+                    (GnomeVFSXferProgressCallback)gtk_true,
+                    NULL))
+        {
+            progress_update_info_free(pui);
+            return FALSE;
+        }
+    }
+
+    g_hash_table_insert(_downloads_hash, pui, pui);
+    if(!_num_downloads++ && !_download_banner)
+        _download_banner = hildon_banner_show_progress(
+                _window, NULL, _("Downloading maps"));
 
     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+    return TRUE;
 }
 
-/**
- * Handle a start tag in the parsing of a GPX file.
- */
-#define MACRO_SET_UNKNOWN() { \
-    data->prev_state = data->state; \
-    data->state = UNKNOWN; \
-    data->unknown_depth = 1; \
-}
 static void
-gpx_start_element(SaxData *data, const xmlChar *name, const xmlChar **attrs)
+map_render_poi()
 {
-    vprintf("%s(%s)\n", __PRETTY_FUNCTION__, name);
+    guint unitx, unity;
+    gfloat lat1, lat2, lon1, lon2, tmp;
+    gchar slat1[10], slat2[10], slon1[10], slon2[10];
+    gchar buffer[100];
+    gchar **pszResult;
+    gint nRow, nColumn, row, poix, poiy;
+    GdkPixbuf *pixbuf = NULL;
+    GError *error = NULL;
 
-    switch(data->state)
+    if(_db && _poi_zoom > _zoom)
     {
-        case ERROR:
-            break;
-        case START:
-            if(!strcmp((gchar*)name, "gpx"))
-                data->state = INSIDE_GPX;
-            else
-                MACRO_SET_UNKNOWN();
-            break;
-        case INSIDE_GPX:
-            if(!strcmp((gchar*)name, "trk"))
-                data->state = INSIDE_PATH;
-            else
-                MACRO_SET_UNKNOWN();
-            break;
-        case INSIDE_PATH:
-            if(!strcmp((gchar*)name, "trkseg"))
-            {
-                data->state = INSIDE_PATH_SEGMENT;
-                data->at_least_one_trkpt = FALSE;
-            }
-            else
-                MACRO_SET_UNKNOWN();
-            break;
-        case INSIDE_PATH_SEGMENT:
-            if(!strcmp((gchar*)name, "trkpt"))
+        unitx = x2unit(1);
+        unity = y2unit(1);
+        unit2latlon(unitx, unity, lat1, lon1);
+        unitx = x2unit(BUF_WIDTH_PIXELS);
+        unity = y2unit(BUF_HEIGHT_PIXELS);
+        unit2latlon(unitx, unity, lat2, lon2);
+        if(lat1 > lat2)
+        {
+            tmp = lat2;
+            lat2 = lat1;
+            lat1 = tmp;
+        }
+        if(lon1 > lon2)
+        {
+            tmp = lon2;
+            lon2 = lon1;
+            lon1 = tmp;
+        }
+
+        g_ascii_dtostr(slat1, sizeof(slat1), lat1);
+        g_ascii_dtostr(slat2, sizeof(slat2), lat2);
+        g_ascii_dtostr(slon1, sizeof(slon1), lon1);
+        g_ascii_dtostr(slon2, sizeof(slon2), lon2);
+
+        if(SQLITE_OK == sqlite_get_table_printf(_db,
+                    "select p.lat, p.lon, lower(p.label), lower(c.label)"
+                    " from poi p, category c "
+                    " where p.lat between %s and %s "
+                    " and p.lon  between %s and %s "
+                    " and c.enabled = 1 and p.cat_id = c.cat_id",
+                    &pszResult, &nRow, &nColumn, NULL,
+                    slat1, slat2, slon1, slon2))
+        {
+            for(row=1; row<nRow+1; row++)
             {
-                const xmlChar **curr_attr;
-                gchar *error_check;
-                gfloat lat = 0.f, lon = 0.f;
-                gboolean has_lat, has_lon;
-                has_lat = FALSE;
-                has_lon = FALSE;
-                for(curr_attr = attrs; *curr_attr != NULL; )
+                lat1 = g_ascii_strtod(pszResult[row*nColumn+0], NULL);
+                lon1 = g_ascii_strtod(pszResult[row*nColumn+1], NULL);
+                latlon2unit(lat1, lon1, unitx, unity);
+                poix = unit2bufx(unitx);
+                poiy = unit2bufy(unity);
+
+                /* Try to get icon for specific POI first. */
+                sprintf(buffer, "%s/poi/%s.jpg", _curr_repo->cache_dir,
+                    pszResult[row*nColumn+2]);
+                pixbuf = gdk_pixbuf_new_from_file(buffer, &error);
+                if(error)
                 {
-                    const gchar *attr_name = *curr_attr++;
-                    const gchar *attr_val = *curr_attr++;
-                    if(!strcmp(attr_name, "lat"))
-                    {
-                        lat = g_ascii_strtod(attr_val, &error_check);
-                        if(error_check != attr_val)
-                            has_lat = TRUE;
-                    }
-                    else if(!strcmp(attr_name, "lon"))
-                    {
-                        lon = g_ascii_strtod(attr_val, &error_check);
-                        if(error_check != attr_val)
-                            has_lon = TRUE;
-                    }
+                    /* No icon for specific POI - try for category. */
+                    error = NULL;
+                    sprintf(buffer, "%s/poi/%s.jpg", _curr_repo->cache_dir,
+                        pszResult[row*nColumn+3]);
+                    pixbuf = gdk_pixbuf_new_from_file(buffer, &error);
                 }
-                if(has_lat && has_lon)
+                if(error)
                 {
-                    if(data->path.path_type == TRACK)
-                    {
-                        MACRO_TRACK_INCREMENT_TAIL(data->path.path.track);
-                        latlon2unit(lat, lon,
-                                data->path.path.track.tail->point.unitx,
-                                data->path.path.track.tail->point.unity);
-                        data->path.path.track.tail->time = 0;
-                    }
-                    else
-                    {
-                        MACRO_ROUTE_INCREMENT_TAIL(data->path.path.route);
-                        latlon2unit(lat, lon,
-                                data->path.path.route.tail->unitx,
-                                data->path.path.route.tail->unity);
-                    }
-                    data->state = INSIDE_PATH_POINT;
-                }
-                else
-                    data->state = ERROR;
-            }
-            else
-                MACRO_SET_UNKNOWN();
-            break;
-        case INSIDE_PATH_POINT:
-            /* only parse time for tracks */
-            if(data->path.path_type == TRACK
-                    && !strcmp((gchar*)name, "time"))
-                data->state = INSIDE_PATH_POINT_TIME;
-
-            /* only parse description for routes */
-            else if(data->path.path_type == ROUTE
-                    && !strcmp((gchar*)name, "desc"))
-                data->state = INSIDE_PATH_POINT_DESC;
-
-            else
-                MACRO_SET_UNKNOWN();
-            break;
-        case UNKNOWN:
-            data->unknown_depth++;
-            break;
-        default:
-            ;
+                    /* No icon for POI or for category - draw default. */
+                    error = NULL;
+                    gdk_draw_rectangle(_map_pixmap, _gc_poi, TRUE,
+                        poix - (int)(0.5f * _draw_line_width),
+                        poiy - (int)(0.5f * _draw_line_width),
+                        3 * _draw_line_width,
+                        3 * _draw_line_width);
+                }
+                else
+                {
+                    gdk_draw_pixbuf(
+                            _map_pixmap,
+                            _gc_poi,
+                            pixbuf,
+                            0, 0,
+                            poix - gdk_pixbuf_get_width(pixbuf) / 2,
+                            poiy - gdk_pixbuf_get_height(pixbuf) / 2,
+                            -1,-1,
+                            GDK_RGB_DITHER_NONE, 0, 0);
+                    g_object_unref(pixbuf);
+                }
+             }
+            sqlite_free_table(pszResult);
+        }
     }
 
     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
 }
 
-/**
- * Handle an end tag in the parsing of a GPX file.
- */
 static void
-gpx_end_element(SaxData *data, const xmlChar *name)
-{
-    vprintf("%s(%s)\n", __PRETTY_FUNCTION__, name);
+map_render_tile(guint tilex, guint tiley, guint destx, guint desty,
+        gboolean fast_fail) {
+    gchar buffer[1024];
+    GdkPixbuf *pixbuf = NULL;
+    GError *error = NULL;
+    guint zoff;
 
-    switch(data->state)
+    if(tilex < _world_size_tiles && tiley < _world_size_tiles)
     {
-        case ERROR:
-            break;
-        case START:
-            data->state = ERROR;
-            break;
-        case INSIDE_GPX:
-            if(!strcmp((gchar*)name, "gpx"))
-                data->state = FINISH;
-            else
-                data->state = ERROR;
-            break;
-        case INSIDE_PATH:
-            if(!strcmp((gchar*)name, "trk"))
-                data->state = INSIDE_GPX;
-            else
-                data->state = ERROR;
-            break;
-        case INSIDE_PATH_SEGMENT:
-            if(!strcmp((gchar*)name, "trkseg"))
+        /* The tile is possible. */
+        vprintf("%s(%u, %u, %u, %u)\n", __PRETTY_FUNCTION__,
+                tilex, tiley, destx, desty);
+        sprintf(buffer, "%s/%u/%u/%u.jpg",
+            _curr_repo->cache_dir, _zoom, tilex, tiley);
+        pixbuf = gdk_pixbuf_new_from_file(buffer, &error);
+
+        if(error)
+        {
+            pixbuf = NULL;
+            error = NULL;
+        }
+
+        if(!pixbuf && !fast_fail && _auto_download && *_curr_repo->url
+                && !(_zoom % _curr_repo->dl_zoom_steps))
+        {
+            map_initiate_download(tilex, tiley, _zoom,
+                    INITIAL_DOWNLOAD_RETRIES);
+            fast_fail = TRUE;
+        }
+
+        for(zoff = 1; !pixbuf && (_zoom + zoff) <= MAX_ZOOM
+                && zoff <= TILE_SIZE_P2; zoff += 1)
+        {
+            /* Attempt to blit a wider map. */
+            sprintf(buffer, "%s/%u/%u/%u.jpg",
+                    _curr_repo->cache_dir, _zoom + zoff,
+                    (tilex >> zoff), (tiley >> zoff));
+            pixbuf = gdk_pixbuf_new_from_file(buffer, &error);
+            if(error)
             {
-                if(data->at_least_one_trkpt)
-                {
-                    if(data->path.path_type == TRACK)
-                    {
-                        MACRO_TRACK_INCREMENT_TAIL(data->path.path.track);
-                        *data->path.path.track.tail = _track_null;
-                    }
-                    else
-                    {
-                        MACRO_ROUTE_INCREMENT_TAIL(data->path.path.route);
-                        *data->path.path.route.tail = _pos_null;
-                    }
-                }
-                data->state = INSIDE_PATH;
+                pixbuf = NULL;
+                error = NULL;
             }
-            else
-                data->state = ERROR;
-            break;
-        case INSIDE_PATH_POINT:
-            if(!strcmp((gchar*)name, "trkpt"))
+            if(pixbuf)
             {
-                data->state = INSIDE_PATH_SEGMENT;
-                data->at_least_one_trkpt = TRUE;
+                map_pixbuf_scale_inplace(gdk_pixbuf_get_pixels(pixbuf), zoff,
+                  (tilex - ((tilex >> zoff) << zoff)) << (TILE_SIZE_P2 - zoff),
+                  (tiley - ((tiley >> zoff) << zoff)) << (TILE_SIZE_P2 - zoff));
             }
             else
-                data->state = ERROR;
-            break;
-        case INSIDE_PATH_POINT_TIME:
-            /* only parse time for tracks */
-            if(!strcmp((gchar*)name, "time"))
             {
-                struct tm time;
-                gchar *ptr;
-
-                if(NULL == (ptr = strptime(data->chars->str,
-                            XML_DATE_FORMAT, &time)))
-                    /* Failed to parse dateTime format. */
-                    data->state = ERROR;
-                else
+                if(_auto_download && *_curr_repo->url
+                        && !((_zoom + zoff) % _curr_repo->dl_zoom_steps))
                 {
-                    /* Parse was successful. Now we have to parse timezone.
-                     * From here on, if there is an error, I just assume local
-                     * timezone.  Yes, this is not proper XML, but I don't
-                     * care. */
-                    gchar *error_check;
-
-                    /* First, set time in "local" time zone. */
-                    data->path.path.track.tail->time = (mktime(&time));
-
-                    /* Now, skip inconsequential characters */
-                    while(*ptr && *ptr != 'Z' && *ptr != '-' && *ptr != '+')
-                        ptr++;
-
-                    /* Check if we ran to the end of the string. */
-                    if(*ptr)
-                    {
-                        /* Next character is either 'Z', '-', or '+' */
-                        if(*ptr == 'Z')
-                            /* Zulu (UTC) time. Undo the local time zone's
-                             * offset. */
-                            data->path.path.track.tail->time += time.tm_gmtoff;
-                        else
-                        {
-                            /* Not Zulu (UTC). Must parse hours and minutes. */
-                            gint offhours = strtol(ptr, &error_check, 10);
-                            if(error_check != ptr
-                                    && *(ptr = error_check) == ':')
-                            {
-                                /* Parse of hours worked. Check minutes. */
-                                gint offmins = strtol(ptr + 1,
-                                        &error_check, 10);
-                                if(error_check != (ptr + 1))
-                                {
-                                    /* Parse of minutes worked. Calculate. */
-                                    data->path.path.track.tail->time
-                                        += (time.tm_gmtoff
-                                                - (offhours * 60 * 60
-                                                    + offmins * 60));
-                                }
-                            }
-                        }
-                    }
-                    /* Successfully parsed dateTime. */
-                    data->state = INSIDE_PATH_POINT;
+                    if(!fast_fail)
+                        map_initiate_download(
+                                tilex >> zoff, tiley >> zoff, _zoom + zoff,
+                                INITIAL_DOWNLOAD_RETRIES);
+                    fast_fail = TRUE;
                 }
-
-                g_string_free(data->chars, TRUE);
-                data->chars = g_string_new("");
-            }
-            else
-                data->state = ERROR;
-            break;
-        case INSIDE_PATH_POINT_DESC:
-            /* only parse description for routes */
-            if(!strcmp((gchar*)name, "desc"))
-            {
-                MACRO_ROUTE_INCREMENT_WTAIL(data->path.path.route);
-                data->path.path.route.wtail->point = data->path.path.route.tail;
-                data->path.path.route.wtail->desc
-                    = g_string_free(data->chars, FALSE);
-                data->chars = g_string_new("");
-                data->state = INSIDE_PATH_POINT;
             }
-            else
-                data->state = ERROR;
-            break;
-        case UNKNOWN:
-            if(!--data->unknown_depth)
-                data->state = data->prev_state;
-            else
-                data->state = ERROR;
-            break;
-        default:
-            ;
+        }
+    }
+    if(pixbuf)
+    {
+        gdk_draw_pixbuf(
+                _map_pixmap,
+                _gc_mark,
+                pixbuf,
+                0, 0,
+                destx, desty,
+                TILE_SIZE_PIXELS, TILE_SIZE_PIXELS,
+                GDK_RGB_DITHER_NONE, 0, 0);
+        g_object_unref(pixbuf);
+    }
+    else
+    {
+        gdk_draw_rectangle(_map_pixmap, _map_widget->style->black_gc, TRUE,
+                destx, desty,
+                TILE_SIZE_PIXELS, TILE_SIZE_PIXELS);
     }
 
     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
 }
 
 /**
- * Handle char data in the parsing of a GPX file.
+ * Force a redraw of the entire _map_pixmap, including fetching the
+ * background maps from disk and redrawing the tracks on top of them.
  */
-static void
-gpx_chars(SaxData *data, const xmlChar *ch, int len)
+void
+map_force_redraw()
 {
-    guint i;
-    vprintf("%s()\n", __PRETTY_FUNCTION__);
+    guint new_x, new_y;
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    switch(data->state)
-    {
-        case ERROR:
-        case UNKNOWN:
-            break;
-        case INSIDE_PATH_POINT_TIME:
-        case INSIDE_PATH_POINT_DESC:
-            for(i = 0; i < len; i++)
-                data->chars = g_string_append_c(data->chars, ch[i]);
-            vprintf("%s\n", data->chars->str);
-            break;
-        default:
-            break;
-    }
+    for(new_y = 0; new_y < BUF_HEIGHT_TILES; ++new_y)
+        for(new_x = 0; new_x < BUF_WIDTH_TILES; ++new_x)
+        {
+            map_render_tile(
+                    _base_tilex + new_x,
+                    _base_tiley + new_y,
+                    new_x * TILE_SIZE_PIXELS,
+                    new_y * TILE_SIZE_PIXELS,
+                    FALSE);
+        }
+    map_render_paths();
+    map_render_poi();
+    MACRO_QUEUE_DRAW_AREA();
 
     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
 }
 
 /**
- * Handle an entity in the parsing of a GPX file.  We don't do anything
- * special here.
+ * Set the current zoom level.  If the given zoom level is the same as the
+ * current zoom level, or if the new zoom is invalid
+ * (not MIN_ZOOM <= new_zoom < MAX_ZOOM), then this method does nothing.
  */
-static xmlEntityPtr
-gpx_get_entity(SaxData *data, const xmlChar *name)
+void
+map_set_zoom(guint new_zoom)
 {
-    vprintf("%s()\n", __PRETTY_FUNCTION__);
-    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-    return xmlGetPredefinedEntity(name);
-}
+    printf("%s(%d)\n", __PRETTY_FUNCTION__, _zoom);
+
+    /* Note that, since new_zoom is a guint and MIN_ZOOM is 0, this if
+     * condition also checks for new_zoom >= MIN_ZOOM. */
+    if(new_zoom > (MAX_ZOOM - 1))
+        return;
+    _zoom = new_zoom / _curr_repo->view_zoom_steps
+                     * _curr_repo->view_zoom_steps;
+    _world_size_tiles = unit2tile(WORLD_SIZE_UNITS);
+
+    /* If we're leading, update the center to reflect new zoom level. */
+    MACRO_RECALC_CENTER(_center.unitx, _center.unity);
+
+    /* Update center bounds to reflect new zoom level. */
+    _min_center.unitx = pixel2unit(grid2pixel(_screen_grids_halfwidth));
+    _min_center.unity = pixel2unit(grid2pixel(_screen_grids_halfheight));
+    _max_center.unitx = WORLD_SIZE_UNITS-grid2unit(_screen_grids_halfwidth) - 1;
+    _max_center.unity = WORLD_SIZE_UNITS-grid2unit(_screen_grids_halfheight)- 1;
+
+    BOUND(_center.unitx, _min_center.unitx, _max_center.unitx);
+    BOUND(_center.unity, _min_center.unity, _max_center.unity);
+
+    _base_tilex = grid2tile((gint)pixel2grid(
+                (gint)unit2pixel((gint)_center.unitx))
+            - (gint)_screen_grids_halfwidth);
+    _base_tiley = grid2tile(pixel2grid(
+                unit2pixel(_center.unity))
+            - _screen_grids_halfheight);
+
+    /* New zoom level, so we can't reuse the old buffer's pixels. */
+
+
+    /* Update state variables. */
+    MACRO_RECALC_OFFSET();
+    MACRO_RECALC_FOCUS_BASE();
+    MACRO_RECALC_FOCUS_SIZE();
+
+    map_set_mark();
+    map_force_redraw();
 
-/**
- * Handle an error in the parsing of a GPX file.
- */
-static void
-gpx_error(SaxData *data, const gchar *msg, ...)
-{
-    vprintf("%s()\n", __PRETTY_FUNCTION__);
     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
-    data->state = ERROR;
 }
 
 /**
- * Parse the given character buffer of the given size, replacing the given
- * Track's pointers with pointers to new arrays depending on the given
- * policy, adding extra_bins slots in the arrays for new data.
- *
- * policy_old should be negative to indicate that the existing data should
- * be prepended to the new GPX data, positive to indicate the opposite, and
- * zero to indicate that we should throw away the old data.
- *
- * When importing tracks, we *prepend* the GPX data and provide extra_bins.
- * When importing routes, we *append* in the case of regular routes, and we
- * *replace* in the case of automatic routing.  Routes get no extra bins.
+ * Center the view on the given unitx/unity.
  */
-static gboolean
-parse_track_gpx(gchar *buffer, gint size, gint policy_old)
+static void
+map_center_unit(guint new_center_unitx, guint new_center_unity)
 {
-    SaxData data;
-    xmlSAXHandler sax_handler;
-    printf("%s()\n", __PRETTY_FUNCTION__);
+    gint new_base_tilex, new_base_tiley;
+    guint new_x, new_y;
+    guint j, k, base_new_x, base_old_x, old_x, old_y, iox, ioy;
+    printf("%s(%d, %d)\n", __PRETTY_FUNCTION__,
+            new_center_unitx, new_center_unity);
 
-    data.path.path_type = TRACK;
-    MACRO_INIT_TRACK(data.path.path.track);
-    data.state = START;
-    data.chars = g_string_new("");
+    /* Assure that _center.unitx/y are bounded. */
+    BOUND(new_center_unitx, _min_center.unitx, _max_center.unitx);
+    BOUND(new_center_unity, _min_center.unity, _max_center.unity);
 
-    memset(&sax_handler, 0, sizeof(sax_handler));
-    sax_handler.characters = (charactersSAXFunc)gpx_chars;
-    sax_handler.startElement = (startElementSAXFunc)gpx_start_element;
-    sax_handler.endElement = (endElementSAXFunc)gpx_end_element;
-    sax_handler.entityDecl = (entityDeclSAXFunc)gpx_get_entity;
-    sax_handler.warning = (warningSAXFunc)gpx_error;
-    sax_handler.error = (errorSAXFunc)gpx_error;
-    sax_handler.fatalError = (fatalErrorSAXFunc)gpx_error;
+    _center.unitx = new_center_unitx;
+    _center.unity = new_center_unity;
 
-    xmlSAXUserParseMemory(&sax_handler, &data, buffer, size);
-    g_string_free(data.chars, TRUE);
+    new_base_tilex = grid2tile((gint)pixel2grid(
+                (gint)unit2pixel((gint)_center.unitx))
+            - (gint)_screen_grids_halfwidth);
+    new_base_tiley = grid2tile(pixel2grid(
+                unit2pixel(_center.unity))
+            - _screen_grids_halfheight);
 
-    if(data.state != FINISH)
-    {
-        vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
-        return FALSE;
-    }
+    /* Same zoom level, so it's likely that we can reuse some of the old
+     * buffer's pixels. */
 
-    /* Successful parsing - replace given Track structure. */
-    if(policy_old && _track.head)
+    if(new_base_tilex != _base_tilex
+            || new_base_tiley != _base_tiley)
     {
-        TrackPoint *src_first;
-        Track *src, *dest;
-
-        if(policy_old > 0)
+        /* If copying from old parts to new parts, we need to make sure we
+         * don't overwrite the old parts when copying, so set up new_x,
+         * new_y, old_x, old_y, iox, and ioy with that in mind. */
+        if(new_base_tiley < _base_tiley)
         {
-            /* Append to current track. */
-            src = &data.path.path.track;
-            dest = &_track;
+            /* New is lower than old - start at bottom and go up. */
+            new_y = BUF_HEIGHT_TILES - 1;
+            ioy = -1;
         }
         else
         {
-            /* Prepend to current track. */
-            src = &_track;
-            dest = &data.path.path.track;
+            /* New is higher than old - start at top and go down. */
+            new_y = 0;
+            ioy = 1;
         }
-
-        /* Find src_first non-zero point. */
-        for(src_first = src->head - 1; src_first++ != src->tail; )
-            if(src_first->point.unity)
-                break;
-
-        /* Append track points from src to dest. */
-        if(src->tail >= src_first)
+        if(new_base_tilex < _base_tilex)
         {
-            guint num_dest_points = dest->tail - dest->head + 1;
-            guint num_src_points = src->tail - src_first + 1;
-
-            /* Adjust dest->tail to be able to fit src track data
-             * plus room for more track data. */
-            track_resize(dest,
-                    num_dest_points + num_src_points + ARRAY_CHUNK_SIZE);
-
-            memcpy(dest->tail + 1, src_first,
-                    num_src_points * sizeof(TrackPoint));
-
-            dest->tail += num_src_points;
+            /* New is righter than old - start at right and go left. */
+            base_new_x = BUF_WIDTH_TILES - 1;
+            iox = -1;
+        }
+        else
+        {
+            /* New is lefter than old - start at left and go right. */
+            base_new_x = 0;
+            iox = 1;
         }
 
-        MACRO_CLEAR_TRACK(*src);
-        if(policy_old < 0)
-            _track = *dest;
-    }
-    else
-    {
-        MACRO_CLEAR_TRACK(_track);
-        /* Overwrite with data.track. */
-        _track = data.path.path.track;
-        track_resize(&_track,
-                _track.tail - _track.head + 1 + ARRAY_CHUNK_SIZE);
+        /* Iterate over the y tile values. */
+        old_y = new_y + new_base_tiley - _base_tiley;
+        base_old_x = base_new_x + new_base_tilex - _base_tilex;
+        _base_tilex = new_base_tilex;
+        _base_tiley = new_base_tiley;
+        for(j = 0; j < BUF_HEIGHT_TILES; ++j, new_y += ioy, old_y += ioy)
+        {
+            new_x = base_new_x;
+            old_x = base_old_x;
+            /* Iterate over the x tile values. */
+            for(k = 0; k < BUF_WIDTH_TILES; ++k, new_x += iox, old_x += iox)
+            {
+                /* Can we get this grid block from the old buffer?. */
+                if(old_x >= 0 && old_x < BUF_WIDTH_TILES
+                        && old_y >= 0 && old_y < BUF_HEIGHT_TILES)
+                {
+                    /* Copy from old buffer to new buffer. */
+                    gdk_draw_drawable(
+                            _map_pixmap,
+                            _gc_mark,
+                            _map_pixmap,
+                            old_x * TILE_SIZE_PIXELS,
+                            old_y * TILE_SIZE_PIXELS,
+                            new_x * TILE_SIZE_PIXELS,
+                            new_y * TILE_SIZE_PIXELS,
+                            TILE_SIZE_PIXELS, TILE_SIZE_PIXELS);
+                }
+                else
+                {
+                    map_render_tile(
+                            new_base_tilex + new_x,
+                            new_base_tiley + new_y,
+                            new_x * TILE_SIZE_PIXELS,
+                            new_y * TILE_SIZE_PIXELS,
+                            FALSE);
+                }
+            }
+        }
+        map_render_paths();
+        map_render_poi();
     }
 
-    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
-    return TRUE;
-}
-
-static gboolean
-parse_route_gpx(gchar *buffer, gint size, gint policy_old)
-{
-    SaxData data;
-    xmlSAXHandler sax_handler;
-    printf("%s()\n", __PRETTY_FUNCTION__);
-
-    data.path.path_type = ROUTE;
-    MACRO_INIT_ROUTE(data.path.path.route);
-    data.state = START;
-    data.chars = g_string_new("");
-
-    memset(&sax_handler, 0, sizeof(sax_handler));
-    sax_handler.characters = (charactersSAXFunc)gpx_chars;
-    sax_handler.startElement = (startElementSAXFunc)gpx_start_element;
-    sax_handler.endElement = (endElementSAXFunc)gpx_end_element;
-    sax_handler.entityDecl = (entityDeclSAXFunc)gpx_get_entity;
-    sax_handler.warning = (warningSAXFunc)gpx_error;
-    sax_handler.error = (errorSAXFunc)gpx_error;
-    sax_handler.fatalError = (fatalErrorSAXFunc)gpx_error;
-
-    xmlSAXUserParseMemory(&sax_handler, &data, buffer, size);
-    g_string_free(data.chars, TRUE);
+    MACRO_RECALC_OFFSET();
+    MACRO_RECALC_FOCUS_BASE();
 
-    if(data.state != FINISH)
-    {
-        vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
-        return FALSE;
-    }
+    map_set_mark();
+    MACRO_QUEUE_DRAW_AREA();
 
-    if(policy_old && _route.head)
-    {
-        Point *src_first;
-        Route *src, *dest;
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
-        if(policy_old > 0)
-        {
-            /* Append to current route. */
-            src = &data.path.path.route;
-            dest = &_route;
-        }
-        else
-        {
-            /* Prepend to current route. */
-            src = &_route;
-            dest = &data.path.path.route;
-        }
+/**
+ * Pan the view by the given number of units in the X and Y directions.
+ */
+void
+map_pan(gint delta_unitx, gint delta_unity)
+{
+    printf("%s(%d, %d)\n", __PRETTY_FUNCTION__, delta_unitx, delta_unity);
 
-        /* Find src_first non-zero point. */
-        for(src_first = src->head - 1; src_first++ != src->tail; )
-            if(src_first->unity)
-                break;
+    if(_center_mode > 0)
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(
+                    _menu_ac_none_item), TRUE);
+    map_center_unit(
+            _center.unitx + delta_unitx,
+            _center.unity + delta_unity);
 
-        /* Append route points from src to dest. */
-        if(src->tail >= src_first)
-        {
-            WayPoint *curr;
-            guint num_dest_points = dest->tail - dest->head + 1;
-            guint num_src_points = src->tail - src_first + 1;
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
-            /* Adjust dest->tail to be able to fit src route data
-             * plus room for more route data. */
-            route_resize(dest, num_dest_points + num_src_points);
+/**
+ * Initiate a move of the mark from the old location to the current
+ * location.  This function queues the draw area of the old mark (to force
+ * drawing of the background map), then updates the mark, then queus the
+ * draw area of the new mark.
+ */
+static void
+map_move_mark()
+{
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-            memcpy(dest->tail + 1, src_first,
-                    num_src_points * sizeof(Point));
+    /* Just queue the old and new draw areas. */
+    gtk_widget_queue_draw_area(_map_widget,
+            _mark_minx,
+            _mark_miny,
+            _mark_width,
+            _mark_height);
+    map_set_mark();
+    gtk_widget_queue_draw_area(_map_widget,
+            _mark_minx,
+            _mark_miny,
+            _mark_width,
+            _mark_height);
 
-            dest->tail += num_src_points;
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
+}
 
-            /* Append waypoints from src to dest->. */
-            route_wresize(dest, (dest->wtail - dest->whead)
-                    + (src->wtail - src->whead) + 2);
-            for(curr = src->whead - 1; curr++ != src->wtail; )
-            {
-                (++(dest->wtail))->point = dest->head + num_dest_points
-                    + (curr->point - src_first);
-                dest->wtail->desc = curr->desc;
-            }
+/**
+ * Make sure the mark is up-to-date.  This function triggers a panning of
+ * the view if the mark is appropriately close to the edge of the view.
+ */
+static void
+refresh_mark()
+{
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-        }
+    guint new_center_unitx;
+    guint new_center_unity;
 
-        /* Kill old route - don't use MACRO_CLEAR_ROUTE(), because that
-         * would free the string desc's that we just moved to data.route. */
-        g_free(src->head);
-        g_free(src->whead);
-        if(policy_old < 0)
-            _route = *dest;
-    }
+    MACRO_RECALC_CENTER(new_center_unitx, new_center_unity);
+
+    if((new_center_unitx - _focus.unitx) < _focus_unitwidth
+            && (new_center_unity - _focus.unity) < _focus_unitheight)
+        /* We're not changing the view - just move the mark. */
+        map_move_mark();
     else
-    {
-        MACRO_CLEAR_ROUTE(_route);
-        /* Overwrite with data.route. */
-        _route = data.path.path.route;
-        route_resize(&_route, _route.tail - _route.head + 1);
-    }
+        map_center_unit(new_center_unitx, new_center_unity);
 
-    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
-    return TRUE;
+    vprintf("%s(): return\n", __PRETTY_FUNCTION__);
 }
 
 /**
@@ -6026,6 +6266,11 @@ maemo_mapper_init(gint argc, gchar **argv)
     ESCAPE_KEY_TEXT[ESCAPE_KEY_TOGGLE_GPS] = _("Toggle GPS");
     ESCAPE_KEY_TEXT[ESCAPE_KEY_TOGGLE_GPSINFO] = _("Toggle GPS Info");
 
+    /* Set up track array (must be done before config). */
+    memset(&_track, 0, sizeof(_track));
+    memset(&_route, 0, sizeof(_route));
+    MACRO_INIT_TRACK(_track);
+
     config_init();
 
     /* Initialize _program. */
@@ -6144,13 +6389,8 @@ maemo_mapper_init(gint argc, gchar **argv)
         _gmtoffset = time2.tm_gmtoff;
     }
 
-    memset(&_track, 0, sizeof(_track));
-    memset(&_route, 0, sizeof(_route));
     _last_spoken_phrase = g_strdup("");
 
-    /* Set up track array. */
-    MACRO_INIT_TRACK(_track);
-
     _downloads_hash = g_hash_table_new((GHashFunc)download_hashfunc,
             (GEqualFunc)download_equalfunc);
     memset(&_autoroute_data, 0, sizeof(_autoroute_data));
@@ -6232,6 +6472,12 @@ main(gint argc, gchar *argv[])
 
     gnome_vfs_init();
 
+    /* Initialize localization. */
+    setlocale(LC_ALL, "");
+    bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
+    bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+    textdomain(GETTEXT_PACKAGE);
+
     maemo_mapper_init(argc, argv);
 
     if(OSSO_OK != osso_rpc_set_default_cb_f(_osso, dbus_cb_default, NULL))
@@ -7562,216 +7808,80 @@ menu_cb_route_open(GtkAction *action)
     printf("%s()\n", __PRETTY_FUNCTION__);
 
     if(open_file(&buffer, NULL, &size, &_route_dir_uri, NULL,
-                    GTK_FILE_CHOOSER_ACTION_OPEN))
-    {
-        /* If auto is enabled, append the route, otherwise replace it. */
-        if(parse_route_gpx(buffer, size, _autoroute_data.enabled ? 0 : 1))
-        {
-            cancel_autoroute();
-
-            /* Find the nearest route point, if we're connected. */
-            route_find_nearest_point();
-
-            map_force_redraw();
-            hildon_banner_show_information(_window, NULL,
-                    _("Route Opened"));
-        }
-        else
-            popup_error(_window, _("Error parsing GPX file."));
-        g_free(buffer);
-    }
-
-    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
-    return TRUE;
-}
-
-static gboolean
-menu_cb_route_reset(GtkAction *action)
-{
-    printf("%s()\n", __PRETTY_FUNCTION__);
-
-    if(_route.head)
-    {
-        route_find_nearest_point();
-        map_render_paths();
-        map_render_poi();
-        MACRO_QUEUE_DRAW_AREA();
-    }
-
-    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
-    return TRUE;
-}
-
-static gboolean
-menu_cb_route_clear(GtkAction *action)
-{
-    printf("%s()\n", __PRETTY_FUNCTION__);
-
-    _next_way_dist_rough = -1; /* to avoid announcement attempts. */
-    cancel_autoroute();
-    MACRO_CLEAR_TRACK(_route);
-    map_force_redraw();
-
-    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
-    return TRUE;
-}
-
-static gboolean
-menu_cb_track_open(GtkAction *action)
-{
-    gchar *buffer;
-    gint size;
-    printf("%s()\n", __PRETTY_FUNCTION__);
-
-    if(open_file(&buffer, NULL, &size, NULL, &_track_file_uri,
-                    GTK_FILE_CHOOSER_ACTION_OPEN))
-    {
-        if(parse_track_gpx(buffer, size, -1))
-        {
-            map_force_redraw();
-            hildon_banner_show_information(_window, NULL, _("Track Opened"));
-        }
-        else
-            popup_error(_window, _("Error parsing GPX file."));
-        g_free(buffer);
-    }
-
-    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
-    return TRUE;
-}
-
-#define WRITE_STRING(string) { \
-    GnomeVFSResult vfs_result; \
-    GnomeVFSFileSize size; \
-    if(GNOME_VFS_OK != (vfs_result = gnome_vfs_write( \
-                    handle, (string), strlen((string)), &size))) \
-    { \
-        gchar buffer[1024]; \
-        sprintf(buffer, "%s:\n%s\n%s", _("Error while writing to file"), \
-                        _("File is incomplete."), \
-                gnome_vfs_result_to_string(vfs_result)); \
-        popup_error(_window, buffer); \
-        return FALSE; \
-    } \
-}
-
-static gboolean
-write_track_gpx(GnomeVFSHandle *handle)
-{
-    TrackPoint *curr;
-    gboolean trkseg_break = FALSE;
-    printf("%s()\n", __PRETTY_FUNCTION__);
-
-    /* Find first non-zero point. */
-    for(curr = _track.head-1; curr++ != _track.tail; )
-        if(curr->point.unity)
-            break;
-
-    /* Write the header. */
-    WRITE_STRING(XML_TRKSEG_HEADER);
-
-    /* Curr points to first non-zero point. */
-    for(curr--; curr++ != _track.tail; )
-    {
-        gfloat lat, lon;
-        if(curr->point.unity)
-        {
-            gchar buffer[80];
-            gchar strlat[80], strlon[80];
-            if(trkseg_break)
-            {
-                /* First trkpt of the segment - write trkseg header. */
-                WRITE_STRING("    </trkseg>\n"
-                /* Write trkseg header. */
-                             "    <trkseg>\n");
-                trkseg_break = FALSE;
-            }
-            unit2latlon(curr->point.unitx, curr->point.unity, lat, lon);
-            g_ascii_formatd(strlat, 80, "%.06f", lat);
-            g_ascii_formatd(strlon, 80, "%.06f", lon);
-            sprintf(buffer, "      <trkpt lat=\"%s\" lon=\"%s\"",
-                    strlat, strlon);
-            WRITE_STRING(buffer);
+                    GTK_FILE_CHOOSER_ACTION_OPEN))
+    {
+        /* If auto is enabled, append the route, otherwise replace it. */
+        if(parse_route_gpx(buffer, size, _autoroute_data.enabled ? 0 : 1))
+        {
+            cancel_autoroute();
 
-            /* write the time */
-            if(curr->time)
-            {
-                WRITE_STRING(">\n        <time>");
-                {
-                    struct tm time;
-                    localtime_r(&curr->time, &time);
-                    strftime(buffer, 80, XML_DATE_FORMAT, &time);
-                    WRITE_STRING(buffer);
-                    WRITE_STRING(XML_TZONE);
-                }
-                WRITE_STRING("</time>\n"
-                         "      </trkpt>\n");
-            }
-            else
-                WRITE_STRING("/>\n");
+            /* Find the nearest route point, if we're connected. */
+            route_find_nearest_point();
+
+            map_force_redraw();
+            hildon_banner_show_information(_window, NULL,
+                    _("Route Opened"));
         }
         else
-            trkseg_break = TRUE;
+            popup_error(_window, _("Error parsing GPX file."));
+        g_free(buffer);
     }
 
-    /* Write the footer. */
-    WRITE_STRING(XML_TRKSEG_FOOTER);
+    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
+    return TRUE;
+}
+
+static gboolean
+menu_cb_route_reset(GtkAction *action)
+{
+    printf("%s()\n", __PRETTY_FUNCTION__);
+
+    if(_route.head)
+    {
+        route_find_nearest_point();
+        map_render_paths();
+        map_render_poi();
+        MACRO_QUEUE_DRAW_AREA();
+    }
 
     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
     return TRUE;
 }
 
 static gboolean
-write_route_gpx(GnomeVFSHandle *handle)
+menu_cb_route_clear(GtkAction *action)
 {
-    Point *curr;
-    WayPoint *wcurr;
-    gboolean trkseg_break = FALSE;
+    printf("%s()\n", __PRETTY_FUNCTION__);
 
-    /* Find first non-zero point. */
-    for(curr = _route.head-1, wcurr = _route.whead; curr++ != _route.tail; )
-        if(curr->unity)
-            break;
-        else if(curr == wcurr->point)
-            wcurr++;
+    _next_way_dist_rough = -1; /* to avoid announcement attempts. */
+    cancel_autoroute();
+    MACRO_CLEAR_TRACK(_route);
+    map_force_redraw();
 
-    /* Write the header. */
-    WRITE_STRING(XML_TRKSEG_HEADER);
+    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
+    return TRUE;
+}
 
-    /* Curr points to first non-zero point. */
-    for(curr--; curr++ != _route.tail; )
+static gboolean
+menu_cb_track_open(GtkAction *action)
+{
+    gchar *buffer;
+    gint size;
+    printf("%s()\n", __PRETTY_FUNCTION__);
+
+    if(open_file(&buffer, NULL, &size, NULL, &_track_file_uri,
+                    GTK_FILE_CHOOSER_ACTION_OPEN))
     {
-        gfloat lat, lon;
-        if(curr->unity)
+        if(parse_track_gpx(buffer, size, -1))
         {
-            gchar buffer[80];
-            gchar strlat[80], strlon[80];
-            if(trkseg_break)
-            {
-                /* First trkpt of the segment - write trkseg header. */
-                WRITE_STRING("    </trkseg>\n"
-                             "    <trkseg>\n");
-                trkseg_break = FALSE;
-            }
-            unit2latlon(curr->unitx, curr->unity, lat, lon);
-            g_ascii_formatd(strlat, 80, "%.06f", lat);
-            g_ascii_formatd(strlon, 80, "%.06f", lon);
-            sprintf(buffer, "      <trkpt lat=\"%s\" lon=\"%s\"",
-                    strlat, strlon);
-            if(curr == wcurr->point)
-                sprintf(buffer + strlen(buffer),
-                        "><desc>%s</desc></trkpt>\n", wcurr++->desc);
-            else
-                strcat(buffer, "/>\n");
-            WRITE_STRING(buffer);
+            map_force_redraw();
+            hildon_banner_show_information(_window, NULL, _("Track Opened"));
         }
         else
-            trkseg_break = TRUE;
+            popup_error(_window, _("Error parsing GPX file."));
+        g_free(buffer);
     }
 
-    /* Write the footer. */
-    WRITE_STRING(XML_TRKSEG_FOOTER);
-
     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
     return TRUE;
 }
@@ -8453,6 +8563,7 @@ menu_cb_maps_repoman(GtkAction *action)
 
 typedef struct _MapmanInfo MapmanInfo;
 struct _MapmanInfo {
+    GtkWidget *dialog;
     GtkWidget *notebook;
     GtkWidget *tbl_area;
 
@@ -8461,8 +8572,8 @@ struct _MapmanInfo {
     GtkWidget *rad_delete;
     GtkWidget *chk_overwrite;
     GtkWidget *rad_by_area;
-    GtkWidget *rad_along_route;
-    GtkWidget *txt_route_radius;
+    GtkWidget *rad_by_route;
+    GtkWidget *num_route_radius;
 
     /* The "Area" tab. */
     GtkWidget *txt_topleft_lat;
@@ -8474,6 +8585,217 @@ struct _MapmanInfo {
     GtkWidget *chk_zoom_levels[MAX_ZOOM];
 };
 
+static gboolean
+mapman_by_area(gfloat start_lat, gfloat start_lon,
+        gfloat end_lat, gfloat end_lon, MapmanInfo *mapman_info,
+        gboolean is_deleting, gboolean is_overwriting)
+{
+    guint start_unitx, start_unity, end_unitx, end_unity;
+    guint num_maps = 0;
+    guint i;
+    gchar buffer[80];
+    GtkWidget *confirm;
+    printf("%s()\n", __PRETTY_FUNCTION__);
+
+    latlon2unit(start_lat, start_lon, start_unitx, start_unity);
+    latlon2unit(end_lat, end_lon, end_unitx, end_unity);
+
+    /* Swap if they specified flipped lats or lons. */
+    if(start_unitx > end_unitx)
+    {
+        guint swap = start_unitx;
+        start_unitx = end_unitx;
+        end_unitx = swap;
+    }
+    if(start_unity > end_unity)
+    {
+        guint swap = start_unity;
+        start_unity = end_unity;
+        end_unity = swap;
+    }
+
+    /* First, get the number of maps to download. */
+    for(i = 0; i < MAX_ZOOM; i++)
+    {
+        if(gtk_toggle_button_get_active(
+                    GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[i])))
+        {
+            guint start_tilex, start_tiley, end_tilex, end_tiley;
+            start_tilex = unit2ztile(start_unitx, i);
+            start_tiley = unit2ztile(start_unity, i);
+            end_tilex = unit2ztile(end_unitx, i);
+            end_tiley = unit2ztile(end_unity, i);
+            num_maps += (end_tilex - start_tilex + 1)
+                * (end_tiley - start_tiley + 1);
+        }
+    }
+
+    if(is_deleting)
+    {
+        sprintf(buffer, "%s %d %s", _("Confirm DELETION of"),
+                num_maps, _("maps"));
+    }
+    else
+    {
+        sprintf(buffer,
+                "%s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
+                num_maps, _("maps"), _("up to about"),
+                num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
+    }
+    confirm = hildon_note_new_confirmation(
+            GTK_WINDOW(mapman_info->dialog), buffer);
+
+    if(GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm)))
+    {
+        gtk_widget_destroy(confirm);
+        vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
+        return FALSE;
+    }
+    for(i = 0; i < MAX_ZOOM; i++)
+    {
+        if(gtk_toggle_button_get_active(
+                    GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[i])))
+        {
+            guint start_tilex, start_tiley, end_tilex, end_tiley;
+            guint tilex, tiley;
+            start_tilex = unit2ztile(start_unitx, i);
+            start_tiley = unit2ztile(start_unity, i);
+            end_tilex = unit2ztile(end_unitx, i);
+            end_tiley = unit2ztile(end_unity, i);
+            for(tiley = start_tiley; tiley <= end_tiley; tiley++)
+                for(tilex = start_tilex; tilex <= end_tilex; tilex++)
+                    map_initiate_download(tilex, tiley, i,
+                            is_deleting ? 0 :
+                                      (is_overwriting
+                                        ? -INITIAL_DOWNLOAD_RETRIES
+                                        : INITIAL_DOWNLOAD_RETRIES));
+        }
+    }
+    gtk_widget_destroy(confirm);
+    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
+    return TRUE;
+}
+
+static gboolean
+mapman_by_route(MapmanInfo *mapman_info,
+        gboolean is_deleting, gboolean is_overwriting)
+{
+    GtkWidget *confirm;
+    guint prev_tilex, prev_tiley, num_maps = 0, i;
+    Point *curr;
+    gchar buffer[80];
+    guint radius = hildon_number_editor_get_value(
+            HILDON_NUMBER_EDITOR(mapman_info->num_route_radius));
+    printf("%s()\n", __PRETTY_FUNCTION__);
+
+    if(!_route.head)
+    {
+        popup_error(mapman_info->dialog, "No route is loaded.");
+        return TRUE;
+    }
+
+    /* First, get the number of maps to download. */
+    for(i = 0; i < MAX_ZOOM; i++)
+    {
+        if(gtk_toggle_button_get_active(
+                    GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[i])))
+        {
+            prev_tilex = 0;
+            prev_tiley = 0;
+            for(curr = _route.head - 1; ++curr != _route.tail; )
+            {
+                if(curr->unity)
+                {
+                    guint tilex = unit2ztile(curr->unitx, i);
+                    guint tiley = unit2ztile(curr->unity, i);
+                    if(tilex != prev_tilex || tiley != prev_tiley)
+                    {
+                        if(prev_tiley)
+                            num_maps += (abs((gint)tilex - prev_tilex) + 1)
+                                * (abs((gint)tiley - prev_tiley) + 1) - 1;
+                        prev_tilex = tilex;
+                        prev_tiley = tiley;
+                    }
+                }
+            }
+        }
+    }
+    num_maps *= 0.625 * pow(radius + 1, 1.85);
+
+    if(is_deleting)
+    {
+        sprintf(buffer, "%s %s %d %s", _("Confirm DELETION of"), _("about"),
+                num_maps, _("maps"));
+    }
+    else
+    {
+        sprintf(buffer,
+                "%s %s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
+                _("about"),
+                num_maps, _("maps"), _("up to about"),
+                num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
+    }
+    confirm = hildon_note_new_confirmation(
+            GTK_WINDOW(mapman_info->dialog), buffer);
+
+    if(GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm)))
+    {
+        gtk_widget_destroy(confirm);
+        vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
+        return FALSE;
+    }
+
+    /* Now, do the actual download. */
+    for(i = 0; i < MAX_ZOOM; i++)
+    {
+        if(gtk_toggle_button_get_active(
+                    GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[i])))
+        {
+            prev_tilex = 0;
+            prev_tiley = 0;
+            for(curr = _route.head - 1; ++curr != _route.tail; )
+            {
+                if(curr->unity)
+                {
+                    guint tilex = unit2ztile(curr->unitx, i);
+                    guint tiley = unit2ztile(curr->unity, i);
+                    if(tilex != prev_tilex || tiley != prev_tiley)
+                    {
+                        guint minx, miny, maxx, maxy, x, y;
+                        if(prev_tiley != 0)
+                        {
+                            minx = MIN(tilex, prev_tilex) - radius;
+                            miny = MIN(tiley, prev_tiley) - radius;
+                            maxx = MAX(tilex, prev_tilex) + radius;
+                            maxy = MAX(tiley, prev_tiley) + radius;
+                        }
+                        else
+                        {
+                            minx = tilex - radius;
+                            miny = tiley - radius;
+                            maxx = tilex + radius;
+                            maxy = tiley + radius;
+                        }
+                        for(x = minx; x <= maxx; x++)
+                            for(y = miny; y <= maxy; y++)
+                                map_initiate_download(x, y, i,
+                                        is_deleting ? 0 :
+                                              (is_overwriting
+                                                ? -INITIAL_DOWNLOAD_RETRIES
+                                                : INITIAL_DOWNLOAD_RETRIES));
+                        prev_tilex = tilex;
+                        prev_tiley = tiley;
+                    }
+                }
+            }
+        }
+    }
+    _route_dl_radius = radius;
+    gtk_widget_destroy(confirm);
+    vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
+    return TRUE;
+}
+
 static void mapman_clear(GtkWidget *widget, MapmanInfo *mapman_info)
 {
     guint i;
@@ -8507,9 +8829,9 @@ static void mapman_update_state(GtkWidget *widget, MapmanInfo *mapman_info)
     else if(gtk_notebook_get_n_pages(GTK_NOTEBOOK(mapman_info->notebook)) == 3)
         gtk_widget_hide(mapman_info->tbl_area);
 
-    gtk_widget_set_sensitive(mapman_info->txt_route_radius,
+    gtk_widget_set_sensitive(mapman_info->num_route_radius,
             gtk_toggle_button_get_active(
-                GTK_TOGGLE_BUTTON(mapman_info->rad_along_route)));
+                GTK_TOGGLE_BUTTON(mapman_info->rad_by_route)));
 }
 
 static gboolean
@@ -8541,7 +8863,7 @@ menu_cb_mapman(GtkAction *action)
     guint i;
     printf("%s()\n", __PRETTY_FUNCTION__);
 
-    dialog = gtk_dialog_new_with_buttons(_("Manage Maps"),
+    mapman_info.dialog = dialog = gtk_dialog_new_with_buttons(_("Manage Maps"),
             GTK_WINDOW(_window), GTK_DIALOG_MODAL,
             GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
             NULL);
@@ -8600,19 +8922,18 @@ menu_cb_mapman(GtkAction *action)
             hbox = gtk_hbox_new(FALSE, 4),
             FALSE, FALSE, 0);
     gtk_box_pack_start(GTK_BOX(hbox),
-            mapman_info.rad_along_route
+            mapman_info.rad_by_route
                     = gtk_radio_button_new_with_label_from_widget(
                         GTK_RADIO_BUTTON(mapman_info.rad_by_area),
-                        _("Along Route - Radius:")),
+                        _("Along Route - Radius (tiles):")),
             FALSE, FALSE, 0);
-    gtk_widget_set_sensitive(mapman_info.rad_along_route, _route.head != NULL);
+    gtk_widget_set_sensitive(mapman_info.rad_by_route, _route.head != NULL);
     gtk_box_pack_start(GTK_BOX(hbox),
-            mapman_info.txt_route_radius
-                    = gtk_entry_new(),
+            mapman_info.num_route_radius = hildon_number_editor_new(0, 100),
             FALSE, FALSE, 0);
-    gtk_box_pack_start(GTK_BOX(hbox),
-            gtk_label_new(UNITS_TEXT[_units]), FALSE, FALSE, 0);
-    gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_route_radius), 1.f);
+    hildon_number_editor_set_value(
+            HILDON_NUMBER_EDITOR(mapman_info.num_route_radius),
+            _route_dl_radius);
 
 
     /* Zoom page. */
@@ -8772,128 +9093,59 @@ menu_cb_mapman(GtkAction *action)
                       G_CALLBACK(mapman_update_state), &mapman_info);
     g_signal_connect(G_OBJECT(mapman_info.rad_by_area), "clicked",
                       G_CALLBACK(mapman_update_state), &mapman_info);
-    g_signal_connect(G_OBJECT(mapman_info.rad_along_route), "clicked",
+    g_signal_connect(G_OBJECT(mapman_info.rad_by_route), "clicked",
                       G_CALLBACK(mapman_update_state), &mapman_info);
 
     while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
     {
-        const gchar *text;
-        gchar *error_check;
-        gfloat start_lat, start_lon, end_lat, end_lon;
-        guint start_unitx, start_unity, end_unitx, end_unity;
-        guint num_maps = 0;
-        GtkWidget *confirm;
-        gboolean is_deleting, is_overwriting;
-
-        text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lat));
-        start_lat = strtof(text, &error_check);
-        if(text == error_check) {
-            popup_error(dialog, _("Invalid Top-Left Latitude"));
-            continue;
-        }
-
-        text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lon));
-        start_lon = strtof(text, &error_check);
-        if(text == error_check) {
-            popup_error(dialog, _("Invalid Top-Left Longitude"));
-            continue;
-        }
-
-        text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lat));
-        end_lat = strtof(text, &error_check);
-        if(text == error_check) {
-            popup_error(dialog, _("Invalid Bottom-Right Latitude"));
-            continue;
-        }
-
-        text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lon));
-        end_lon = strtof(text, &error_check);
-        if(text == error_check) {
-            popup_error(dialog,_("Invalid Bottom-Right Longitude"));
-            continue;
-        }
-
-        latlon2unit(start_lat, start_lon, start_unitx, start_unity);
-        latlon2unit(end_lat, end_lon, end_unitx, end_unity);
-
-        /* Swap if they specified flipped lats or lons. */
-        if(start_unitx > end_unitx)
-        {
-            guint swap = start_unitx;
-            start_unitx = end_unitx;
-            end_unitx = swap;
-        }
-        if(start_unity > end_unity)
-        {
-            guint swap = start_unity;
-            start_unity = end_unity;
-            end_unity = swap;
-        }
-
-        /* First, get the number of maps to download. */
-        for(i = 0; i < MAX_ZOOM; i++)
-        {
-            if(gtk_toggle_button_get_active(
-                        GTK_TOGGLE_BUTTON(mapman_info.chk_zoom_levels[i])))
-            {
-                guint start_tilex, start_tiley, end_tilex, end_tiley;
-                start_tilex = unit2ztile(start_unitx, i);
-                start_tiley = unit2ztile(start_unity, i);
-                end_tilex = unit2ztile(end_unitx, i);
-                end_tiley = unit2ztile(end_unity, i);
-                num_maps += (end_tilex - start_tilex + 1)
-                    * (end_tiley - start_tiley + 1);
-            }
-        }
-        text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lat));
-
-        is_deleting = gtk_toggle_button_get_active(
+        gboolean is_deleting = gtk_toggle_button_get_active(
                 GTK_TOGGLE_BUTTON(mapman_info.rad_delete));
-        is_overwriting = gtk_toggle_button_get_active(
+        gboolean is_overwriting = gtk_toggle_button_get_active(
                 GTK_TOGGLE_BUTTON(mapman_info.chk_overwrite));
-
-        if(is_deleting)
+        if(gtk_toggle_button_get_active(
+                    GTK_TOGGLE_BUTTON(mapman_info.rad_by_route)))
         {
-            sprintf(buffer, "%s %d %s", _("Confirm DELETION of"),
-                    num_maps, _("maps"));
+            if(mapman_by_route(&mapman_info, is_deleting, is_overwriting))
+                break;
         }
         else
         {
-            sprintf(buffer,
-                    "%s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
-                    num_maps, _("maps"), _("up to about"),
-                    num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
-        }
-        text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lat));
-        confirm = hildon_note_new_confirmation(GTK_WINDOW(dialog), buffer);
-        text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lat));
+            const gchar *text;
+            gchar *error_check;
+            gfloat start_lat, start_lon, end_lat, end_lon;
+
+            text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lat));
+            start_lat = strtof(text, &error_check);
+            if(text == error_check) {
+                popup_error(dialog, _("Invalid Top-Left Latitude"));
+                continue;
+            }
 
-        if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
-        {
-            for(i = 0; i < MAX_ZOOM; i++)
-            {
-                if(gtk_toggle_button_get_active(
-                            GTK_TOGGLE_BUTTON(mapman_info.chk_zoom_levels[i])))
-                {
-                    guint start_tilex, start_tiley, end_tilex, end_tiley;
-                    guint tilex, tiley;
-                    start_tilex = unit2ztile(start_unitx, i);
-                    start_tiley = unit2ztile(start_unity, i);
-                    end_tilex = unit2ztile(end_unitx, i);
-                    end_tiley = unit2ztile(end_unity, i);
-                    for(tiley = start_tiley; tiley <= end_tiley; tiley++)
-                        for(tilex = start_tilex; tilex <= end_tilex; tilex++)
-                            map_initiate_download(tilex, tiley, i,
-                                    is_deleting ? 0 :
-                                              (is_overwriting
-                                                ? -INITIAL_DOWNLOAD_RETRIES
-                                                : INITIAL_DOWNLOAD_RETRIES));
-                }
+            text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lon));
+            start_lon = strtof(text, &error_check);
+            if(text == error_check) {
+                popup_error(dialog, _("Invalid Top-Left Longitude"));
+                continue;
             }
-            gtk_widget_destroy(confirm);
-            break;
+
+            text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lat));
+            end_lat = strtof(text, &error_check);
+            if(text == error_check) {
+                popup_error(dialog, _("Invalid Bottom-Right Latitude"));
+                continue;
+            }
+
+            text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lon));
+            end_lon = strtof(text, &error_check);
+            if(text == error_check) {
+                popup_error(dialog,_("Invalid Bottom-Right Longitude"));
+                continue;
+            }
+
+            if(mapman_by_area(start_lat, start_lon, end_lat, end_lon,
+                        &mapman_info, is_deleting, is_overwriting))
+                break;
         }
-        gtk_widget_destroy(confirm);
     }
 
     gtk_widget_hide(dialog); /* Destroying causes a crash (!?!?!??!) */