Diff of /trunk/src/osm-gps-map.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 68 by harbaum, Thu Aug 20 09:54:10 2009 UTC revision 280 by harbaum, Fri May 21 19:28:16 2010 UTC
# Line 4  Line 4 
4   * osm-gps-map.c   * osm-gps-map.c
5   * Copyright (C) Marcus Bauer 2008 <marcus.bauer@gmail.com>   * Copyright (C) Marcus Bauer 2008 <marcus.bauer@gmail.com>
6   * Copyright (C) John Stowers 2009 <john.stowers@gmail.com>   * Copyright (C) John Stowers 2009 <john.stowers@gmail.com>
7     * Copyright (C) Till Harbaum 2009 <till@harbaum.org>
8   *   *
9   * Contributions by   * Contributions by
10   * Everaldo Canuto 2009 <everaldo.canuto@gmail.com>   * Everaldo Canuto 2009 <everaldo.canuto@gmail.com>
11   *   *
12   * osm-gps-map.c is free software: you can redistribute it and/or modify it   * osm-gps-map.c is free software: you can redistribute it and/or modify it
13   * under the terms of the GNU General Public License as published by the   * under the terms of the GNU General Public License
14   * Free Software Foundation, either version 3 of the License, or   * as published by the Free Software Foundation; version 2.
  * (at your option) any later version.  
15   *   *
16   * osm-gps-map.c is distributed in the hope that it will be useful, but   * This program is distributed in the hope that it will be useful,
17   * WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * See the GNU General Public License for more details.   * GNU General Public License for more details.
20   *   *
21   * You should have received a copy of the GNU General Public License along   * You should have received a copy of the GNU General Public License
22   * with this program.  If not, see <http://www.gnu.org/licenses/>.   * along with this program; if not, see <http://www.gnu.org/licenses/>.
23   */   */
24    
25  #include "config.h"  #include "config.h"
# Line 36  Line 36 
36  #include <glib/gstdio.h>  #include <glib/gstdio.h>
37  #include <glib/gprintf.h>  #include <glib/gprintf.h>
38  #include <libsoup/soup.h>  #include <libsoup/soup.h>
39    #include <cairo.h>
40    
41  #include "converter.h"  #include "converter.h"
42  #include "osm-gps-map-types.h"  #include "osm-gps-map-types.h"
43  #include "osm-gps-map.h"  #include "osm-gps-map.h"
44    
 #ifdef USE_CAIRO  
 #include <cairo.h>  
 #endif  
   
45  #define ENABLE_DEBUG 0  #define ENABLE_DEBUG 0
46    
47  #define EXTRA_BORDER (TILESIZE / 2)  #define EXTRA_BORDER (TILESIZE / 2)
48    
49    #define OSM_GPS_MAP_SCROLL_STEP 10
50    
51    #define USER_AGENT "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11"
52    
53  struct _OsmGpsMapPrivate  struct _OsmGpsMapPrivate
54  {  {
55      GHashTable *tile_queue;      GHashTable *tile_queue;
# Line 78  struct _OsmGpsMapPrivate Line 79  struct _OsmGpsMapPrivate
79      char *proxy_uri;      char *proxy_uri;
80    
81      //where downloaded tiles are cached      //where downloaded tiles are cached
82        char *tile_dir;
83        char *tile_base_dir;
84      char *cache_dir;      char *cache_dir;
     gboolean cache_dir_is_full_path;  
85    
86      //contains flags indicating the various special characters      //contains flags indicating the various special characters
87      //the uri string contains, that will be replaced when calculating      //the uri string contains, that will be replaced when calculating
# Line 96  struct _OsmGpsMapPrivate Line 98  struct _OsmGpsMapPrivate
98      gboolean show_trip_history;      gboolean show_trip_history;
99      GSList *trip_history;      GSList *trip_history;
100      coord_t *gps;      coord_t *gps;
101        float gps_heading;
102      gboolean gps_valid;      gboolean gps_valid;
103    
 #ifdef ENABLE_BALLOON  
     //a balloon with additional info  
     struct {  
         coord_t *coo;  
         gboolean valid;  
         OsmGpsMapRect_t rect;  
         OsmGpsMapBalloonCallback cb;  
         gpointer data;  
     } balloon;  
 #endif  
   
104  #ifdef ENABLE_OSD  #ifdef ENABLE_OSD
105      //the osd controls      //the osd controls (if present)
106      struct {      osm_gps_map_osd_t *osd;
107          GdkPixmap *backup;  #ifdef OSD_DOUBLE_BUFFER
108          cairo_surface_t *overlay;      GdkPixmap *dbuf_pixmap;
         gint backup_x, backup_y;  
         OsmGpsMapOsdGpsCallback cb;  
         gpointer data;  
     } osd;  
109  #endif  #endif
110    #endif
111      //additional images or tracks added to the map      //additional images or tracks added to the map
112      GSList *tracks;      GSList *tracks;
113      GSList *images;      GSList *images;
# Line 139  struct _OsmGpsMapPrivate Line 127  struct _OsmGpsMapPrivate
127      int drag_start_mouse_y;      int drag_start_mouse_y;
128      int drag_start_map_x;      int drag_start_map_x;
129      int drag_start_map_y;      int drag_start_map_y;
130        int drag_limit;
131        guint drag_expose;
132    
133      //for customizing the redering of the gps track      //for customizing the redering of the gps track
134      int ui_gps_track_width;      int ui_gps_track_width;
135      int ui_gps_point_inner_radius;      int ui_gps_point_inner_radius;
136      int ui_gps_point_outer_radius;      int ui_gps_point_outer_radius;
137    
138        //For storing keybindings
139        guint keybindings[OSM_GPS_MAP_KEY_MAX];
140    
141        guint fullscreen : 1;
142        guint keybindings_enabled : 1;
143      guint is_disposed : 1;      guint is_disposed : 1;
144      guint dragging : 1;      guint dragging : 1;
145      guint center_coord_set : 1;      guint button_down : 1;
146        guint double_pixel : 1;
147  };  };
148    
149  #define OSM_GPS_MAP_PRIVATE(o)  (OSM_GPS_MAP (o)->priv)  #define OSM_GPS_MAP_PRIVATE(o)  (OSM_GPS_MAP (o)->priv)
# Line 164  enum Line 160  enum
160  {  {
161      PROP_0,      PROP_0,
162    
163        PROP_DOUBLE_PIXEL,
164      PROP_AUTO_CENTER,      PROP_AUTO_CENTER,
165      PROP_RECORD_TRIP_HISTORY,      PROP_RECORD_TRIP_HISTORY,
166      PROP_SHOW_TRIP_HISTORY,      PROP_SHOW_TRIP_HISTORY,
# Line 171  enum Line 168  enum
168      PROP_REPO_URI,      PROP_REPO_URI,
169      PROP_PROXY_URI,      PROP_PROXY_URI,
170      PROP_TILE_CACHE_DIR,      PROP_TILE_CACHE_DIR,
171        PROP_TILE_CACHE_BASE_DIR,
172      PROP_TILE_CACHE_DIR_IS_FULL_PATH,      PROP_TILE_CACHE_DIR_IS_FULL_PATH,
173      PROP_ZOOM,      PROP_ZOOM,
174      PROP_MAX_ZOOM,      PROP_MAX_ZOOM,
# Line 184  enum Line 182  enum
182      PROP_GPS_POINT_R1,      PROP_GPS_POINT_R1,
183      PROP_GPS_POINT_R2,      PROP_GPS_POINT_R2,
184      PROP_MAP_SOURCE,      PROP_MAP_SOURCE,
185      PROP_IMAGE_FORMAT      PROP_IMAGE_FORMAT,
186        PROP_DRAG_LIMIT,
187  };  };
188    
189  G_DEFINE_TYPE (OsmGpsMap, osm_gps_map, GTK_TYPE_DRAWING_AREA);  G_DEFINE_TYPE (OsmGpsMap, osm_gps_map, GTK_TYPE_DRAWING_AREA);
# Line 198  static gchar    *replace_map_uri(OsmGpsM Line 197  static gchar    *replace_map_uri(OsmGpsM
197  static void     osm_gps_map_print_images (OsmGpsMap *map);  static void     osm_gps_map_print_images (OsmGpsMap *map);
198  static void     osm_gps_map_draw_gps_point (OsmGpsMap *map);  static void     osm_gps_map_draw_gps_point (OsmGpsMap *map);
199  static void     osm_gps_map_blit_tile(OsmGpsMap *map, GdkPixbuf *pixbuf, int offset_x, int offset_y);  static void     osm_gps_map_blit_tile(OsmGpsMap *map, GdkPixbuf *pixbuf, int offset_x, int offset_y);
200  #ifdef LIBSOUP22  #if USE_LIBSOUP22
201  static void     osm_gps_map_tile_download_complete (SoupMessage *msg, gpointer user_data);  static void     osm_gps_map_tile_download_complete (SoupMessage *msg, gpointer user_data);
202  #else  #else
203  static void     osm_gps_map_tile_download_complete (SoupSession *session, SoupMessage *msg, gpointer user_data);  static void     osm_gps_map_tile_download_complete (SoupSession *session, SoupMessage *msg, gpointer user_data);
# Line 332  static void Line 331  static void
331  inspect_map_uri(OsmGpsMap *map)  inspect_map_uri(OsmGpsMap *map)
332  {  {
333      OsmGpsMapPrivate *priv = map->priv;      OsmGpsMapPrivate *priv = map->priv;
334        priv->uri_format = 0;
335        priv->the_google = FALSE;
336    
337      if (g_strrstr(priv->repo_uri, URI_MARKER_X))      if (g_strrstr(priv->repo_uri, URI_MARKER_X))
338          priv->uri_format |= URI_HAS_X;          priv->uri_format |= URI_HAS_X;
# Line 540  osm_gps_map_print_images (OsmGpsMap *map Line 541  osm_gps_map_print_images (OsmGpsMap *map
541                           priv->gc_map,                           priv->gc_map,
542                           im->image,                           im->image,
543                           0,0,                           0,0,
544                           x-(im->w/2),y-(im->h/2),                           x-im->xoffset,y-im->yoffset,
545                           im->w,im->h,                           im->w,im->h,
546                           GDK_RGB_DITHER_NONE, 0, 0);                           GDK_RGB_DITHER_NONE, 0, 0);
547    
# Line 568  osm_gps_map_draw_gps_point (OsmGpsMap *m Line 569  osm_gps_map_draw_gps_point (OsmGpsMap *m
569          int x, y;          int x, y;
570          int r = priv->ui_gps_point_inner_radius;          int r = priv->ui_gps_point_inner_radius;
571          int r2 = priv->ui_gps_point_outer_radius;          int r2 = priv->ui_gps_point_outer_radius;
572          // int lw = priv->ui_gps_track_width;          int mr = MAX(3*r,r2);
         int mr = MAX(r,r2);  
573    
574          map_x0 = priv->map_x - EXTRA_BORDER;          map_x0 = priv->map_x - EXTRA_BORDER;
575          map_y0 = priv->map_y - EXTRA_BORDER;          map_y0 = priv->map_y - EXTRA_BORDER;
576          x = lon2pixel(priv->map_zoom, priv->gps->rlon) - map_x0;          x = lon2pixel(priv->map_zoom, priv->gps->rlon) - map_x0;
577          y = lat2pixel(priv->map_zoom, priv->gps->rlat) - map_y0;          y = lat2pixel(priv->map_zoom, priv->gps->rlat) - map_y0;
 #ifdef USE_CAIRO  
578          cairo_t *cr;          cairo_t *cr;
579          cairo_pattern_t *pat;          cairo_pattern_t *pat;
 #else  
         GdkColor color;  
         GdkGC *marker;  
 #endif  
580    
 #ifdef USE_CAIRO  
581          cr = gdk_cairo_create(priv->pixmap);          cr = gdk_cairo_create(priv->pixmap);
582    
583          // draw transparent area          // draw transparent area
# Line 600  osm_gps_map_draw_gps_point (OsmGpsMap *m Line 594  osm_gps_map_draw_gps_point (OsmGpsMap *m
594    
595          // draw ball gradient          // draw ball gradient
596          if (r > 0) {          if (r > 0) {
597                // draw direction arrow
598                if(!isnan(priv->gps_heading))
599                {
600                    cairo_move_to (cr, x-r*cos(priv->gps_heading), y-r*sin(priv->gps_heading));
601                    cairo_line_to (cr, x+3*r*sin(priv->gps_heading), y-3*r*cos(priv->gps_heading));
602                    cairo_line_to (cr, x+r*cos(priv->gps_heading), y+r*sin(priv->gps_heading));
603                    cairo_close_path (cr);
604    
605                    cairo_set_source_rgba (cr, 0.3, 0.3, 1.0, 0.5);
606                    cairo_fill_preserve (cr);
607    
608                    cairo_set_line_width (cr, 1.0);
609                    cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5);
610                    cairo_stroke(cr);
611                }
612    
613              pat = cairo_pattern_create_radial (x-(r/5), y-(r/5), (r/5), x,  y, r);              pat = cairo_pattern_create_radial (x-(r/5), y-(r/5), (r/5), x,  y, r);
614              cairo_pattern_add_color_stop_rgba (pat, 0, 1, 1, 1, 1.0);              cairo_pattern_add_color_stop_rgba (pat, 0, 1, 1, 1, 1.0);
615              cairo_pattern_add_color_stop_rgba (pat, 1, 0, 0, 1, 1.0);              cairo_pattern_add_color_stop_rgba (pat, 1, 0, 0, 1, 1.0);
# Line 620  osm_gps_map_draw_gps_point (OsmGpsMap *m Line 630  osm_gps_map_draw_gps_point (OsmGpsMap *m
630                                      y-mr,                                      y-mr,
631                                      mr*2,                                      mr*2,
632                                      mr*2);                                      mr*2);
 #else  
         marker = gdk_gc_new(priv->pixmap);  
         color.red = 5000;  
         color.green = 5000;  
         color.blue = 55000;  
         gdk_gc_set_rgb_fg_color(marker, &color);  
         gdk_gc_set_line_attributes(marker, lw, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);  
   
         if (r2 > 0) {  
             gdk_draw_arc (priv->pixmap,  
                           marker,  
                           FALSE,            //filled  
                           x-r2, y-r2,       // x,y  
                           r2*2,r2*2,        // width, height  
                           0, 360*64);       // start-end angle 64th, from 3h, anti clockwise  
         }  
         if (r > 0) {  
             gdk_draw_arc (priv->pixmap,  
                           marker,  
                           TRUE,         //filled  
                           x-r, y-r,     // x,y  
                           r*2,r*2,      // width, height  
                           0, 360*64);   // start-end angle 64th, from 3h, anti clockwise  
         }  
   
         g_object_unref(marker);  
         gtk_widget_queue_draw_area (GTK_WIDGET(map),  
                                     x-(mr+lw),  
                                     y-(mr+lw),  
                                     (mr*2)+lw+lw,  
                                     (mr*2)+lw+lw);  
 #endif  
     }  
 }  
   
 #ifdef ENABLE_BALLOON  
 /* most visual effects are hardcoded by now, but may be made */  
 /* available via properties later */  
 #ifndef BALLOON_AREA_WIDTH  
 #define BALLOON_AREA_WIDTH           290  
 #endif  
 #ifndef BALLOON_AREA_HEIGHT  
 #define BALLOON_AREA_HEIGHT           75  
 #endif  
 #ifndef BALLOON_CORNER_RADIUS  
 #define BALLOON_CORNER_RADIUS         10  
 #endif  
   
 #define BALLOON_BORDER               (BALLOON_CORNER_RADIUS/2)  
 #define BALLOON_WIDTH                (BALLOON_AREA_WIDTH + 2 * BALLOON_BORDER)  
 #define BALLOON_HEIGHT               (BALLOON_AREA_HEIGHT + 2 * BALLOON_BORDER)  
 #define BALLOON_TRANSPARENCY         0.8  
 #define POINTER_HEIGHT                20  
 #define POINTER_FOOT_WIDTH            20  
 #define POINTER_OFFSET               (BALLOON_CORNER_RADIUS*3/4)  
 #define BALLOON_SHADOW               (BALLOON_CORNER_RADIUS/2)  
 #define BALLOON_SHADOW_TRANSPARENCY  0.2  
   
 #define CLOSE_BUTTON_RADIUS   (BALLOON_CORNER_RADIUS)  
   
   
 /* draw the bubble shape. this is used twice, once for the shape and once */  
 /* for the shadow */  
 static void  
 osm_gps_map_draw_balloon_shape (cairo_t *cr, int x0, int y0, int x1, int y1,  
        gboolean bottom, int px, int py, int px0, int px1) {  
   
     cairo_move_to (cr, x0, y0 + BALLOON_CORNER_RADIUS);  
     cairo_arc (cr, x0 + BALLOON_CORNER_RADIUS, y0 + BALLOON_CORNER_RADIUS,  
                BALLOON_CORNER_RADIUS, -M_PI, -M_PI/2);  
     if(!bottom) {  
         /* insert top pointer */  
         cairo_line_to (cr, px1, y0);  
         cairo_line_to (cr, px, py);  
         cairo_line_to (cr, px0, y0);  
     }  
   
     cairo_line_to (cr, x1 - BALLOON_CORNER_RADIUS, y0);  
     cairo_arc (cr, x1 - BALLOON_CORNER_RADIUS, y0 + BALLOON_CORNER_RADIUS,  
                BALLOON_CORNER_RADIUS, -M_PI/2, 0);  
     cairo_line_to (cr, x1 , y1 - BALLOON_CORNER_RADIUS);  
     cairo_arc (cr, x1 - BALLOON_CORNER_RADIUS, y1 - BALLOON_CORNER_RADIUS,  
                BALLOON_CORNER_RADIUS, 0, M_PI/2);  
     if(bottom) {  
         /* insert bottom pointer */  
         cairo_line_to (cr, px0, y1);  
         cairo_line_to (cr, px, py);  
         cairo_line_to (cr, px1, y1);  
633      }      }
   
     cairo_line_to (cr, x0 + BALLOON_CORNER_RADIUS, y1);  
     cairo_arc (cr, x0 + BALLOON_CORNER_RADIUS, y1 - BALLOON_CORNER_RADIUS,  
                BALLOON_CORNER_RADIUS, M_PI/2, M_PI);  
   
     cairo_close_path (cr);  
634  }  }
635    
636  static void  static void
637  osm_gps_map_draw_balloon_int (OsmGpsMap *map)  osm_gps_map_blit_tile(OsmGpsMap *map, GdkPixbuf *pixbuf, int offset_x, int offset_y)
638  {  {
639      OsmGpsMapPrivate *priv = map->priv;      OsmGpsMapPrivate *priv = map->priv;
640    
641      if (priv->balloon.valid) {      if (priv->double_pixel) {
642            g_debug("Queing redraw @ %d,%d (w:%d h:%d)", offset_x,offset_y, TILESIZE*2,TILESIZE*2);
         /* ------- convert given coordinate into screen position --------- */  
         int x0 = lon2pixel(priv->map_zoom, priv->balloon.coo->rlon) -  
             priv->map_x + EXTRA_BORDER;  
         int y0 = lat2pixel(priv->map_zoom, priv->balloon.coo->rlat) -  
             priv->map_y + EXTRA_BORDER;  
643    
644          /* check position of this relative to screen center to determine */          GdkPixbuf *double_pixbuf = gdk_pixbuf_scale_simple (pixbuf, TILESIZE*2, TILESIZE*2,
645          /* pointer direction ... */                                        GDK_INTERP_NEAREST);
         int pointer_x = x0, pointer_x0, pointer_x1;  
         int pointer_y = y0;  
   
         /* ... and calculate position */  
         if((x0 - EXTRA_BORDER) > GTK_WIDGET(map)->allocation.width/2) {  
             x0 -= BALLOON_WIDTH - POINTER_OFFSET;  
             pointer_x0 = pointer_x - (BALLOON_CORNER_RADIUS - POINTER_OFFSET);  
             pointer_x1 = pointer_x0 - POINTER_FOOT_WIDTH;  
         } else {  
             x0 -= POINTER_OFFSET;  
             pointer_x1 = pointer_x + (BALLOON_CORNER_RADIUS - POINTER_OFFSET);  
             pointer_x0 = pointer_x1 + POINTER_FOOT_WIDTH;  
         }  
   
         gboolean bottom = FALSE;  
         if((y0 - EXTRA_BORDER) > GTK_WIDGET(map)->allocation.height/2) {  
             bottom = TRUE;  
             y0 -= BALLOON_HEIGHT + POINTER_HEIGHT;  
         } else  
             y0 += POINTER_HEIGHT;  
   
         /* calculate bottom/right of box */  
         int x1 = x0 + BALLOON_WIDTH, y1 = y0 + BALLOON_HEIGHT;  
   
         /* save balloon screen coordinates for later use */  
         priv->balloon.rect.x = x0 + BALLOON_BORDER;  
         priv->balloon.rect.y = y0 + BALLOON_BORDER;  
         priv->balloon.rect.w = x1 - x0 - 2*BALLOON_BORDER;  
         priv->balloon.rect.h = y1 - y0 - 2*BALLOON_BORDER;  
   
 #ifdef USE_CAIRO  
         cairo_t *cr = gdk_cairo_create(priv->pixmap);  
   
         /* --------- draw shadow --------------- */  
         osm_gps_map_draw_balloon_shape (cr,  
                     x0 + BALLOON_SHADOW, y0 + BALLOON_SHADOW,  
                     x1 + BALLOON_SHADOW, y1 + BALLOON_SHADOW,  
                     bottom, pointer_x, pointer_y,  
                     pointer_x0 + BALLOON_SHADOW, pointer_x1 + BALLOON_SHADOW);  
   
         cairo_set_source_rgba (cr, 0, 0, 0, BALLOON_SHADOW_TRANSPARENCY);  
         cairo_fill_preserve (cr);  
         cairo_set_source_rgba (cr, 1, 0, 0, 1.0);  
         cairo_set_line_width (cr, 0);  
         cairo_stroke (cr);  
   
         /* --------- draw main shape ----------- */  
         osm_gps_map_draw_balloon_shape (cr, x0, y0, x1, y1,  
                     bottom, pointer_x, pointer_y, pointer_x0, pointer_x1);  
   
         cairo_set_source_rgba (cr, 1, 1, 1, BALLOON_TRANSPARENCY);  
         cairo_fill_preserve (cr);  
         cairo_set_source_rgba (cr, 0, 0, 0, BALLOON_TRANSPARENCY);  
         cairo_set_line_width (cr, 1);  
         cairo_stroke (cr);  
   
   
         /* ---------- draw close button --------- */  
   
         int cx = x1 - BALLOON_BORDER - CLOSE_BUTTON_RADIUS;  
         int cy = y0 + BALLOON_BORDER + CLOSE_BUTTON_RADIUS;  
         int crad = CLOSE_BUTTON_RADIUS;  
   
         cairo_arc (cr, cx, cy, crad, 0, 2 * M_PI);  
         cairo_set_source_rgba (cr, 0.8, 0, 0, 1.0);  
         cairo_fill_preserve (cr);  
         cairo_set_source_rgba (cr, 0.3, 0, 0, 1.0);  
         cairo_set_line_width (cr, 2);  
         cairo_stroke(cr);  
   
         cairo_set_source_rgba (cr, 1, 1, 1, 1.0);  
         cairo_set_line_width (cr, BALLOON_CORNER_RADIUS/3.3);  
         cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);  
         cairo_move_to (cr, cx - crad/2, cy - crad/2);  
         cairo_line_to (cr, cx + crad/2, cy + crad/2);  
         cairo_stroke (cr);  
         cairo_move_to (cr, cx + crad/2, cy - crad/2);  
         cairo_line_to (cr, cx - crad/2, cy + crad/2);  
         cairo_stroke (cr);  
   
         if (priv->balloon.cb) {  
             /* clip in case application tries to draw in */  
             /* exceed of the balloon */  
             cairo_rectangle (cr, priv->balloon.rect.x, priv->balloon.rect.y,  
                              priv->balloon.rect.w, priv->balloon.rect.h);  
             cairo_clip (cr);  
             cairo_new_path (cr);  /* current path is not  
                                      consumed by cairo_clip() */  
   
             priv->balloon.cb(cr, &priv->balloon.rect, priv->balloon.data);  
         }  
   
         cairo_destroy(cr);  
646    
647          gtk_widget_queue_draw_area (GTK_WIDGET(map),          /* draw pixbuf onto pixmap */
648                                      x0, y0, BALLOON_WIDTH,          gdk_draw_pixbuf (priv->pixmap,
649                                      BALLOON_HEIGHT + POINTER_HEIGHT);                           priv->gc_map,
650  #else                           double_pixbuf,
651  #warning "Balloon display lacks a non-cairo implementation!"                           0,0,
652  #endif                           offset_x,offset_y,
653                             TILESIZE*2,TILESIZE*2,
654                             GDK_RGB_DITHER_NONE, 0, 0);
655            g_object_unref (double_pixbuf);
656      }      }
657  }      else
658        {
659  /* the user clicked into the balloons main area. handle this */          g_debug("Queing redraw @ %d,%d (w:%d h:%d)", offset_x,offset_y, TILESIZE,TILESIZE);
 static void  
 osm_gps_map_handle_balloon_click(OsmGpsMap *map, gint x, gint y)  
 {  
     OsmGpsMapPrivate *priv = map->priv;  
   
     if (!priv->balloon.valid)  
         return;  
   
     /* check if the close button was clicked */  
     if ((x > priv->balloon.rect.w - 2*CLOSE_BUTTON_RADIUS) &&  
         (x < priv->balloon.rect.w) &&  
         (y > 0) && (y < 2*CLOSE_BUTTON_RADIUS)) {  
660    
661          priv->balloon.valid = FALSE;          /* draw pixbuf onto pixmap */
662          osm_gps_map_map_redraw_idle(map);          gdk_draw_pixbuf (priv->pixmap,
663                             priv->gc_map,
664                             pixbuf,
665                             0,0,
666                             offset_x,offset_y,
667                             TILESIZE,TILESIZE,
668                             GDK_RGB_DITHER_NONE, 0, 0);
669      }      }
670  }  }
671    
 /* return true if balloon is being displayed and if */  
 /* the given coordinate is within this balloon */  
 static gboolean  
 osm_gps_map_in_balloon(OsmGpsMapPrivate *priv, gint x, gint y)  
 {  
     return (priv->balloon.valid &&  
             (x > priv->balloon.rect.x) &&  
             (x < priv->balloon.rect.x + priv->balloon.rect.w) &&  
             (y > priv->balloon.rect.y) &&  
             (y < priv->balloon.rect.y + priv->balloon.rect.h));  
 }  
 #endif // ENABLE_BALLOON  
   
 static void  
 osm_gps_map_blit_tile(OsmGpsMap *map, GdkPixbuf *pixbuf, int offset_x, int offset_y)  
 {  
     OsmGpsMapPrivate *priv = map->priv;  
   
     g_debug("Queing redraw @ %d,%d (w:%d h:%d)", offset_x,offset_y, TILESIZE,TILESIZE);  
   
     /* draw pixbuf onto pixmap */  
     gdk_draw_pixbuf (priv->pixmap,  
                      priv->gc_map,  
                      pixbuf,  
                      0,0,  
                      offset_x,offset_y,  
                      TILESIZE,TILESIZE,  
                      GDK_RGB_DITHER_NONE, 0, 0);  
 }  
   
672  /* libsoup-2.2 and libsoup-2.4 use different ways to store the body data */  /* libsoup-2.2 and libsoup-2.4 use different ways to store the body data */
673  #ifdef LIBSOUP22  #if USE_LIBSOUP22
674  #define  soup_message_headers_append(a,b,c) soup_message_add_header(a,b,c)  #define  soup_message_headers_append(a,b,c) soup_message_add_header(a,b,c)
675  #define MSG_RESPONSE_BODY(a)    ((a)->response.body)  #define MSG_RESPONSE_BODY(a)    ((a)->response.body)
676  #define MSG_RESPONSE_LEN(a)     ((a)->response.length)  #define MSG_RESPONSE_LEN(a)     ((a)->response.length)
# Line 896  osm_gps_map_blit_tile(OsmGpsMap *map, Gd Line 681  osm_gps_map_blit_tile(OsmGpsMap *map, Gd
681  #define MSG_RESPONSE_LEN_FORMAT "%lld"  #define MSG_RESPONSE_LEN_FORMAT "%lld"
682  #endif  #endif
683    
684  #ifdef LIBSOUP22  #if USE_LIBSOUP22
685  static void  static void
686  osm_gps_map_tile_download_complete (SoupMessage *msg, gpointer user_data)  osm_gps_map_tile_download_complete (SoupMessage *msg, gpointer user_data)
687  #else  #else
# Line 1012  osm_gps_map_tile_download_complete (Soup Line 797  osm_gps_map_tile_download_complete (Soup
797          }          }
798          else          else
799          {          {
800  #ifdef LIBSOUP22  #if USE_LIBSOUP22
801              soup_session_requeue_message(dl->session, msg);              soup_session_requeue_message(dl->session, msg);
802  #else  #else
803              soup_session_requeue_message(session, msg);              soup_session_requeue_message(session, msg);
# Line 1034  osm_gps_map_download_tile (OsmGpsMap *ma Line 819  osm_gps_map_download_tile (OsmGpsMap *ma
819      //calculate the uri to download      //calculate the uri to download
820      dl->uri = replace_map_uri(map, priv->repo_uri, zoom, x, y);      dl->uri = replace_map_uri(map, priv->repo_uri, zoom, x, y);
821    
822  #ifdef LIBSOUP22  #if USE_LIBSOUP22
823      dl->session = priv->soup_session;      dl->session = priv->soup_session;
824  #endif  #endif
825    
# Line 1078  osm_gps_map_download_tile (OsmGpsMap *ma Line 863  osm_gps_map_download_tile (OsmGpsMap *ma
863                  }                  }
864              }              }
865    
866    #if USE_LIBSOUP22
867                soup_message_headers_append(msg->request_headers,
868                                            "User-Agent", USER_AGENT);
869    #endif
870    
871              g_hash_table_insert (priv->tile_queue, dl->uri, msg);              g_hash_table_insert (priv->tile_queue, dl->uri, msg);
872              soup_session_queue_message (priv->soup_session, msg, osm_gps_map_tile_download_complete, dl);              soup_session_queue_message (priv->soup_session, msg, osm_gps_map_tile_download_complete, dl);
873          } else {          } else {
# Line 1119  osm_gps_map_load_cached_tile (OsmGpsMap Line 909  osm_gps_map_load_cached_tile (OsmGpsMap
909              tile->pixbuf = pixbuf;              tile->pixbuf = pixbuf;
910              g_hash_table_insert (priv->tile_cache, filename, tile);              g_hash_table_insert (priv->tile_cache, filename, tile);
911          }          }
912            else
913            {
914                g_free (filename);
915            }
916      }      }
917    
918      /* set/update the redraw_cycle timestamp on the tile */      /* set/update the redraw_cycle timestamp on the tile */
# Line 1186  osm_gps_map_render_missing_tile (OsmGpsM Line 980  osm_gps_map_render_missing_tile (OsmGpsM
980      return osm_gps_map_render_missing_tile_upscaled (map, zoom, x, y);      return osm_gps_map_render_missing_tile_upscaled (map, zoom, x, y);
981  }  }
982    
983    /* default tile lifetime is one week */
984    #ifndef OSD_GPS_MAP_TILE_TTL
985    #define  OSD_GPS_MAP_TILE_TTL  (60*60*24*7)
986    #endif
987    
988    static gboolean
989    osm_gps_map_tile_age_exceeded(char *filename)
990    {
991        struct stat buf;
992    
993        if(!g_stat(filename, &buf))
994            return(time(NULL) - buf.st_mtime > OSD_GPS_MAP_TILE_TTL);
995    
996        return FALSE;
997    }
998    
999  static void  static void
1000  osm_gps_map_load_tile (OsmGpsMap *map, int zoom, int x, int y, int offset_x, int offset_y)  osm_gps_map_load_tile (OsmGpsMap *map, int zoom, int x, int y, int offset_x, int offset_y)
1001  {  {
1002      OsmGpsMapPrivate *priv = map->priv;      OsmGpsMapPrivate *priv = map->priv;
1003      gchar *filename;      gchar *filename;
1004      GdkPixbuf *pixbuf;      GdkPixbuf *pixbuf = NULL;
1005    
1006      g_debug("Load tile %d,%d (%d,%d) z:%d", x, y, offset_x, offset_y, zoom);      g_debug("Load tile %d,%d (%d,%d) z:%d", x, y, offset_x, offset_y, zoom);
1007    
# Line 1207  osm_gps_map_load_tile (OsmGpsMap *map, i Line 1017  osm_gps_map_load_tile (OsmGpsMap *map, i
1017                  y,                  y,
1018                  priv->image_format);                  priv->image_format);
1019    
1020      /* try to get file from internal cache first */      gboolean needs_refresh = FALSE;
1021      if(!(pixbuf = osm_gps_map_load_cached_tile(map, zoom, x, y)))      if (g_file_test(filename, G_FILE_TEST_EXISTS)) {
1022          pixbuf = gdk_pixbuf_new_from_file (filename, NULL);          /* try to get file from internal cache first */
1023            if(!(pixbuf = osm_gps_map_load_cached_tile(map, zoom, x, y)))
1024                pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
1025    
1026             needs_refresh = osm_gps_map_tile_age_exceeded(filename);
1027        }
1028    
1029      if(pixbuf)      if(pixbuf)
1030      {      {
# Line 1217  osm_gps_map_load_tile (OsmGpsMap *map, i Line 1032  osm_gps_map_load_tile (OsmGpsMap *map, i
1032          osm_gps_map_blit_tile(map, pixbuf, offset_x,offset_y);          osm_gps_map_blit_tile(map, pixbuf, offset_x,offset_y);
1033          g_object_unref (pixbuf);          g_object_unref (pixbuf);
1034      }      }
1035      else  
1036    
1037        if(!pixbuf || needs_refresh)
1038      {      {
1039          if (priv->map_auto_download)          if (priv->map_auto_download)
1040              osm_gps_map_download_tile(map, zoom, x, y, TRUE);              osm_gps_map_download_tile(map, zoom, x, y, TRUE);
1041    
1042          /* try to render the tile by scaling cached tiles from other zoom          if(!needs_refresh) {
1043           * levels */              /* try to render the tile by scaling cached tiles from other zoom
1044          pixbuf = osm_gps_map_render_missing_tile (map, zoom, x, y);               * levels */
1045          if (pixbuf)              pixbuf = osm_gps_map_render_missing_tile (map, zoom, x, y);
1046          {              if (pixbuf)
1047              gdk_draw_pixbuf (priv->pixmap,              {
1048                               priv->gc_map,                  osm_gps_map_blit_tile (map, pixbuf, offset_x,offset_y);
1049                               pixbuf,                  g_object_unref (pixbuf);
1050                               0,0,              }
1051                               offset_x,offset_y,              else
1052                               TILESIZE,TILESIZE,              {
1053                               GDK_RGB_DITHER_NONE, 0, 0);                  //prevent some artifacts when drawing not yet loaded areas.
1054              g_object_unref (pixbuf);                  gdk_draw_rectangle (priv->pixmap,
1055          }                                      GTK_WIDGET(map)->style->white_gc,
1056          else                                      TRUE, offset_x, offset_y, TILESIZE, TILESIZE);
1057          {              }
             //prevent some artifacts when drawing not yet loaded areas.  
             gdk_draw_rectangle (priv->pixmap,  
                                 GTK_WIDGET(map)->style->white_gc,  
                                 TRUE, offset_x, offset_y, TILESIZE, TILESIZE);  
1058          }          }
1059      }      }
1060      g_free(filename);      g_free(filename);
# Line 1259  osm_gps_map_fill_tiles_pixel (OsmGpsMap Line 1072  osm_gps_map_fill_tiles_pixel (OsmGpsMap
1072    
1073      g_debug("Fill tiles: %d,%d z:%d", priv->map_x, priv->map_y, priv->map_zoom);      g_debug("Fill tiles: %d,%d z:%d", priv->map_x, priv->map_y, priv->map_zoom);
1074    
1075      offset_x = - priv->map_x % TILESIZE;      if (priv->double_pixel)
1076      offset_y = - priv->map_y % TILESIZE;      {
1077      if (offset_x > 0) offset_x -= TILESIZE;          width  = GTK_WIDGET(map)->allocation.width;
1078      if (offset_y > 0) offset_y -= TILESIZE;          height = GTK_WIDGET(map)->allocation.height;
1079    
1080      offset_xn = offset_x + EXTRA_BORDER;          offset_x = - priv->map_x % (TILESIZE*2);
1081      offset_yn = offset_y + EXTRA_BORDER;          offset_y = - priv->map_y % (TILESIZE*2);
1082            if (offset_x > 0) offset_x -= (TILESIZE*2);
1083            if (offset_y > 0) offset_y -= (TILESIZE*2);
1084    
1085      width  = GTK_WIDGET(map)->allocation.width;          offset_xn = offset_x + EXTRA_BORDER;
1086      height = GTK_WIDGET(map)->allocation.height;          offset_yn = offset_y + EXTRA_BORDER;
1087    
1088      tiles_nx = (width  - offset_x) / TILESIZE + 1;          tiles_nx = (width  - offset_x) / (TILESIZE*2) + 1;
1089      tiles_ny = (height - offset_y) / TILESIZE + 1;          tiles_ny = (height - offset_y) / (TILESIZE*2) + 1;
1090    
1091      tile_x0 =  floor((float)priv->map_x / (float)TILESIZE);          tile_x0 =  floor((float)priv->map_x / (float)(TILESIZE*2));
1092      tile_y0 =  floor((float)priv->map_y / (float)TILESIZE);          tile_y0 =  floor((float)priv->map_y / (float)(TILESIZE*2));
1093    
1094      //TODO: implement wrap around          for (i=tile_x0; i<(tile_x0+tiles_nx);i++)
     for (i=tile_x0; i<(tile_x0+tiles_nx);i++)  
     {  
         for (j=tile_y0;  j<(tile_y0+tiles_ny); j++)  
1095          {          {
1096              if( j<0 || i<0 || i>=exp(priv->map_zoom * M_LN2) || j>=exp(priv->map_zoom * M_LN2))              for (j=tile_y0;  j<(tile_y0+tiles_ny); j++)
1097              {              {
1098                  gdk_draw_rectangle (priv->pixmap,                  if( j<0 || i<0 || i>=exp(priv->map_zoom * M_LN2) || j>=exp(priv->map_zoom * M_LN2))
1099                                      GTK_WIDGET(map)->style->white_gc,                  {
1100                                      TRUE,                      gdk_draw_rectangle (priv->pixmap,
1101                                      offset_xn, offset_yn,                                          GTK_WIDGET(map)->style->white_gc,
1102                                      TILESIZE,TILESIZE);                                          TRUE,
1103                                            offset_xn, offset_yn,
1104                                            TILESIZE*2, TILESIZE*2);
1105                    }
1106                    else
1107                    {
1108                        osm_gps_map_load_tile(map,
1109                                              priv->map_zoom - 1,
1110                                              i,j,
1111                                              offset_xn,offset_yn);
1112                    }
1113                    offset_yn += TILESIZE*2;
1114              }              }
1115              else              offset_xn += TILESIZE*2;
1116                offset_yn = offset_y + EXTRA_BORDER;
1117            }
1118        }
1119        else
1120        {
1121            offset_x = - priv->map_x % TILESIZE;
1122            offset_y = - priv->map_y % TILESIZE;
1123            if (offset_x > 0) offset_x -= TILESIZE;
1124            if (offset_y > 0) offset_y -= TILESIZE;
1125    
1126            offset_xn = offset_x + EXTRA_BORDER;
1127            offset_yn = offset_y + EXTRA_BORDER;
1128    
1129            width  = GTK_WIDGET(map)->allocation.width;
1130            height = GTK_WIDGET(map)->allocation.height;
1131    
1132            tiles_nx = (width  - offset_x) / TILESIZE + 1;
1133            tiles_ny = (height - offset_y) / TILESIZE + 1;
1134    
1135            tile_x0 =  floor((float)priv->map_x / (float)TILESIZE);
1136            tile_y0 =  floor((float)priv->map_y / (float)TILESIZE);
1137    
1138            //TODO: implement wrap around
1139            for (i=tile_x0; i<(tile_x0+tiles_nx);i++)
1140            {
1141                for (j=tile_y0;  j<(tile_y0+tiles_ny); j++)
1142              {              {
1143                  osm_gps_map_load_tile(map,                  if( j<0 || i<0 || i>=exp(priv->map_zoom * M_LN2) || j>=exp(priv->map_zoom * M_LN2))
1144                                        priv->map_zoom,                  {
1145                                        i,j,                      gdk_draw_rectangle (priv->pixmap,
1146                                        offset_xn,offset_yn);                                          GTK_WIDGET(map)->style->white_gc,
1147                                            TRUE,
1148                                            offset_xn, offset_yn,
1149                                            TILESIZE,TILESIZE);
1150                    }
1151                    else
1152                    {
1153                        osm_gps_map_load_tile(map,
1154                                              priv->map_zoom,
1155                                              i,j,
1156                                              offset_xn,offset_yn);
1157                    }
1158                    offset_yn += TILESIZE;
1159              }              }
1160              offset_yn += TILESIZE;              offset_xn += TILESIZE;
1161                offset_yn = offset_y + EXTRA_BORDER;
1162          }          }
         offset_xn += TILESIZE;  
         offset_yn = offset_y + EXTRA_BORDER;  
1163      }      }
1164  }  }
1165    
# Line 1313  osm_gps_map_print_track (OsmGpsMap *map, Line 1173  osm_gps_map_print_track (OsmGpsMap *map,
1173      int min_x = 0,min_y = 0,max_x = 0,max_y = 0;      int min_x = 0,min_y = 0,max_x = 0,max_y = 0;
1174      int lw = priv->ui_gps_track_width;      int lw = priv->ui_gps_track_width;
1175      int map_x0, map_y0;      int map_x0, map_y0;
 #ifdef USE_CAIRO  
1176      cairo_t *cr;      cairo_t *cr;
 #else  
     int last_x = 0, last_y = 0;  
     GdkColor color;  
     GdkGC *gc;  
 #endif  
1177    
 #ifdef USE_CAIRO  
1178      cr = gdk_cairo_create(priv->pixmap);      cr = gdk_cairo_create(priv->pixmap);
1179      cairo_set_line_width (cr, lw);      cairo_set_line_width (cr, lw);
1180      cairo_set_source_rgba (cr, 60000.0/65535.0, 0.0, 0.0, 0.6);      cairo_set_source_rgba (cr, 60000.0/65535.0, 0.0, 0.0, 0.6);
1181      cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);      cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
1182      cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);      cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
 #else  
     gc = gdk_gc_new(priv->pixmap);  
     color.green = 0;  
     color.blue = 0;  
     color.red = 60000;  
     gdk_gc_set_rgb_fg_color(gc, &color);  
     gdk_gc_set_line_attributes(gc, lw, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);  
 #endif  
1183    
1184      map_x0 = priv->map_x - EXTRA_BORDER;      map_x0 = priv->map_x - EXTRA_BORDER;
1185      map_y0 = priv->map_y - EXTRA_BORDER;      map_y0 = priv->map_y - EXTRA_BORDER;
# Line 1347  osm_gps_map_print_track (OsmGpsMap *map, Line 1192  osm_gps_map_print_track (OsmGpsMap *map,
1192    
1193          // first time through loop          // first time through loop
1194          if (list == trackpoint_list) {          if (list == trackpoint_list) {
 #ifdef USE_CAIRO  
1195              cairo_move_to(cr, x, y);              cairo_move_to(cr, x, y);
 #else  
             last_x = x;  
             last_y = y;  
 #endif  
1196          }          }
1197    
 #ifdef USE_CAIRO  
1198          cairo_line_to(cr, x, y);          cairo_line_to(cr, x, y);
 #else  
         gdk_draw_line (priv->pixmap, gc, x, y, last_x, last_y);  
         last_x = x;  
         last_y = y;  
 #endif  
1199    
1200          max_x = MAX(x,max_x);          max_x = MAX(x,max_x);
1201          min_x = MIN(x,min_x);          min_x = MIN(x,min_x);
# Line 1376  osm_gps_map_print_track (OsmGpsMap *map, Line 1210  osm_gps_map_print_track (OsmGpsMap *map,
1210                                  max_x + (lw * 2),                                  max_x + (lw * 2),
1211                                  max_y + (lw * 2));                                  max_y + (lw * 2));
1212    
 #ifdef USE_CAIRO  
1213      cairo_stroke(cr);      cairo_stroke(cr);
1214      cairo_destroy(cr);      cairo_destroy(cr);
 #else  
     g_object_unref(gc);  
 #endif  
1215  }  }
1216    
1217  /* Prints the gps trip history, and any other tracks */  /* Prints the gps trip history, and any other tracks */
# Line 1423  osm_gps_map_purge_cache (OsmGpsMap *map) Line 1253  osm_gps_map_purge_cache (OsmGpsMap *map)
1253     g_hash_table_foreach_remove(priv->tile_cache, osm_gps_map_purge_cache_check, priv);     g_hash_table_foreach_remove(priv->tile_cache, osm_gps_map_purge_cache_check, priv);
1254  }  }
1255    
 #ifdef ENABLE_OSD  
 /* position and extent of bounding box */  
 #define OSD_X      (10)  
 #define OSD_Y      (10)  
   
 #define OSD_COLOR            0.5, 0.5, 1  
 #define OSD_COLOR_DISABLED   0.8, 0.8, 0.8  
   
 /* parameters of the direction shape */  
 #ifndef OSM_GPS_MAP_OSD_DIAMETER  
 #define D_RAD  (30)         // diameter of dpad  
 #else  
 #define D_RAD  (OSM_GPS_MAP_OSD_DIAMETER)  
 #endif  
 #define D_TIP  (4*D_RAD/5)  // distance of arrow tip from dpad center  
 #define D_LEN  (D_RAD/4)    // length of arrow  
 #define D_WID  (D_LEN)      // width of arrow  
   
 /* parameters of the "zoom" pad */  
 #define Z_STEP   (D_RAD/4)  // distance between dpad and zoom  
 #define Z_RAD    (D_RAD/2)  // radius of "caps" of zoom bar  
   
 /* shadow also depends on control size */  
 #define OSD_SHADOW (D_RAD/6)  
   
 /* total width and height of controls incl. shadow */  
 #define OSD_W    (2*D_RAD + OSD_SHADOW)  
 #define OSD_H    (2*D_RAD + Z_STEP + 2*Z_RAD + OSD_SHADOW)  
   
 #define OSD_LBL_SHADOW (OSD_SHADOW/2)  
   
 #define Z_TOP    (2 * D_RAD + Z_STEP)  
 #define Z_MID    (Z_TOP + Z_RAD)  
 #define Z_BOT    (Z_MID + Z_RAD)  
 #define Z_LEFT   (Z_RAD)  
 #define Z_RIGHT  (2 * D_RAD - Z_RAD)  
   
 /* create the cairo shape used for the zoom buttons */  
 static void  
 osm_gps_map_osd_zoom_shape(cairo_t *cr, gint x, gint y) {  
     cairo_move_to (cr, x+Z_LEFT,    y+Z_TOP);  
     cairo_line_to (cr, x+Z_RIGHT,   y+Z_TOP);  
     cairo_arc     (cr, x+Z_RIGHT,   y+Z_MID, Z_RAD, -M_PI/2,  M_PI/2);  
     cairo_line_to (cr, x+Z_LEFT,    y+Z_BOT);  
     cairo_arc     (cr, x+Z_LEFT,    y+Z_MID, Z_RAD,  M_PI/2, -M_PI/2);  
 }  
   
 /* create the cairo shape used for the dpad */  
 static void  
 osm_gps_map_osd_dpad_shape(cairo_t *cr, gint x, gint y) {  
     cairo_arc (cr, x+D_RAD, y+D_RAD, D_RAD, 0, 2 * M_PI);  
 }  
   
 typedef enum {  
     OSD_NONE = 0,  
     OSD_BG,  
     OSD_UP,  
     OSD_DOWN,  
     OSD_LEFT,  
     OSD_RIGHT,  
     OSD_IN,  
     OSD_OUT,  
     OSD_GPS  
 } osd_button_t;  
   
1256  static gboolean  static gboolean
1257  osm_gps_map_in_circle(gint x, gint y, gint cx, gint cy, gint rad)  osm_gps_map_map_redraw (OsmGpsMap *map)
 {  
     return( pow(cx - x, 2) + pow(cy - y, 2) < rad * rad);  
 }  
   
 /* check whether x/y is within the dpad */  
 static osd_button_t  
 osm_gps_map_osd_check_dpad(gint x, gint y)  
 {  
     /* within entire dpad circle */  
     if( osm_gps_map_in_circle(x, y, OSD_X + D_RAD, OSD_Y + D_RAD, D_RAD))  
     {  
         /* convert into position relative to dpads centre */  
         x -= (OSD_X + D_RAD);  
         y -= (OSD_Y + D_RAD);  
   
         /* check for dpad center goes here! */  
         if( osm_gps_map_in_circle(x, y, 0, 0, D_RAD/3))  
             return OSD_GPS;  
   
         if( y < 0 && abs(x) < abs(y))  
             return OSD_UP;  
   
         if( y > 0 && abs(x) < abs(y))  
             return OSD_DOWN;  
   
         if( x < 0 && abs(y) < abs(x))  
             return OSD_LEFT;  
   
         if( x > 0 && abs(y) < abs(x))  
             return OSD_RIGHT;  
   
         return OSD_BG;  
     }  
     return OSD_NONE;  
 }  
   
 /* check whether x/y is within the zoom pads */  
 static osd_button_t  
 osm_gps_map_osd_check_zoom(gint x, gint y) {  
     if( x > OSD_X && x < (OSD_X + OSD_W) && y > Z_TOP && y < (OSD_Y+Z_BOT)) {  
   
         /* within circle around (-) label */  
         if( osm_gps_map_in_circle(x, y, OSD_X + Z_LEFT, OSD_Y + Z_MID, Z_RAD))  
             return OSD_OUT;  
   
         /* between center of (-) button and center of entire zoom control area */  
         if(x > OSD_LEFT && x < OSD_X + D_RAD)  
             return OSD_OUT;  
   
         /* within circle around (+) label */  
         if( osm_gps_map_in_circle(x, y, OSD_X + Z_RIGHT, OSD_Y + Z_MID, Z_RAD))  
             return OSD_IN;  
   
         /* between center of (+) button and center of entire zoom control area */  
         if(x < OSD_RIGHT && x > OSD_X + D_RAD)  
             return OSD_IN;  
     }  
   
     return OSD_NONE;  
 }  
   
 static osd_button_t  
 osm_gps_map_osd_check(gint x, gint y) {  
     osd_button_t but = OSD_NONE;  
   
     /* first do a rough test for the OSD area. */  
     /* this is just to avoid an unnecessary detailed test */  
     if(x > OSD_X && x < OSD_X + OSD_W &&  
        y > OSD_Y && y < OSD_Y + OSD_H) {  
         but = osm_gps_map_osd_check_dpad(x, y);  
   
         if(but == OSD_NONE)  
             but = osm_gps_map_osd_check_zoom(x, y);  
     }  
   
     return but;  
 }  
   
 static void  
 osm_gps_map_osd_shape_shadow(cairo_t *cr) {  
     cairo_set_source_rgba (cr, 0, 0, 0, 0.2);  
     cairo_fill (cr);  
     cairo_stroke (cr);  
 }  
   
 static void  
 osm_gps_map_osd_shape(cairo_t *cr) {  
     cairo_set_source_rgb (cr, 1, 1, 1);  
     cairo_fill_preserve (cr);  
     cairo_set_source_rgb (cr, OSD_COLOR);  
     cairo_set_line_width (cr, 1);  
     cairo_stroke (cr);  
 }  
   
 static void  
 osm_gps_map_osd_dpad_labels(cairo_t *cr, gint x, gint y) {  
     /* move reference to dpad center */  
     x += D_RAD;  
     y += D_RAD;  
   
     const static gint offset[][3][2] = {  
         /* left arrow/triangle */  
         { { -D_TIP+D_LEN, -D_WID }, { -D_LEN, D_WID }, { +D_LEN, D_WID } },  
         /* right arrow/triangle */  
         { { +D_TIP-D_LEN, -D_WID }, { +D_LEN, D_WID }, { -D_LEN, D_WID } },  
         /* top arrow/triangle */  
         { { -D_WID, -D_TIP+D_LEN }, { D_WID, -D_LEN }, { D_WID, +D_LEN } },  
         /* bottom arrow/triangle */  
         { { -D_WID, +D_TIP-D_LEN }, { D_WID, +D_LEN }, { D_WID, -D_LEN } }  
     };  
   
     int i;  
     for(i=0;i<4;i++) {  
         cairo_move_to (cr, x + offset[i][0][0], y + offset[i][0][1]);  
         cairo_rel_line_to (cr, offset[i][1][0], offset[i][1][1]);  
         cairo_rel_line_to (cr, offset[i][2][0], offset[i][2][1]);  
     }  
 }  
   
 /* draw the sattelite dish icon in the center of the dpad */  
 #define GPS_V0  (D_RAD/8)  
 #define GPS_V1  (D_RAD/10)  
 #define GPS_V2  (D_RAD/5)  
   
 /* draw a satellite receiver dish */  
 static void  
 osm_gps_map_osd_dpad_gps(cairo_t *cr, gint x, gint y) {  
     /* move reference to dpad center */  
     x += D_RAD;  
     y += D_RAD + GPS_V0;  
   
     cairo_move_to (cr, x-GPS_V0, y+GPS_V0);  
     cairo_rel_line_to (cr, +GPS_V0, -GPS_V0);  
     cairo_rel_line_to (cr, +GPS_V0, +GPS_V0);  
     cairo_close_path (cr);  
   
     cairo_move_to (cr, x+GPS_V1-GPS_V2, y-2*GPS_V2);  
     cairo_curve_to (cr, x-GPS_V2, y, x+GPS_V1, y+GPS_V1, x+GPS_V1+GPS_V2, y);  
     cairo_close_path (cr);  
   
     x += GPS_V1;  
     cairo_move_to (cr, x, y-GPS_V2);  
     cairo_rel_line_to (cr, +GPS_V1, -GPS_V1);  
 }  
   
 #define Z_LEN  (2*Z_RAD/3)  
   
 static void  
 osm_gps_map_osd_zoom_labels(cairo_t *cr, gint x, gint y) {  
     cairo_move_to (cr, x + Z_LEFT  - Z_LEN, y + Z_MID);  
     cairo_line_to (cr, x + Z_LEFT  + Z_LEN, y + Z_MID);  
   
     cairo_move_to (cr, x + Z_RIGHT,         y + Z_MID - Z_LEN);  
     cairo_line_to (cr, x + Z_RIGHT,         y + Z_MID + Z_LEN);  
     cairo_move_to (cr, x + Z_RIGHT - Z_LEN, y + Z_MID);  
     cairo_line_to (cr, x + Z_RIGHT + Z_LEN, y + Z_MID);  
 }  
   
 static void  
 osm_gps_map_osd_labels(cairo_t *cr, gint width, gboolean enabled) {  
     if(enabled)  cairo_set_source_rgb (cr, OSD_COLOR);  
     else         cairo_set_source_rgb (cr, OSD_COLOR_DISABLED);  
     cairo_set_line_width (cr, width);  
     cairo_stroke (cr);  
 }  
   
 static void  
 osm_gps_map_osd_labels_shadow(cairo_t *cr, gint width, gboolean enabled) {  
     cairo_set_source_rgba (cr, 0, 0, 0, enabled?0.3:0.15);  
     cairo_set_line_width (cr, width);  
     cairo_stroke (cr);  
 }  
   
 static void  
 osm_gps_map_osd_render(OsmGpsMapPrivate *priv) {  
   
     /* first fill with transparency */  
     cairo_t *cr = cairo_create(priv->osd.overlay);  
     cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);  
     cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.0);  
     cairo_paint(cr);  
   
     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);  
   
     /* --------- draw zoom and dpad shape shadow ----------- */  
     gint x = 0, y = 0;  
   
     osm_gps_map_osd_zoom_shape(cr, x + OSD_SHADOW, y + OSD_SHADOW);  
     osm_gps_map_osd_shape_shadow(cr);  
     osm_gps_map_osd_dpad_shape(cr, x + OSD_SHADOW, y + OSD_SHADOW);  
     osm_gps_map_osd_shape_shadow(cr);  
   
     /* --------- draw zoom and dpad shape ----------- */  
   
     osm_gps_map_osd_zoom_shape(cr, x, y);  
     osm_gps_map_osd_shape(cr);  
     osm_gps_map_osd_dpad_shape(cr, x, y);  
     osm_gps_map_osd_shape(cr);  
   
     /* --------- draw zoom and dpad labels --------- */  
   
     osm_gps_map_osd_zoom_labels(cr, x + OSD_LBL_SHADOW, y + OSD_LBL_SHADOW);  
     osm_gps_map_osd_dpad_labels(cr, x + OSD_LBL_SHADOW, y + OSD_LBL_SHADOW);  
     osm_gps_map_osd_labels_shadow(cr, Z_RAD/3, TRUE);  
     osm_gps_map_osd_dpad_gps(cr, x + OSD_LBL_SHADOW, y + OSD_LBL_SHADOW);  
     osm_gps_map_osd_labels_shadow(cr, Z_RAD/6, priv->osd.cb != NULL);  
   
     osm_gps_map_osd_zoom_labels(cr, x, y);  
     osm_gps_map_osd_dpad_labels(cr, x, y);  
     osm_gps_map_osd_labels(cr, Z_RAD/3, TRUE);  
     osm_gps_map_osd_dpad_gps(cr, x, y);  
     osm_gps_map_osd_labels(cr, Z_RAD/6, priv->osd.cb != NULL);  
   
     cairo_destroy(cr);  
 }  
   
 static void  
 osm_gps_map_osd_draw_controls (OsmGpsMap *map, gint xoffset, gint yoffset)  
1258  {  {
1259      OsmGpsMapPrivate *priv = map->priv;      OsmGpsMapPrivate *priv = map->priv;
1260    
1261      /* backup previous contents */      /* on diablo the map comes up at 1x1 pixel size and */
1262      if(!priv->osd.backup)      /* isn't really usable. we'll just ignore this ... */
1263          priv->osd.backup = gdk_pixmap_new(priv->pixmap, OSD_W+2, OSD_H+2, -1);      if((GTK_WIDGET(map)->allocation.width < 2) ||
1264           (GTK_WIDGET(map)->allocation.height < 2)) {
1265      gint x = OSD_X + EXTRA_BORDER + xoffset;          printf("not a useful sized map yet ...\n");
1266      gint y = OSD_Y + EXTRA_BORDER + yoffset;          return FALSE;
   
     /* create backup of background */  
     gdk_draw_drawable(priv->osd.backup,  
         GTK_WIDGET(map)->style->fg_gc[GTK_WIDGET_STATE(GTK_WIDGET(map))],  
                       priv->pixmap, x-1, y-1, 0, 0, OSD_W+2, OSD_H+2);  
   
     priv->osd.backup_x = x-1;  
     priv->osd.backup_y = y-1;  
   
   
 #ifdef USE_CAIRO  
     /* OSD itself uses some off-screen rendering, so check if the */  
     /* offscreen buffer is present and create it if not */  
     if(!priv->osd.overlay) {  
         /* create overlay ... */  
         priv->osd.overlay =  
             cairo_image_surface_create(CAIRO_FORMAT_ARGB32, OSD_W, OSD_H);  
         /* ... and render it */  
         osm_gps_map_osd_render(priv);  
1267      }      }
1268    
1269      // now draw this onto the original context      priv->idle_map_redraw = 0;
     cairo_t *cr = gdk_cairo_create(priv->pixmap);  
     cairo_set_source_surface(cr, priv->osd.overlay, x, y);  
     cairo_paint(cr);  
     cairo_destroy(cr);  
1270    
1271  #else  #ifdef ENABLE_OSD
1272  #warning "OSD control display lacks a non-cairo implementation!"      /* don't redraw the entire map while the OSD is doing */
1273        /* some animation or the like. This is to keep the animation */
1274        /* fluid */
1275        if (priv->osd->busy(priv->osd))
1276            return FALSE;
1277  #endif  #endif
 }  
   
 static void  
 osm_gps_map_osd_restore (OsmGpsMap *map)  
 {  
     OsmGpsMapPrivate *priv = map->priv;  
   
     /* restore backup of previous contents */  
     if(priv->osd.backup) {  
         /* create backup of background */  
         gdk_draw_drawable(priv->pixmap,  
             GTK_WIDGET(map)->style->fg_gc[GTK_WIDGET_STATE(GTK_WIDGET(map))],  
                       priv->osd.backup, 0, 0,  
                       priv->osd.backup_x, priv->osd.backup_y, OSD_W+2, OSD_H+2);  
     }  
 }  
1278    
1279    #ifdef DRAG_DEBUG
1280        printf("trying redraw\n");
1281  #endif  #endif
1282    
 static gboolean  
 osm_gps_map_map_redraw (OsmGpsMap *map)  
 {  
     OsmGpsMapPrivate *priv = map->priv;  
   
     priv->idle_map_redraw = 0;  
   
1283      /* the motion_notify handler uses priv->pixmap to redraw the area; if we      /* the motion_notify handler uses priv->pixmap to redraw the area; if we
1284       * change it while we are dragging, we will end up showing it in the wrong       * change it while we are dragging, we will end up showing it in the wrong
1285       * place. This could be fixed by carefully recompute the coordinates, but       * place. This could be fixed by carefully recompute the coordinates, but
# Line 1780  osm_gps_map_map_redraw (OsmGpsMap *map) Line 1287  osm_gps_map_map_redraw (OsmGpsMap *map)
1287      if (priv->dragging)      if (priv->dragging)
1288          return FALSE;          return FALSE;
1289    
1290        /* undo all offsets that may have happened when dragging */
1291        priv->drag_mouse_dx = 0;
1292        priv->drag_mouse_dy = 0;
1293    
1294      priv->redraw_cycle++;      priv->redraw_cycle++;
1295    
1296      /* draw white background to initialise pixmap */      /* draw white background to initialise pixmap */
1297      gdk_draw_rectangle (      gdk_draw_rectangle (priv->pixmap,
                         priv->pixmap,  
1298                          GTK_WIDGET(map)->style->white_gc,                          GTK_WIDGET(map)->style->white_gc,
1299                          TRUE,                          TRUE,
1300                          0, 0,                          0, 0,
# Line 1796  osm_gps_map_map_redraw (OsmGpsMap *map) Line 1306  osm_gps_map_map_redraw (OsmGpsMap *map)
1306      osm_gps_map_print_tracks(map);      osm_gps_map_print_tracks(map);
1307      osm_gps_map_draw_gps_point(map);      osm_gps_map_draw_gps_point(map);
1308      osm_gps_map_print_images(map);      osm_gps_map_print_images(map);
1309  #ifdef ENABLE_BALLOON  
     osm_gps_map_draw_balloon_int(map);  
 #endif  
1310  #ifdef ENABLE_OSD  #ifdef ENABLE_OSD
1311      osm_gps_map_osd_draw_controls(map, 0, 0);      /* OSD may contain a coordinate/scale, so we may have to re-render it */
1312        if(priv->osd && OSM_IS_GPS_MAP (priv->osd->widget))
1313            priv->osd->render (priv->osd);
1314  #endif  #endif
1315    
     //osm_gps_map_osd_speed(map, 1.5);  
1316      osm_gps_map_purge_cache(map);      osm_gps_map_purge_cache(map);
1317      gtk_widget_queue_draw (GTK_WIDGET (map));      gtk_widget_queue_draw (GTK_WIDGET (map));
1318    
# Line 1820  osm_gps_map_map_redraw_idle (OsmGpsMap * Line 1329  osm_gps_map_map_redraw_idle (OsmGpsMap *
1329  }  }
1330    
1331  static void  static void
1332  osm_gps_map_init (OsmGpsMap *object)  center_coord_update(OsmGpsMap *map) {
1333  {  
1334      OsmGpsMapPrivate *priv;      GtkWidget *widget = GTK_WIDGET(map);
1335        OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(map);
1336    
1337        // pixel_x,y, offsets
1338        gint pixel_x = priv->map_x + widget->allocation.width/2;
1339        gint pixel_y = priv->map_y + widget->allocation.height/2;
1340    
1341        priv->center_rlon = pixel2lon(priv->map_zoom, pixel_x);
1342        priv->center_rlat = pixel2lat(priv->map_zoom, pixel_y);
1343    
1344        g_signal_emit_by_name(widget, "changed");
1345    }
1346    
1347    static gboolean
1348    on_window_key_press(GtkWidget *widget, GdkEventKey *event, OsmGpsMapPrivate *priv)
1349    {
1350        int i;
1351        int step;
1352        gboolean handled;
1353        OsmGpsMap *map;
1354    
1355        //if no keybindings are set, let the app handle them...
1356        if (!priv->keybindings_enabled)
1357            return FALSE;
1358    
1359        handled = FALSE;
1360        map = OSM_GPS_MAP(widget);
1361        step = GTK_WIDGET(widget)->allocation.width/OSM_GPS_MAP_SCROLL_STEP;
1362    
1363        //the map handles some keys on its own
1364        for (i = 0; i < OSM_GPS_MAP_KEY_MAX; i++) {
1365            //not the key we have a binding for
1366            if (map->priv->keybindings[i] != event->keyval)
1367                continue;
1368    
1369            switch(i) {
1370                case OSM_GPS_MAP_KEY_FULLSCREEN: {
1371                    GtkWidget *toplevel = gtk_widget_get_toplevel(GTK_WIDGET(widget));
1372                    if(!priv->fullscreen)
1373                        gtk_window_fullscreen(GTK_WINDOW(toplevel));
1374                    else
1375                        gtk_window_unfullscreen(GTK_WINDOW(toplevel));
1376    
1377                    priv->fullscreen = !priv->fullscreen;
1378                    handled = TRUE;
1379                    } break;
1380                case OSM_GPS_MAP_KEY_ZOOMIN:
1381                    osm_gps_map_zoom_in(map);
1382                    handled = TRUE;
1383                    break;
1384                case OSM_GPS_MAP_KEY_ZOOMOUT:
1385                    osm_gps_map_zoom_out(map);
1386                    handled = TRUE;
1387                    break;
1388                case OSM_GPS_MAP_KEY_UP:
1389                    priv->map_y -= step;
1390                    center_coord_update(map);
1391                    osm_gps_map_map_redraw_idle(map);
1392                    handled = TRUE;
1393                    break;
1394                case OSM_GPS_MAP_KEY_DOWN:
1395                    priv->map_y += step;
1396                    center_coord_update(map);
1397                    osm_gps_map_map_redraw_idle(map);
1398                    handled = TRUE;
1399                    break;
1400                  case OSM_GPS_MAP_KEY_LEFT:
1401                    priv->map_x -= step;
1402                    center_coord_update(map);
1403                    osm_gps_map_map_redraw_idle(map);
1404                    handled = TRUE;
1405                    break;
1406                case OSM_GPS_MAP_KEY_RIGHT:
1407                    priv->map_x += step;
1408                    center_coord_update(map);
1409                    osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));
1410                    handled = TRUE;
1411                    break;
1412                default:
1413                    break;
1414            }
1415        }
1416    
1417        return handled;
1418    }
1419    
1420    static void
1421    osm_gps_map_init (OsmGpsMap *object)
1422    {
1423        int i;
1424        OsmGpsMapPrivate *priv;
1425    
1426      priv = G_TYPE_INSTANCE_GET_PRIVATE (object, OSM_TYPE_GPS_MAP, OsmGpsMapPrivate);      priv = G_TYPE_INSTANCE_GET_PRIVATE (object, OSM_TYPE_GPS_MAP, OsmGpsMapPrivate);
1427      object->priv = priv;      object->priv = priv;
# Line 1832  osm_gps_map_init (OsmGpsMap *object) Line 1431  osm_gps_map_init (OsmGpsMap *object)
1431      priv->trip_history = NULL;      priv->trip_history = NULL;
1432      priv->gps = g_new0(coord_t, 1);      priv->gps = g_new0(coord_t, 1);
1433      priv->gps_valid = FALSE;      priv->gps_valid = FALSE;
1434        priv->gps_heading = OSM_GPS_MAP_INVALID;
 #ifdef ENABLE_BALLOON  
     priv->balloon.coo = g_new0(coord_t, 1);  
     priv->balloon.valid = FALSE;  
     priv->balloon.cb = NULL;  
 #endif  
1435    
1436  #ifdef ENABLE_OSD  #ifdef ENABLE_OSD
1437      priv->osd.backup = NULL;      priv->osd = NULL;
     priv->osd.overlay = NULL;  
     priv->osd.cb = NULL;  
1438  #endif  #endif
   
1439      priv->tracks = NULL;      priv->tracks = NULL;
1440      priv->images = NULL;      priv->images = NULL;
1441    
# Line 1859  osm_gps_map_init (OsmGpsMap *object) Line 1450  osm_gps_map_init (OsmGpsMap *object)
1450    
1451      priv->map_source = -1;      priv->map_source = -1;
1452    
1453  #ifndef LIBSOUP22      priv->keybindings_enabled = FALSE;
1454      //Change naumber of concurrent connections option?      for (i = 0; i < OSM_GPS_MAP_KEY_MAX; i++)
1455      priv->soup_session = soup_session_async_new_with_options(          priv->keybindings[i] = 0;
1456                                                               SOUP_SESSION_USER_AGENT,  
1457                                                               "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11",  
1458                                                               NULL);  #if USE_LIBSOUP22
1459  #else      /* libsoup-2.2 has no special way to set the user agent, so we */
1460      /* libsoup-2.2 seems not to be able to set the user agent */      /* set it seperately as an extra header field for each reuest */
1461      priv->soup_session = soup_session_async_new();      priv->soup_session = soup_session_async_new();
1462  #endif  #else
1463        /* set the user agent */
1464        priv->soup_session =
1465            soup_session_async_new_with_options(SOUP_SESSION_USER_AGENT,
1466                                                USER_AGENT, NULL);
1467    
1468    #endif
1469      //Hash table which maps tile d/l URIs to SoupMessage requests      //Hash table which maps tile d/l URIs to SoupMessage requests
1470      priv->tile_queue = g_hash_table_new (g_str_hash, g_str_equal);      priv->tile_queue = g_hash_table_new (g_str_hash, g_str_equal);
1471    
# Line 1889  osm_gps_map_init (OsmGpsMap *object) Line 1485  osm_gps_map_init (OsmGpsMap *object)
1485      GTK_WIDGET_SET_FLAGS (object, GTK_CAN_FOCUS);      GTK_WIDGET_SET_FLAGS (object, GTK_CAN_FOCUS);
1486    
1487      g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MASK, my_log_handler, NULL);      g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MASK, my_log_handler, NULL);
1488    
1489        //Setup signal handlers
1490        g_signal_connect(G_OBJECT(object), "key_press_event",
1491                                G_CALLBACK(on_window_key_press), priv);
1492  }  }
1493    
1494  #ifndef G_CHECKSUM_MD5  static char*
1495  /* simple hash algorithm hack if md5 is not present */  osm_gps_map_get_cache_dir(OsmGpsMapPrivate *priv)
1496  static char *simple_hash(char *str) {  {
1497      union {      if (priv->tile_base_dir)
1498          char str[4];          return g_strdup(priv->tile_base_dir);
1499          gulong val;      return osm_gps_map_get_default_cache_directory();
1500      } hash = { .val = 0x55555555 };  }
1501    
1502      while(*str) {  /* strcmp0 was introduced with glib 2.16 */
1503          hash.str[(int)str & 3] ^= *str;  #if ! GLIB_CHECK_VERSION (2, 16, 0)
1504          str++;  int g_strcmp0(const char *str1, const char *str2)
1505      }  {
1506      return g_strdup_printf("%08lX", hash.val);      if( str1 == NULL && str2 == NULL ) return 0;
1507        if( str1 == NULL ) return -1;
1508        if( str2 == NULL ) return 1;
1509        return strcmp(str1, str2);
1510  }  }
1511  #endif  #endif
1512    
1513  static GObject *  static void
1514  osm_gps_map_constructor (GType gtype, guint n_properties, GObjectConstructParam *properties)  osm_gps_map_setup(OsmGpsMapPrivate *priv)
1515  {  {
     GObject *object;  
     OsmGpsMapPrivate *priv;  
     OsmGpsMap *map;  
1516      const char *uri;      const char *uri;
1517    
1518      //Always chain up to the parent constructor     //user can specify a map source ID, or a repo URI as the map source
     object = G_OBJECT_CLASS(osm_gps_map_parent_class)->constructor(gtype, n_properties, properties);  
     map = OSM_GPS_MAP(object);  
     priv = OSM_GPS_MAP_PRIVATE(object);  
   
     //user can specify a map source ID, or a repo URI as the map source  
1519      uri = osm_gps_map_source_get_repo_uri(OSM_GPS_MAP_SOURCE_NULL);      uri = osm_gps_map_source_get_repo_uri(OSM_GPS_MAP_SOURCE_NULL);
1520      if ( (priv->map_source == 0) || (strcmp(priv->repo_uri, uri) == 0) ) {      if ( (priv->map_source == 0) || (strcmp(priv->repo_uri, uri) == 0) ) {
1521          g_debug("Using null source");          g_debug("Using null source");
# Line 1944  osm_gps_map_constructor (GType gtype, gu Line 1539  osm_gps_map_constructor (GType gtype, gu
1539          }          }
1540      }      }
1541    
1542      if (!priv->cache_dir_is_full_path) {      if (priv->tile_dir == NULL)
1543  #ifdef G_CHECKSUM_MD5          priv->tile_dir = g_strdup(OSM_GPS_MAP_CACHE_DISABLED);
1544    
1545        if ( g_strcmp0(priv->tile_dir, OSM_GPS_MAP_CACHE_DISABLED) == 0 ) {
1546            priv->cache_dir = NULL;
1547        } else if ( g_strcmp0(priv->tile_dir, OSM_GPS_MAP_CACHE_AUTO) == 0 ) {
1548            char *base = osm_gps_map_get_cache_dir(priv);
1549    #if GLIB_CHECK_VERSION (2, 16, 0)
1550          char *md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, priv->repo_uri, -1);          char *md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, priv->repo_uri, -1);
1551  #else  #else
1552          char *md5 = simple_hash(priv->repo_uri);          char *md5 = g_strdup(osm_gps_map_source_get_friendly_name(priv->map_source));
1553  #endif  #endif
1554            priv->cache_dir = g_strdup_printf("%s%c%s", base, G_DIR_SEPARATOR, md5);
1555          if (priv->cache_dir) {          g_free(base);
             char *old = priv->cache_dir;  
             //the new cachedir is the given cache dir + the md5 of the repo_uri  
             priv->cache_dir = g_strdup_printf("%s%c%s", old, G_DIR_SEPARATOR, md5);  
             g_debug("Adjusting cache dir %s -> %s", old, priv->cache_dir);  
             g_free(old);  
         } else {  
             //the new cachedir is the current dir + the md5 of the repo_uri  
             priv->cache_dir = g_strdup(md5);  
         }  
   
1556          g_free(md5);          g_free(md5);
1557        } else if ( g_strcmp0(priv->tile_dir, OSM_GPS_MAP_CACHE_FRIENDLY) == 0 ) {
1558            char *base = osm_gps_map_get_cache_dir(priv);
1559            const char *fname = osm_gps_map_source_get_friendly_name(priv->map_source);
1560            priv->cache_dir = g_strdup_printf("%s%c%s", base, G_DIR_SEPARATOR, fname);
1561            g_free(base);
1562        } else {
1563            priv->cache_dir = g_strdup(priv->tile_dir);
1564      }      }
1565        g_debug("Cache dir: %s", priv->cache_dir);
1566    }
1567    
1568      inspect_map_uri(map);  static GObject *
1569    osm_gps_map_constructor (GType gtype, guint n_properties, GObjectConstructParam *properties)
1570    {
1571        //Always chain up to the parent constructor
1572        GObject *object =
1573            G_OBJECT_CLASS(osm_gps_map_parent_class)->constructor(gtype, n_properties, properties);
1574    
1575        osm_gps_map_setup(OSM_GPS_MAP_PRIVATE(object));
1576    
1577        inspect_map_uri(OSM_GPS_MAP(object));
1578    
1579      return object;      return object;
1580  }  }
# Line 1988  osm_gps_map_dispose (GObject *object) Line 1597  osm_gps_map_dispose (GObject *object)
1597      g_hash_table_destroy(priv->missing_tiles);      g_hash_table_destroy(priv->missing_tiles);
1598      g_hash_table_destroy(priv->tile_cache);      g_hash_table_destroy(priv->tile_cache);
1599    
1600        /* images and layers contain GObjects which need unreffing, so free here */
1601      osm_gps_map_free_images(map);      osm_gps_map_free_images(map);
1602    
1603      if(priv->pixmap)      if(priv->pixmap)
# Line 2002  osm_gps_map_dispose (GObject *object) Line 1612  osm_gps_map_dispose (GObject *object)
1612      if (priv->idle_map_redraw != 0)      if (priv->idle_map_redraw != 0)
1613          g_source_remove (priv->idle_map_redraw);          g_source_remove (priv->idle_map_redraw);
1614    
1615      g_free(priv->gps);      if (priv->drag_expose != 0)
1616            g_source_remove (priv->drag_expose);
1617    
1618  #ifdef ENABLE_BALLOON      g_free(priv->gps);
     g_free(priv->balloon.coo);  
 #endif  
1619    
1620  #ifdef ENABLE_OSD  #ifdef ENABLE_OSD
1621      if (priv->osd.backup)      if(priv->osd) {
1622          g_object_unref(priv->osd.backup);          priv->osd->free(priv->osd);
1623            priv->osd = NULL;
1624        }
1625    
1626      if (priv->osd.overlay)  #ifdef OSD_DOUBLE_BUFFER
1627           cairo_surface_destroy(priv->osd.overlay);      if(priv->dbuf_pixmap)
1628            g_object_unref (priv->dbuf_pixmap);
1629    #endif
1630  #endif  #endif
1631    
1632      G_OBJECT_CLASS (osm_gps_map_parent_class)->dispose (object);      G_OBJECT_CLASS (osm_gps_map_parent_class)->dispose (object);
# Line 2025  osm_gps_map_finalize (GObject *object) Line 1638  osm_gps_map_finalize (GObject *object)
1638      OsmGpsMap *map = OSM_GPS_MAP(object);      OsmGpsMap *map = OSM_GPS_MAP(object);
1639      OsmGpsMapPrivate *priv = map->priv;      OsmGpsMapPrivate *priv = map->priv;
1640    
1641      g_free(priv->cache_dir);      if (priv->tile_dir)
1642            g_free(priv->tile_dir);
1643    
1644        if (priv->cache_dir)
1645            g_free(priv->cache_dir);
1646    
1647      g_free(priv->repo_uri);      g_free(priv->repo_uri);
1648      g_free(priv->image_format);      g_free(priv->image_format);
1649    
1650        /* trip and tracks contain simple non GObject types, so free them here */
1651      osm_gps_map_free_trip(map);      osm_gps_map_free_trip(map);
1652      osm_gps_map_free_tracks(map);      osm_gps_map_free_tracks(map);
1653    
# Line 2047  osm_gps_map_set_property (GObject *objec Line 1666  osm_gps_map_set_property (GObject *objec
1666          case PROP_AUTO_CENTER:          case PROP_AUTO_CENTER:
1667              priv->map_auto_center = g_value_get_boolean (value);              priv->map_auto_center = g_value_get_boolean (value);
1668              break;              break;
1669            case PROP_DOUBLE_PIXEL:
1670                priv->double_pixel = g_value_get_boolean (value);
1671                osm_gps_map_map_redraw_idle(map);
1672                break;
1673          case PROP_RECORD_TRIP_HISTORY:          case PROP_RECORD_TRIP_HISTORY:
1674              priv->record_trip_history = g_value_get_boolean (value);              priv->record_trip_history = g_value_get_boolean (value);
1675              break;              break;
# Line 2064  osm_gps_map_set_property (GObject *objec Line 1687  osm_gps_map_set_property (GObject *objec
1687                  priv->proxy_uri = g_value_dup_string (value);                  priv->proxy_uri = g_value_dup_string (value);
1688                  g_debug("Setting proxy server: %s", priv->proxy_uri);                  g_debug("Setting proxy server: %s", priv->proxy_uri);
1689    
1690  #ifndef LIBSOUP22  #if USE_LIBSOUP22
1691                    SoupUri* uri = soup_uri_new(priv->proxy_uri);
1692                    g_object_set(G_OBJECT(priv->soup_session), SOUP_SESSION_PROXY_URI, uri, NULL);
1693    #else
1694                  GValue val = {0};                  GValue val = {0};
   
1695                  SoupURI* uri = soup_uri_new(priv->proxy_uri);                  SoupURI* uri = soup_uri_new(priv->proxy_uri);
1696                  g_value_init(&val, SOUP_TYPE_URI);                  g_value_init(&val, SOUP_TYPE_URI);
1697                  g_value_take_boxed(&val, uri);                  g_value_take_boxed(&val, uri);
   
1698                  g_object_set_property(G_OBJECT(priv->soup_session),SOUP_SESSION_PROXY_URI,&val);                  g_object_set_property(G_OBJECT(priv->soup_session),SOUP_SESSION_PROXY_URI,&val);
 #else  
                 SoupUri* uri = soup_uri_new(priv->proxy_uri);  
                 g_object_set(G_OBJECT(priv->soup_session), SOUP_SESSION_PROXY_URI, uri, NULL);  
1699  #endif  #endif
1700              } else              } else
1701                  priv->proxy_uri = NULL;                  priv->proxy_uri = NULL;
1702    
1703              break;              break;
1704          case PROP_TILE_CACHE_DIR:          case PROP_TILE_CACHE_DIR:
1705              if ( g_value_get_string(value) )              priv->tile_dir = g_value_dup_string (value);
                 priv->cache_dir = g_value_dup_string (value);  
1706              break;              break;
1707          case PROP_TILE_CACHE_DIR_IS_FULL_PATH:          case PROP_TILE_CACHE_BASE_DIR:
1708              priv->cache_dir_is_full_path = g_value_get_boolean (value);              priv->tile_base_dir = g_value_dup_string (value);
1709              break;              break;
1710            case PROP_TILE_CACHE_DIR_IS_FULL_PATH:
1711                 g_warning("GObject property tile-cache-is-full-path depreciated");
1712                 break;
1713          case PROP_ZOOM:          case PROP_ZOOM:
1714              priv->map_zoom = g_value_get_int (value);              priv->map_zoom = g_value_get_int (value);
1715              break;              break;
# Line 2098  osm_gps_map_set_property (GObject *objec Line 1721  osm_gps_map_set_property (GObject *objec
1721              break;              break;
1722          case PROP_MAP_X:          case PROP_MAP_X:
1723              priv->map_x = g_value_get_int (value);              priv->map_x = g_value_get_int (value);
1724              priv->center_coord_set = FALSE;              center_coord_update(map);
1725              break;              break;
1726          case PROP_MAP_Y:          case PROP_MAP_Y:
1727              priv->map_y = g_value_get_int (value);              priv->map_y = g_value_get_int (value);
1728              priv->center_coord_set = FALSE;              center_coord_update(map);
1729              break;              break;
1730          case PROP_GPS_TRACK_WIDTH:          case PROP_GPS_TRACK_WIDTH:
1731              priv->ui_gps_track_width = g_value_get_int (value);              priv->ui_gps_track_width = g_value_get_int (value);
# Line 2113  osm_gps_map_set_property (GObject *objec Line 1736  osm_gps_map_set_property (GObject *objec
1736          case PROP_GPS_POINT_R2:          case PROP_GPS_POINT_R2:
1737              priv->ui_gps_point_outer_radius = g_value_get_int (value);              priv->ui_gps_point_outer_radius = g_value_get_int (value);
1738              break;              break;
1739          case PROP_MAP_SOURCE:          case PROP_MAP_SOURCE: {
1740                gint old = priv->map_source;
1741              priv->map_source = g_value_get_int (value);              priv->map_source = g_value_get_int (value);
1742              break;              if(old >= OSM_GPS_MAP_SOURCE_NULL &&
1743                   priv->map_source != old &&
1744                   priv->map_source >= OSM_GPS_MAP_SOURCE_NULL &&
1745                   priv->map_source <= OSM_GPS_MAP_SOURCE_LAST) {
1746    
1747                    /* we now have to switch the entire map */
1748    
1749                    /* flush the ram cache */
1750                    g_hash_table_remove_all(priv->tile_cache);
1751    
1752                    osm_gps_map_setup(priv);
1753    
1754                    inspect_map_uri(map);
1755    
1756                    /* adjust zoom if necessary */
1757                    if(priv->map_zoom > priv->max_zoom)
1758                        osm_gps_map_set_zoom(map, priv->max_zoom);
1759    
1760                    if(priv->map_zoom < priv->min_zoom)
1761                        osm_gps_map_set_zoom(map, priv->min_zoom);
1762    
1763                } } break;
1764          case PROP_IMAGE_FORMAT:          case PROP_IMAGE_FORMAT:
1765              priv->image_format = g_value_dup_string (value);              priv->image_format = g_value_dup_string (value);
1766              break;              break;
1767            case PROP_DRAG_LIMIT:
1768                priv->drag_limit = g_value_get_int (value);
1769                break;
1770          default:          default:
1771              G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);              G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1772              break;              break;
# Line 2129  static void Line 1777  static void
1777  osm_gps_map_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)  osm_gps_map_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
1778  {  {
1779      g_return_if_fail (OSM_IS_GPS_MAP (object));      g_return_if_fail (OSM_IS_GPS_MAP (object));
     float lat,lon;  
1780      OsmGpsMap *map = OSM_GPS_MAP(object);      OsmGpsMap *map = OSM_GPS_MAP(object);
1781      OsmGpsMapPrivate *priv = map->priv;      OsmGpsMapPrivate *priv = map->priv;
1782    
1783      switch (prop_id)      switch (prop_id)
1784      {      {
1785            case PROP_DOUBLE_PIXEL:
1786                g_value_set_boolean(value, priv->double_pixel);
1787                break;
1788          case PROP_AUTO_CENTER:          case PROP_AUTO_CENTER:
1789              g_value_set_boolean(value, priv->map_auto_center);              g_value_set_boolean(value, priv->map_auto_center);
1790              break;              break;
# Line 2156  osm_gps_map_get_property (GObject *objec Line 1806  osm_gps_map_get_property (GObject *objec
1806          case PROP_TILE_CACHE_DIR:          case PROP_TILE_CACHE_DIR:
1807              g_value_set_string(value, priv->cache_dir);              g_value_set_string(value, priv->cache_dir);
1808              break;              break;
1809            case PROP_TILE_CACHE_BASE_DIR:
1810                g_value_set_string(value, priv->tile_base_dir);
1811                break;
1812          case PROP_TILE_CACHE_DIR_IS_FULL_PATH:          case PROP_TILE_CACHE_DIR_IS_FULL_PATH:
1813              g_value_set_boolean(value, priv->cache_dir_is_full_path);              g_value_set_boolean(value, FALSE);
1814              break;              break;
1815          case PROP_ZOOM:          case PROP_ZOOM:
1816              g_value_set_int(value, priv->map_zoom);              g_value_set_int(value, priv->map_zoom);
# Line 2169  osm_gps_map_get_property (GObject *objec Line 1822  osm_gps_map_get_property (GObject *objec
1822              g_value_set_int(value, priv->min_zoom);              g_value_set_int(value, priv->min_zoom);
1823              break;              break;
1824          case PROP_LATITUDE:          case PROP_LATITUDE:
1825              lat = pixel2lat(priv->map_zoom,              g_value_set_float(value, rad2deg(priv->center_rlat));
                             priv->map_y + (GTK_WIDGET(map)->allocation.height / 2));  
             g_value_set_float(value, rad2deg(lat));  
1826              break;              break;
1827          case PROP_LONGITUDE:          case PROP_LONGITUDE:
1828              lon = pixel2lon(priv->map_zoom,              g_value_set_float(value, rad2deg(priv->center_rlon));
                             priv->map_x + (GTK_WIDGET(map)->allocation.width / 2));  
             g_value_set_float(value, rad2deg(lon));  
1829              break;              break;
1830          case PROP_MAP_X:          case PROP_MAP_X:
1831              g_value_set_int(value, priv->map_x);              g_value_set_int(value, priv->map_x);
# Line 2202  osm_gps_map_get_property (GObject *objec Line 1851  osm_gps_map_get_property (GObject *objec
1851          case PROP_IMAGE_FORMAT:          case PROP_IMAGE_FORMAT:
1852              g_value_set_string(value, priv->image_format);              g_value_set_string(value, priv->image_format);
1853              break;              break;
1854            case PROP_DRAG_LIMIT:
1855                g_value_set_int(value, priv->drag_limit);
1856                break;
1857          default:          default:
1858              G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);              G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1859              break;              break;
# Line 2212  static gboolean Line 1864  static gboolean
1864  osm_gps_map_scroll_event (GtkWidget *widget, GdkEventScroll  *event)  osm_gps_map_scroll_event (GtkWidget *widget, GdkEventScroll  *event)
1865  {  {
1866      OsmGpsMap *map = OSM_GPS_MAP(widget);      OsmGpsMap *map = OSM_GPS_MAP(widget);
     OsmGpsMapPrivate *priv = map->priv;  
1867    
1868      if (event->direction == GDK_SCROLL_UP)      if (event->direction == GDK_SCROLL_UP)
1869      {          osm_gps_map_zoom_in(map);
1870          osm_gps_map_set_zoom(map, priv->map_zoom+1);      else if (event->direction == GDK_SCROLL_DOWN)
1871      }          osm_gps_map_zoom_out(map);
     else  
     {  
         osm_gps_map_set_zoom(map, priv->map_zoom-1);  
     }  
1872    
1873      return FALSE;      return FALSE;
1874  }  }
# Line 2229  osm_gps_map_scroll_event (GtkWidget *wid Line 1876  osm_gps_map_scroll_event (GtkWidget *wid
1876  static gboolean  static gboolean
1877  osm_gps_map_button_press (GtkWidget *widget, GdkEventButton *event)  osm_gps_map_button_press (GtkWidget *widget, GdkEventButton *event)
1878  {  {
1879      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);      OsmGpsMap *map = OSM_GPS_MAP(widget);
1880        OsmGpsMapPrivate *priv = map->priv;
 #ifdef ENABLE_BALLOON  
     /* don't drag if the user clicked within the balloon */  
     if (osm_gps_map_in_balloon(priv,  
                    event->x + EXTRA_BORDER,  
                    event->y + EXTRA_BORDER))  
     {  
         priv->drag_counter = -1;  
         return FALSE;  
     }  
 #endif  
1881    
1882  #ifdef ENABLE_OSD  #ifdef ENABLE_OSD
     #define SCROLL_STEP 10  
   
1883      /* pressed inside OSD control? */      /* pressed inside OSD control? */
1884      osd_button_t but = osm_gps_map_osd_check(event->x, event->y);      if(priv->osd) {
1885      if(but != OSD_NONE)          osd_button_t but =
1886      {              priv->osd->check(priv->osd, TRUE, event->x, event->y);
         priv->drag_counter = -1;  
1887    
1888          switch(but) {          if(but != OSD_NONE)
1889          case OSD_GPS:          {
1890              priv->osd.cb(priv->osd.data);              int step =
1891              break;                  GTK_WIDGET(widget)->allocation.width/OSM_GPS_MAP_SCROLL_STEP;
1892                priv->drag_counter = -1;
1893          case OSD_UP:  
1894              priv->map_y -= GTK_WIDGET(widget)->allocation.height/SCROLL_STEP;              switch(but) {
1895              priv->center_coord_set = FALSE;              case OSD_UP:
1896              break;                  priv->map_y -= step;
1897                    center_coord_update(map);
1898          case OSD_DOWN:                  g_object_set(G_OBJECT(widget), "auto-center", FALSE, NULL);
1899              priv->map_y += GTK_WIDGET(widget)->allocation.height/SCROLL_STEP;                  osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));
1900              priv->center_coord_set = FALSE;                  break;
             break;  
   
         case OSD_LEFT:  
             priv->map_x -= GTK_WIDGET(widget)->allocation.width/SCROLL_STEP;  
             priv->center_coord_set = FALSE;  
             break;  
   
         case OSD_RIGHT:  
             priv->map_x += GTK_WIDGET(widget)->allocation.width/SCROLL_STEP;  
             priv->center_coord_set = FALSE;  
             break;  
   
         case OSD_IN:  
             osm_gps_map_set_zoom(OSM_GPS_MAP(widget), priv->map_zoom+1);  
             break;  
1901    
1902          case OSD_OUT:              case OSD_DOWN:
1903              osm_gps_map_set_zoom(OSM_GPS_MAP(widget), priv->map_zoom-1);                  priv->map_y += step;
1904              break;                  center_coord_update(map);
1905                    g_object_set(G_OBJECT(widget), "auto-center", FALSE, NULL);
1906                    osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));
1907                    break;
1908    
1909          default:              case OSD_LEFT:
1910              break;                  priv->map_x -= step;
1911                    center_coord_update(map);
1912                    g_object_set(G_OBJECT(widget), "auto-center", FALSE, NULL);
1913                    osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));
1914                    break;
1915    
1916                case OSD_RIGHT:
1917                    priv->map_x += step;
1918                    center_coord_update(map);
1919                    g_object_set(G_OBJECT(widget), "auto-center", FALSE, NULL);
1920                    osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));
1921                    break;
1922    
1923                case OSD_IN:
1924                    osm_gps_map_set_zoom(OSM_GPS_MAP(widget), priv->map_zoom+1);
1925                    break;
1926    
1927                case OSD_OUT:
1928                    osm_gps_map_set_zoom(OSM_GPS_MAP(widget), priv->map_zoom-1);
1929                    break;
1930    
1931                default:
1932                    /* all custom buttons are forwarded to the application */
1933                    if(priv->osd->cb)
1934                        priv->osd->cb(but, priv->osd->data);
1935                    break;
1936                }
1937    
1938                return FALSE;
1939          }          }
   
         osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));  
   
         return FALSE;  
1940      }      }
1941  #endif  #endif
1942    
1943        priv->button_down = TRUE;
1944      priv->drag_counter = 0;      priv->drag_counter = 0;
1945      priv->drag_start_mouse_x = (int) event->x;      priv->drag_start_mouse_x = (int) event->x;
1946      priv->drag_start_mouse_y = (int) event->y;      priv->drag_start_mouse_y = (int) event->y;
# Line 2306  osm_gps_map_button_press (GtkWidget *wid Line 1953  osm_gps_map_button_press (GtkWidget *wid
1953  static gboolean  static gboolean
1954  osm_gps_map_button_release (GtkWidget *widget, GdkEventButton *event)  osm_gps_map_button_release (GtkWidget *widget, GdkEventButton *event)
1955  {  {
1956        OsmGpsMap *map = OSM_GPS_MAP(widget);
1957      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);
1958    
1959  #ifdef ENABLE_BALLOON      if(!priv->button_down)
1960      /* released inside the balloon? */          return FALSE;
     if (osm_gps_map_in_balloon(priv,  
                    event->x + EXTRA_BORDER,  
                    event->y + EXTRA_BORDER))  
     {  
         osm_gps_map_handle_balloon_click(OSM_GPS_MAP(widget),  
              event->x - priv->balloon.rect.x + EXTRA_BORDER,  
              event->y - priv->balloon.rect.y + EXTRA_BORDER);  
     }  
 #endif  
1961    
1962      if (priv->dragging)      if (priv->dragging)
1963      {      {
# Line 2330  osm_gps_map_button_release (GtkWidget *w Line 1969  osm_gps_map_button_release (GtkWidget *w
1969          priv->map_x += (priv->drag_start_mouse_x - (int) event->x);          priv->map_x += (priv->drag_start_mouse_x - (int) event->x);
1970          priv->map_y += (priv->drag_start_mouse_y - (int) event->y);          priv->map_y += (priv->drag_start_mouse_y - (int) event->y);
1971    
1972          priv->center_coord_set = FALSE;          center_coord_update(map);
1973    
1974          osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));          osm_gps_map_map_redraw_idle(map);
1975      }      }
1976    #ifdef ENABLE_OSD
1977        /* pressed inside OSD control? */
1978        else if(priv->osd)
1979            priv->osd->check(priv->osd, FALSE, event->x, event->y);
1980    #endif
1981    
1982    #ifdef DRAG_DEBUG
1983        printf("dragging done\n");
1984    #endif
1985    
     priv->drag_mouse_dx = 0;  
     priv->drag_mouse_dy = 0;  
1986      priv->drag_counter = -1;      priv->drag_counter = -1;
1987        priv->button_down = 0;
1988    
1989      return FALSE;      return FALSE;
1990  }  }
# Line 2346  static gboolean Line 1993  static gboolean
1993  osm_gps_map_expose (GtkWidget *widget, GdkEventExpose  *event);  osm_gps_map_expose (GtkWidget *widget, GdkEventExpose  *event);
1994    
1995  static gboolean  static gboolean
1996    osm_gps_map_map_expose (GtkWidget *widget)
1997    {
1998        OsmGpsMapPrivate *priv = OSM_GPS_MAP(widget)->priv;
1999    
2000        priv->drag_expose = 0;
2001        osm_gps_map_expose (widget, NULL);
2002        return FALSE;
2003    }
2004    
2005    static gboolean
2006  osm_gps_map_motion_notify (GtkWidget *widget, GdkEventMotion  *event)  osm_gps_map_motion_notify (GtkWidget *widget, GdkEventMotion  *event)
2007  {  {
2008      int x, y;      int x, y;
2009      GdkModifierType state;      GdkModifierType state;
2010      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);
2011    
2012        if(!priv->button_down)
2013            return FALSE;
2014    
2015      if (event->is_hint)      if (event->is_hint)
2016          gdk_window_get_pointer (event->window, &x, &y, &state);          gdk_window_get_pointer (event->window, &x, &y, &state);
2017      else      else
# Line 2368  osm_gps_map_motion_notify (GtkWidget *wi Line 2028  osm_gps_map_motion_notify (GtkWidget *wi
2028      if (priv->drag_counter < 0)      if (priv->drag_counter < 0)
2029          return FALSE;          return FALSE;
2030    
2031      priv->drag_counter++;      /* not yet dragged far enough? */
2032        if(!priv->drag_counter &&
2033      // we havent dragged more than 6 pixels         ( (x - priv->drag_start_mouse_x) * (x - priv->drag_start_mouse_x) +
2034      if (priv->drag_counter < 6)           (y - priv->drag_start_mouse_y) * (y - priv->drag_start_mouse_y) <
2035             priv->drag_limit*priv->drag_limit))
2036          return FALSE;          return FALSE;
2037    
2038  #ifdef USE_MAEMO      priv->drag_counter++;
     /* reduce update frequency on maemo to keep screen update fluid */  
     static guint32 last_time = 0;  
   
     if(event->time - last_time < 100) return FALSE;  
     last_time = event->time;  
 #endif  
2039    
2040      priv->dragging = TRUE;      priv->dragging = TRUE;
2041    
# Line 2390  osm_gps_map_motion_notify (GtkWidget *wi Line 2045  osm_gps_map_motion_notify (GtkWidget *wi
2045      priv->drag_mouse_dx = x - priv->drag_start_mouse_x;      priv->drag_mouse_dx = x - priv->drag_start_mouse_x;
2046      priv->drag_mouse_dy = y - priv->drag_start_mouse_y;      priv->drag_mouse_dy = y - priv->drag_start_mouse_y;
2047    
2048  #ifdef ENABLE_OSD      /* instead of redrawing directly just add an idle function */
2049      /* undo OSD */      if (!priv->drag_expose)
2050      osm_gps_map_osd_restore (OSM_GPS_MAP(widget));          priv->drag_expose =
2051                g_idle_add ((GSourceFunc)osm_gps_map_map_expose, widget);
     /* draw new OSD */  
     osm_gps_map_osd_draw_controls (OSM_GPS_MAP(widget),  
                                    -priv->drag_mouse_dx,  
                                    -priv->drag_mouse_dy);  
 #endif  
   
     osm_gps_map_expose (widget, NULL);  
   
2052    
2053      return FALSE;      return FALSE;
2054  }  }
# Line 2416  osm_gps_map_configure (GtkWidget *widget Line 2063  osm_gps_map_configure (GtkWidget *widget
2063          g_object_unref (priv->pixmap);          g_object_unref (priv->pixmap);
2064    
2065      priv->pixmap = gdk_pixmap_new (      priv->pixmap = gdk_pixmap_new (
2066                                     widget->window,                          widget->window,
2067                                     widget->allocation.width + EXTRA_BORDER * 2,                          widget->allocation.width + EXTRA_BORDER * 2,
2068                                     widget->allocation.height + EXTRA_BORDER * 2,                          widget->allocation.height + EXTRA_BORDER * 2,
2069                                     -1);                          -1);
2070    
2071        // pixel_x,y, offsets
2072        gint pixel_x = lon2pixel(priv->map_zoom, priv->center_rlon);
2073        gint pixel_y = lat2pixel(priv->map_zoom, priv->center_rlat);
2074    
2075        priv->map_x = pixel_x - widget->allocation.width/2;
2076        priv->map_y = pixel_y - widget->allocation.height/2;
2077    
2078    #ifdef ENABLE_OSD
2079    
2080    #ifdef OSD_DOUBLE_BUFFER
2081        if (priv->dbuf_pixmap)
2082            g_object_unref (priv->dbuf_pixmap);
2083    
2084        priv->dbuf_pixmap = gdk_pixmap_new (
2085                            widget->window,
2086                            widget->allocation.width,
2087                            widget->allocation.height,
2088                            -1);
2089    #endif
2090    
2091        /* the osd needs some references to map internal objects */
2092        if(priv->osd)
2093            priv->osd->widget = widget;
2094    #endif
2095    
2096      /* and gc, used for clipping (I think......) */      /* and gc, used for clipping (I think......) */
2097      if(priv->gc_map)      if(priv->gc_map)
# Line 2429  osm_gps_map_configure (GtkWidget *widget Line 2101  osm_gps_map_configure (GtkWidget *widget
2101    
2102      osm_gps_map_map_redraw(OSM_GPS_MAP(widget));      osm_gps_map_map_redraw(OSM_GPS_MAP(widget));
2103    
2104        g_signal_emit_by_name(widget, "changed");
2105    
2106      return FALSE;      return FALSE;
2107  }  }
2108    
2109  static gboolean  static gboolean
2110  osm_gps_map_expose (GtkWidget *widget, GdkEventExpose  *event)  osm_gps_map_expose (GtkWidget *widget, GdkEventExpose  *event)
2111  {  {
2112      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);      OsmGpsMap *map = OSM_GPS_MAP(widget);
2113        OsmGpsMapPrivate *priv = map->priv;
2114    
2115      gdk_draw_drawable (  #ifdef OSD_DOUBLE_BUFFER
2116                         widget->window,      GdkDrawable *drawable = priv->dbuf_pixmap;
2117                         widget->style->fg_gc[GTK_WIDGET_STATE (widget)],  #else
2118                         priv->pixmap,      GdkDrawable *drawable = widget->window;
2119                         0,0,  #endif
2120                         priv->drag_mouse_dx - EXTRA_BORDER,  
2121                         priv->drag_mouse_dy - EXTRA_BORDER,  #ifdef DRAG_DEBUG
2122                         -1,-1);      printf("expose, map %d/%d\n", priv->map_x, priv->map_y);
2123    #endif
2124      //Paint white outside of the map if dragging. Its less  
2125      //ugly than painting the corrupted map      if (!priv->drag_mouse_dx && !priv->drag_mouse_dy && event)
2126      if(priv->drag_mouse_dx>EXTRA_BORDER) {      {
2127          gdk_draw_rectangle (  #ifdef DRAG_DEBUG
2128                              widget->window,          printf("  dragging = %d, event = %p\n", priv->dragging, event);
2129                              widget->style->white_gc,  #endif
2130                              TRUE,  
2131                              0, 0,          gdk_draw_drawable (drawable,
2132                              priv->drag_mouse_dx - EXTRA_BORDER,                             widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
2133                              widget->allocation.height);                             priv->pixmap,
2134      }                             event->area.x + EXTRA_BORDER, event->area.y + EXTRA_BORDER,
2135      else if (-priv->drag_mouse_dx > EXTRA_BORDER)                             event->area.x, event->area.y,
2136      {                             event->area.width, event->area.height);
2137          gdk_draw_rectangle (      }
2138                              widget->window,      else
2139                              widget->style->white_gc,      {
2140                              TRUE,  #ifdef DRAG_DEBUG
2141                              priv->drag_mouse_dx + widget->allocation.width + EXTRA_BORDER, 0,          printf("  drag_mouse %d/%d\n",
2142                              -priv->drag_mouse_dx - EXTRA_BORDER,                 priv->drag_mouse_dx - EXTRA_BORDER,
2143                              widget->allocation.height);                 priv->drag_mouse_dy - EXTRA_BORDER);
2144      }  #endif
2145    
2146      if (priv->drag_mouse_dy>EXTRA_BORDER) {          gdk_draw_drawable (drawable,
2147          gdk_draw_rectangle (                             widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
2148                              widget->window,                             priv->pixmap,
2149                              widget->style->white_gc,                             0,0,
2150                              TRUE,                             priv->drag_mouse_dx - EXTRA_BORDER,
2151                              0, 0,                             priv->drag_mouse_dy - EXTRA_BORDER,
2152                              widget->allocation.width,                             -1,-1);
2153                              priv->drag_mouse_dy - EXTRA_BORDER);  
2154      }          //Paint white outside of the map if dragging. Its less
2155      else if (-priv->drag_mouse_dy > EXTRA_BORDER)          //ugly than painting the corrupted map
2156      {          if(priv->drag_mouse_dx>EXTRA_BORDER) {
2157          gdk_draw_rectangle (              gdk_draw_rectangle (drawable,
2158                              widget->window,                                  widget->style->white_gc,
2159                              widget->style->white_gc,                                  TRUE,
2160                              TRUE,                                  0, 0,
2161                              0, priv->drag_mouse_dy + widget->allocation.height + EXTRA_BORDER,                                  priv->drag_mouse_dx - EXTRA_BORDER,
2162                              widget->allocation.width,                                  widget->allocation.height);
2163                              -priv->drag_mouse_dy - EXTRA_BORDER);          }
2164      }          else if (-priv->drag_mouse_dx > EXTRA_BORDER)
2165  #if 0          {
2166      if(!priv->dragging)              gdk_draw_rectangle (drawable,
2167          gdk_draw_drawable (                                  widget->style->white_gc,
2168                         widget->window,                                  TRUE,
2169                                    priv->drag_mouse_dx + widget->allocation.width + EXTRA_BORDER, 0,
2170                                    -priv->drag_mouse_dx - EXTRA_BORDER,
2171                                    widget->allocation.height);
2172            }
2173    
2174            if (priv->drag_mouse_dy>EXTRA_BORDER) {
2175                gdk_draw_rectangle (drawable,
2176                                    widget->style->white_gc,
2177                                    TRUE,
2178                                    0, 0,
2179                                    widget->allocation.width,
2180                                    priv->drag_mouse_dy - EXTRA_BORDER);
2181            }
2182            else if (-priv->drag_mouse_dy > EXTRA_BORDER)
2183            {
2184                gdk_draw_rectangle (drawable,
2185                                    widget->style->white_gc,
2186                                    TRUE,
2187                                    0, priv->drag_mouse_dy + widget->allocation.height + EXTRA_BORDER,
2188                                    widget->allocation.width,
2189                                    -priv->drag_mouse_dy - EXTRA_BORDER);
2190            }
2191        }
2192    
2193    #ifdef ENABLE_OSD
2194        /* draw new OSD */
2195        if(priv->osd)
2196            priv->osd->draw (priv->osd, drawable);
2197    
2198    #ifdef OSD_DOUBLE_BUFFER
2199        gdk_draw_drawable (widget->window,
2200                         widget->style->fg_gc[GTK_WIDGET_STATE (widget)],                         widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
2201                         priv->pixmap,                         priv->dbuf_pixmap,
2202                         event->area.x + EXTRA_BORDER,                         0,0,0,0,-1,-1);
                        event->area.y + EXTRA_BORDER,  
                        event->area.x, event->area.y,  
                        event->area.width, event->area.height);  
2203  #endif  #endif
2204    
2205    #endif
2206    
2207      return FALSE;      return FALSE;
2208  }  }
2209    
# Line 2523  osm_gps_map_class_init (OsmGpsMapClass * Line 2229  osm_gps_map_class_init (OsmGpsMapClass *
2229      widget_class->scroll_event = osm_gps_map_scroll_event;      widget_class->scroll_event = osm_gps_map_scroll_event;
2230    
2231      g_object_class_install_property (object_class,      g_object_class_install_property (object_class,
2232                                         PROP_DOUBLE_PIXEL,
2233                                         g_param_spec_boolean ("double-pixel",
2234                                                               "double pixel",
2235                                                               "double map pixels for better readability",
2236                                                               FALSE,
2237                                                               G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
2238    
2239    
2240        g_object_class_install_property (object_class,
2241                                       PROP_AUTO_CENTER,                                       PROP_AUTO_CENTER,
2242                                       g_param_spec_boolean ("auto-center",                                       g_param_spec_boolean ("auto-center",
2243                                                             "auto center",                                                             "auto center",
# Line 2575  osm_gps_map_class_init (OsmGpsMapClass * Line 2290  osm_gps_map_class_init (OsmGpsMapClass *
2290                                       g_param_spec_string ("tile-cache",                                       g_param_spec_string ("tile-cache",
2291                                                            "tile cache",                                                            "tile cache",
2292                                                            "osm local tile cache dir",                                                            "osm local tile cache dir",
2293                                                            NULL,                                                            OSM_GPS_MAP_CACHE_AUTO,
2294                                                            G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));                                                            G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
2295    
2296      g_object_class_install_property (object_class,      g_object_class_install_property (object_class,
2297                                       PROP_TILE_CACHE_DIR_IS_FULL_PATH,                                       PROP_TILE_CACHE_BASE_DIR,
2298                                       g_param_spec_boolean ("tile-cache-is-full-path",                                       g_param_spec_string ("tile-cache-base",
2299                                                             "tile cache is full path",                                                            "tile cache-base",
2300                                                             "if true, the path passed to tile-cache is interpreted as the full cache path",                                                            "base directory to which friendly and auto paths are appended",
2301                                                             FALSE,                                                            NULL,
2302                                                             G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));                                                            G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
2303    
2304         g_object_class_install_property (object_class,
2305                                          PROP_TILE_CACHE_DIR_IS_FULL_PATH,
2306                                          g_param_spec_boolean ("tile-cache-is-full-path",
2307                                                                "tile cache is full path",
2308                                                                "DEPRECIATED",
2309                                                                FALSE,
2310                                                                G_PARAM_READABLE | G_PARAM_WRITABLE));
2311    
2312      g_object_class_install_property (object_class,      g_object_class_install_property (object_class,
2313                                       PROP_ZOOM,                                       PROP_ZOOM,
2314                                       g_param_spec_int ("zoom",                                       g_param_spec_int ("zoom",
2315                                                         "zoom",                                                         "zoom",
2316                                                         "zoom level",                                                         "initial zoom level",
2317                                                         MIN_ZOOM, /* minimum property value */                                                         MIN_ZOOM, /* minimum property value */
2318                                                         MAX_ZOOM, /* maximum property value */                                                         MAX_ZOOM, /* maximum property value */
2319                                                         3,                                                         3,
# Line 2683  osm_gps_map_class_init (OsmGpsMapClass * Line 2406  osm_gps_map_class_init (OsmGpsMapClass *
2406                                                         "radius of the gps point inner circle",                                                         "radius of the gps point inner circle",
2407                                                         0,           /* minimum property value */                                                         0,           /* minimum property value */
2408                                                         G_MAXINT,    /* maximum property value */                                                         G_MAXINT,    /* maximum property value */
2409                                                         10,                                                         5,
2410                                                         G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));                                                         G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
2411    
2412      g_object_class_install_property (object_class,      g_object_class_install_property (object_class,
# Line 2701  osm_gps_map_class_init (OsmGpsMapClass * Line 2424  osm_gps_map_class_init (OsmGpsMapClass *
2424                                       g_param_spec_int ("map-source",                                       g_param_spec_int ("map-source",
2425                                                         "map source",                                                         "map source",
2426                                                         "map source ID",                                                         "map source ID",
2427                                                         -1,           /* minimum property value */                                                         -1,          /* minimum property value */
2428                                                         G_MAXINT,    /* maximum property value */                                                         G_MAXINT,    /* maximum property value */
2429                                                         -1,                                                         -1,
2430                                                         G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));                                                         G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
2431    
2432      g_object_class_install_property (object_class,      g_object_class_install_property (object_class,
2433                                       PROP_IMAGE_FORMAT,                                       PROP_IMAGE_FORMAT,
# Line 2713  osm_gps_map_class_init (OsmGpsMapClass * Line 2436  osm_gps_map_class_init (OsmGpsMapClass *
2436                                                            "map source tile repository image format (jpg, png)",                                                            "map source tile repository image format (jpg, png)",
2437                                                            OSM_IMAGE_FORMAT,                                                            OSM_IMAGE_FORMAT,
2438                                                            G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));                                                            G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
2439    
2440        g_object_class_install_property (object_class,
2441                                         PROP_DRAG_LIMIT,
2442                                         g_param_spec_int ("drag-limit",
2443                                                           "drag limit",
2444                                                           "the number of pixels the user has to move the pointer in order to start dragging",
2445                                                           0,           /* minimum property value */
2446                                                           G_MAXINT,    /* maximum property value */
2447                                                           10,
2448                                                           G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
2449    
2450        g_signal_new ("changed", OSM_TYPE_GPS_MAP,
2451                      G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
2452                      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
2453  }  }
2454    
2455  const char*  const char*
# Line 2723  osm_gps_map_source_get_friendly_name(Osm Line 2460  osm_gps_map_source_get_friendly_name(Osm
2460          case OSM_GPS_MAP_SOURCE_NULL:          case OSM_GPS_MAP_SOURCE_NULL:
2461              return "None";              return "None";
2462          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP:          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP:
2463              return "OpenStreetMap";              return "OpenStreetMap I";
2464          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER:          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER:
2465              return "OpenStreetMap Renderer";              return "OpenStreetMap II";
2466          case OSM_GPS_MAP_SOURCE_OPENAERIALMAP:          case OSM_GPS_MAP_SOURCE_OPENAERIALMAP:
2467              return "OpenAerialMap";              return "OpenAerialMap";
2468            case OSM_GPS_MAP_SOURCE_OPENCYCLEMAP:
2469                return "OpenCycleMap";
2470            case OSM_GPS_MAP_SOURCE_OSM_PUBLIC_TRANSPORT:
2471                return "Public Transport";
2472            case OSM_GPS_MAP_SOURCE_OSMC_TRAILS:
2473                return "OSMC Trails";
2474          case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE:          case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE:
2475              return "Maps-For-Free";              return "Maps-For-Free";
2476          case OSM_GPS_MAP_SOURCE_GOOGLE_STREET:          case OSM_GPS_MAP_SOURCE_GOOGLE_STREET:
# Line 2748  osm_gps_map_source_get_friendly_name(Osm Line 2491  osm_gps_map_source_get_friendly_name(Osm
2491              return "Yahoo Satellite";              return "Yahoo Satellite";
2492          case OSM_GPS_MAP_SOURCE_YAHOO_HYBRID:          case OSM_GPS_MAP_SOURCE_YAHOO_HYBRID:
2493              return "Yahoo Hybrid";              return "Yahoo Hybrid";
2494            case OSM_GPS_MAP_SOURCE_LAST:
2495          default:          default:
2496              return NULL;              return NULL;
2497      }      }
# Line 2767  osm_gps_map_source_get_repo_uri(OsmGpsMa Line 2511  osm_gps_map_source_get_repo_uri(OsmGpsMa
2511              return "none://";              return "none://";
2512          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP:          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP:
2513              return OSM_REPO_URI;              return OSM_REPO_URI;
2514            case OSM_GPS_MAP_SOURCE_OPENAERIALMAP:
2515                /* OpenAerialMap is down, offline till furthur notice
2516                   http://openaerialmap.org/pipermail/talk_openaerialmap.org/2008-December/000055.html */
2517                return NULL;
2518          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER:          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER:
2519              return "http://tah.openstreetmap.org/Tiles/tile/#Z/#X/#Y.png";              return "http://tah.openstreetmap.org/Tiles/tile/#Z/#X/#Y.png";
2520          case OSM_GPS_MAP_SOURCE_OPENAERIALMAP:          case OSM_GPS_MAP_SOURCE_OPENCYCLEMAP:
2521              return "http://tile.openaerialmap.org/tiles/1.0.0/openaerialmap-900913/#Z/#X/#Y.jpg";              return "http://c.andy.sandbox.cloudmade.com/tiles/cycle/#Z/#X/#Y.png";
2522            case OSM_GPS_MAP_SOURCE_OSM_PUBLIC_TRANSPORT:
2523                return "http://tile.xn--pnvkarte-m4a.de/tilegen/#Z/#X/#Y.png";
2524            case OSM_GPS_MAP_SOURCE_OSMC_TRAILS:
2525                return "http://topo.geofabrik.de/trails/#Z/#X/#Y.png";
2526          case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE:          case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE:
2527              return "http://maps-for-free.com/layer/relief/z#Z/row#Y/#Z_#X-#Y.jpg";              return "http://maps-for-free.com/layer/relief/z#Z/row#Y/#Z_#X-#Y.jpg";
2528          case OSM_GPS_MAP_SOURCE_GOOGLE_STREET:          case OSM_GPS_MAP_SOURCE_GOOGLE_STREET:
2529              return "http://mt#R.google.com/vt/v=w2.97&x=#X&y=#Y&z=#Z";              return "http://mt#R.google.com/vt/v=w2.97&x=#X&y=#Y&z=#Z";
         case OSM_GPS_MAP_SOURCE_GOOGLE_SATELLITE:  
             return "http://khm#R.google.com/kh?n=404&v=3&t=#Q";  
2530          case OSM_GPS_MAP_SOURCE_GOOGLE_HYBRID:          case OSM_GPS_MAP_SOURCE_GOOGLE_HYBRID:
2531              return NULL; /* No longer working  "http://mt#R.google.com/mt?n=404&v=w2t.99&x=#X&y=#Y&zoom=#S" */              /* No longer working
2532                   "http://mt#R.google.com/mt?n=404&v=w2t.99&x=#X&y=#Y&zoom=#S" */
2533                return NULL;
2534            case OSM_GPS_MAP_SOURCE_GOOGLE_SATELLITE:
2535                return "http://khm#R.google.com/kh/v=51&x=#X&y=#Y&z=#Z";
2536          case OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_STREET:          case OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_STREET:
2537              return "http://a#R.ortho.tiles.virtualearth.net/tiles/r#W.jpeg?g=50";              return "http://a#R.ortho.tiles.virtualearth.net/tiles/r#W.jpeg?g=50";
2538          case OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_SATELLITE:          case OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_SATELLITE:
# Line 2795  osm_gps_map_source_get_repo_uri(OsmGpsMa Line 2549  osm_gps_map_source_get_repo_uri(OsmGpsMa
2549               *  z = zoom - (MAX_ZOOM - 17));               *  z = zoom - (MAX_ZOOM - 17));
2550               */               */
2551              return NULL;              return NULL;
2552            case OSM_GPS_MAP_SOURCE_LAST:
2553          default:          default:
2554              return NULL;              return NULL;
2555      }      }
# Line 2808  osm_gps_map_source_get_image_format(OsmG Line 2563  osm_gps_map_source_get_image_format(OsmG
2563          case OSM_GPS_MAP_SOURCE_NULL:          case OSM_GPS_MAP_SOURCE_NULL:
2564          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP:          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP:
2565          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER:          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER:
2566            case OSM_GPS_MAP_SOURCE_OPENCYCLEMAP:
2567            case OSM_GPS_MAP_SOURCE_OSM_PUBLIC_TRANSPORT:
2568            case OSM_GPS_MAP_SOURCE_OSMC_TRAILS:
2569              return "png";              return "png";
2570          case OSM_GPS_MAP_SOURCE_OPENAERIALMAP:          case OSM_GPS_MAP_SOURCE_OPENAERIALMAP:
2571          case OSM_GPS_MAP_SOURCE_GOOGLE_STREET:          case OSM_GPS_MAP_SOURCE_GOOGLE_STREET:
# Line 2821  osm_gps_map_source_get_image_format(OsmG Line 2579  osm_gps_map_source_get_image_format(OsmG
2579          case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE:          case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE:
2580          case OSM_GPS_MAP_SOURCE_GOOGLE_SATELLITE:          case OSM_GPS_MAP_SOURCE_GOOGLE_SATELLITE:
2581              return "jpg";              return "jpg";
2582            case OSM_GPS_MAP_SOURCE_LAST:
2583          default:          default:
2584              return "bin";              return "bin";
2585      }      }
# Line 2841  osm_gps_map_source_get_max_zoom(OsmGpsMa Line 2600  osm_gps_map_source_get_max_zoom(OsmGpsMa
2600          case OSM_GPS_MAP_SOURCE_NULL:          case OSM_GPS_MAP_SOURCE_NULL:
2601              return 18;              return 18;
2602          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP:          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP:
2603            case OSM_GPS_MAP_SOURCE_OPENCYCLEMAP:
2604            case OSM_GPS_MAP_SOURCE_OSM_PUBLIC_TRANSPORT:
2605              return OSM_MAX_ZOOM;              return OSM_MAX_ZOOM;
2606          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER:          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER:
2607          case OSM_GPS_MAP_SOURCE_OPENAERIALMAP:          case OSM_GPS_MAP_SOURCE_OPENAERIALMAP:
# Line 2853  osm_gps_map_source_get_max_zoom(OsmGpsMa Line 2614  osm_gps_map_source_get_max_zoom(OsmGpsMa
2614          case OSM_GPS_MAP_SOURCE_YAHOO_SATELLITE:          case OSM_GPS_MAP_SOURCE_YAHOO_SATELLITE:
2615          case OSM_GPS_MAP_SOURCE_YAHOO_HYBRID:          case OSM_GPS_MAP_SOURCE_YAHOO_HYBRID:
2616              return 17;              return 17;
2617            case OSM_GPS_MAP_SOURCE_OSMC_TRAILS:
2618                return 15;
2619          case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE:          case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE:
2620              return 11;              return 11;
2621          case OSM_GPS_MAP_SOURCE_GOOGLE_SATELLITE:          case OSM_GPS_MAP_SOURCE_GOOGLE_SATELLITE:
2622              return 18;              return 18;
2623            case OSM_GPS_MAP_SOURCE_LAST:
2624          default:          default:
2625              return 17;              return 17;
2626      }      }
2627      return 17;      return 17;
2628  }  }
2629    
2630    gboolean
2631    osm_gps_map_source_is_valid(OsmGpsMapSource_t source)
2632    {
2633        return osm_gps_map_source_get_repo_uri(source) != NULL;
2634    }
2635    
2636  void  void
2637  osm_gps_map_download_maps (OsmGpsMap *map, coord_t *pt1, coord_t *pt2, int zoom_start, int zoom_end)  osm_gps_map_download_maps (OsmGpsMap *map, coord_t *pt1, coord_t *pt2, int zoom_start, int zoom_end)
2638  {  {
# Line 2899  osm_gps_map_download_maps (OsmGpsMap *ma Line 2669  osm_gps_map_download_maps (OsmGpsMap *ma
2669                                      i, G_DIR_SEPARATOR,                                      i, G_DIR_SEPARATOR,
2670                                      j,                                      j,
2671                                      priv->image_format);                                      priv->image_format);
2672                      if (!g_file_test(filename, G_FILE_TEST_EXISTS))  
2673                        if ((!g_file_test(filename, G_FILE_TEST_EXISTS)) ||
2674                            osm_gps_map_tile_age_exceeded(filename))
2675                      {                      {
2676                          osm_gps_map_download_tile(map, zoom, i, j, FALSE);                          osm_gps_map_download_tile(map, zoom, i, j, FALSE);
2677                          num_tiles++;                          num_tiles++;
2678                      }                      }
2679    
2680                      g_free(filename);                      g_free(filename);
2681                  }                  }
2682              }              }
# Line 2943  osm_gps_map_set_center (OsmGpsMap *map, Line 2716  osm_gps_map_set_center (OsmGpsMap *map,
2716      g_return_if_fail (OSM_IS_GPS_MAP (map));      g_return_if_fail (OSM_IS_GPS_MAP (map));
2717      priv = map->priv;      priv = map->priv;
2718    
2719        g_object_set(G_OBJECT(map), "auto-center", FALSE, NULL);
2720    
2721      priv->center_rlat = deg2rad(latitude);      priv->center_rlat = deg2rad(latitude);
2722      priv->center_rlon = deg2rad(longitude);      priv->center_rlon = deg2rad(longitude);
     priv->center_coord_set = TRUE;  
2723    
2724      // pixel_x,y, offsets      // pixel_x,y, offsets
2725      pixel_x = lon2pixel(priv->map_zoom, priv->center_rlon);      pixel_x = lon2pixel(priv->map_zoom, priv->center_rlon);
# Line 2955  osm_gps_map_set_center (OsmGpsMap *map, Line 2729  osm_gps_map_set_center (OsmGpsMap *map,
2729      priv->map_y = pixel_y - GTK_WIDGET(map)->allocation.height/2;      priv->map_y = pixel_y - GTK_WIDGET(map)->allocation.height/2;
2730    
2731      osm_gps_map_map_redraw_idle(map);      osm_gps_map_map_redraw_idle(map);
2732    
2733        g_signal_emit_by_name(map, "changed");
2734  }  }
2735    
2736  int  int
# Line 2977  osm_gps_map_set_zoom (OsmGpsMap *map, in Line 2753  osm_gps_map_set_zoom (OsmGpsMap *map, in
2753          //constrain zoom min_zoom -> max_zoom          //constrain zoom min_zoom -> max_zoom
2754          priv->map_zoom = CLAMP(zoom, priv->min_zoom, priv->max_zoom);          priv->map_zoom = CLAMP(zoom, priv->min_zoom, priv->max_zoom);
2755    
2756          if (priv->center_coord_set)          priv->map_x = lon2pixel(priv->map_zoom, priv->center_rlon) - width_center;
2757          {          priv->map_y = lat2pixel(priv->map_zoom, priv->center_rlat) - height_center;
             priv->map_x = lon2pixel(priv->map_zoom, priv->center_rlon) - width_center;  
             priv->map_y = lat2pixel(priv->map_zoom, priv->center_rlat) - height_center;  
         }  
         else  
         {  
             factor = exp(priv->map_zoom * M_LN2)/exp(zoom_old * M_LN2);  
             priv->map_x = ((priv->map_x + width_center) * factor) - width_center;  
             priv->map_y = ((priv->map_y + height_center) * factor) - height_center;  
         }  
2758    
2759            factor = pow(2, priv->map_zoom-zoom_old);
2760          g_debug("Zoom changed from %d to %d factor:%f x:%d",          g_debug("Zoom changed from %d to %d factor:%f x:%d",
2761                  zoom_old, priv->map_zoom, factor, priv->map_x);                  zoom_old, priv->map_zoom, factor, priv->map_x);
2762    
2763            /* adjust gps precision indicator */
2764            priv->ui_gps_point_outer_radius *= factor;
2765    
2766    #ifdef ENABLE_OSD
2767            /* OSD may contain a scale, so we may have to re-render it */
2768            if(priv->osd && OSM_IS_GPS_MAP (priv->osd->widget))
2769                priv->osd->render (priv->osd);
2770    #endif
2771    
2772          osm_gps_map_map_redraw_idle(map);          osm_gps_map_map_redraw_idle(map);
2773    
2774            g_signal_emit_by_name(map, "changed");
2775      }      }
2776      return priv->map_zoom;      return priv->map_zoom;
2777  }  }
2778    
2779    int
2780    osm_gps_map_zoom_in (OsmGpsMap *map)
2781    {
2782        g_return_val_if_fail (OSM_IS_GPS_MAP (map), 0);
2783        return osm_gps_map_set_zoom(map, map->priv->map_zoom+1);
2784    }
2785    
2786    int
2787    osm_gps_map_zoom_out (OsmGpsMap *map)
2788    {
2789        g_return_val_if_fail (OSM_IS_GPS_MAP (map), 0);
2790        return osm_gps_map_set_zoom(map, map->priv->map_zoom-1);
2791    }
2792    
2793  void  void
2794  osm_gps_map_add_track (OsmGpsMap *map, GSList *track)  osm_gps_map_add_track (OsmGpsMap *map, GSList *track)
2795  {  {
# Line 3012  osm_gps_map_add_track (OsmGpsMap *map, G Line 2805  osm_gps_map_add_track (OsmGpsMap *map, G
2805  }  }
2806    
2807  void  void
2808    osm_gps_map_replace_track (OsmGpsMap *map, GSList *old_track, GSList *new_track)
2809    {
2810        OsmGpsMapPrivate *priv;
2811    
2812        if(!old_track) {
2813            osm_gps_map_add_track (map, new_track);
2814            return;
2815        }
2816    
2817        g_return_if_fail (OSM_IS_GPS_MAP (map));
2818        priv = map->priv;
2819    
2820        GSList *old = g_slist_find(priv->tracks, old_track);
2821        if(!old) {
2822            g_warning("track to be replaced not found");
2823            return;
2824        }
2825    
2826        old->data = new_track;
2827        osm_gps_map_map_redraw_idle(map);
2828    }
2829    
2830    void
2831  osm_gps_map_clear_tracks (OsmGpsMap *map)  osm_gps_map_clear_tracks (OsmGpsMap *map)
2832  {  {
2833      g_return_if_fail (OSM_IS_GPS_MAP (map));      g_return_if_fail (OSM_IS_GPS_MAP (map));
# Line 3021  osm_gps_map_clear_tracks (OsmGpsMap *map Line 2837  osm_gps_map_clear_tracks (OsmGpsMap *map
2837  }  }
2838    
2839  void  void
2840  osm_gps_map_add_image (OsmGpsMap *map, float latitude, float longitude, GdkPixbuf *image)  osm_gps_map_add_image_with_alignment (OsmGpsMap *map, float latitude, float longitude, GdkPixbuf *image, float xalign, float yalign)
2841  {  {
2842      g_return_if_fail (OSM_IS_GPS_MAP (map));      g_return_if_fail (OSM_IS_GPS_MAP (map));
2843    
# Line 3036  osm_gps_map_add_image (OsmGpsMap *map, f Line 2852  osm_gps_map_add_image (OsmGpsMap *map, f
2852          im->pt.rlat = deg2rad(latitude);          im->pt.rlat = deg2rad(latitude);
2853          im->pt.rlon = deg2rad(longitude);          im->pt.rlon = deg2rad(longitude);
2854    
2855            //handle alignment
2856            im->xoffset = xalign * im->w;
2857            im->yoffset = yalign * im->h;
2858    
2859          g_object_ref(image);          g_object_ref(image);
2860          im->image = image;          im->image = image;
2861    
# Line 3045  osm_gps_map_add_image (OsmGpsMap *map, f Line 2865  osm_gps_map_add_image (OsmGpsMap *map, f
2865      }      }
2866  }  }
2867    
2868    void
2869    osm_gps_map_add_image (OsmGpsMap *map, float latitude, float longitude, GdkPixbuf *image)
2870    {
2871        osm_gps_map_add_image_with_alignment (map, latitude, longitude, image, 0.5, 0.5);
2872    }
2873    
2874  gboolean  gboolean
2875  osm_gps_map_remove_image (OsmGpsMap *map, GdkPixbuf *image)  osm_gps_map_remove_image (OsmGpsMap *map, GdkPixbuf *image)
2876  {  {
# Line 3077  osm_gps_map_clear_images (OsmGpsMap *map Line 2903  osm_gps_map_clear_images (OsmGpsMap *map
2903  }  }
2904    
2905  void  void
 osm_gps_map_osd_speed (OsmGpsMap *map, float speed)  
 {  
     OsmGpsMapPrivate *priv;  
   
     PangoContext        *context = NULL;  
     PangoLayout     *layout  = NULL;  
     PangoFontDescription    *desc    = NULL;  
   
     GdkColor color;  
     GdkGC *gc;  
   
     gchar *buffer;  
     //static int x = 10, y = 10;  
     static int width = 0, height = 0;  
   
     g_return_if_fail (OSM_IS_GPS_MAP (map));  
     priv = map->priv;  
   
     buffer = g_strdup_printf("%.0f", speed);  
   
     /* pango initialisation */  
     context = gtk_widget_get_pango_context (GTK_WIDGET(map));  
     layout  = pango_layout_new (context);  
     desc    = pango_font_description_new();  
   
     pango_font_description_set_size (desc, 40 * PANGO_SCALE);  
     pango_layout_set_font_description (layout, desc);  
     pango_layout_set_text (layout, buffer, strlen(buffer));  
   
     gc = gdk_gc_new (GTK_WIDGET(map)->window);  
   
     color.red = (0 > 50) ? 0xffff : 0;  
     color.green = 0;  
     color.blue = 0;  
   
     gdk_gc_set_rgb_fg_color (gc, &color);  
   
     /* faster / less flicker alternative:*/  
     gdk_draw_drawable (  
                        GTK_WIDGET(map)->window,  
                        GTK_WIDGET(map)->style->fg_gc[GTK_WIDGET_STATE(map)],  
                        priv->pixmap,  
                        0,0,  
                        0,0,  
                        width+10,width+10);  
   
     gdk_draw_layout(GTK_WIDGET(map)->window,  
                     gc,  
                     0, 0,  
                     layout);  
   
     /* set width and height */  
     pango_layout_get_pixel_size(layout, &width, &height);  
   
     g_free(buffer);  
     pango_font_description_free (desc);  
     g_object_unref (layout);  
     g_object_unref (gc);  
 }  
   
 void  
2906  osm_gps_map_draw_gps (OsmGpsMap *map, float latitude, float longitude, float heading)  osm_gps_map_draw_gps (OsmGpsMap *map, float latitude, float longitude, float heading)
2907  {  {
2908      int pixel_x, pixel_y;      int pixel_x, pixel_y;
# Line 3149  osm_gps_map_draw_gps (OsmGpsMap *map, fl Line 2914  osm_gps_map_draw_gps (OsmGpsMap *map, fl
2914      priv->gps->rlat = deg2rad(latitude);      priv->gps->rlat = deg2rad(latitude);
2915      priv->gps->rlon = deg2rad(longitude);      priv->gps->rlon = deg2rad(longitude);
2916      priv->gps_valid = TRUE;      priv->gps_valid = TRUE;
2917        priv->gps_heading = deg2rad(heading);
2918    
2919      // pixel_x,y, offsets      // pixel_x,y, offsets
2920      pixel_x = lon2pixel(priv->map_zoom, priv->gps->rlon);      pixel_x = lon2pixel(priv->map_zoom, priv->gps->rlon);
# Line 3179  osm_gps_map_draw_gps (OsmGpsMap *map, fl Line 2945  osm_gps_map_draw_gps (OsmGpsMap *map, fl
2945    
2946              priv->map_x = pixel_x - GTK_WIDGET(map)->allocation.width/2;              priv->map_x = pixel_x - GTK_WIDGET(map)->allocation.width/2;
2947              priv->map_y = pixel_y - GTK_WIDGET(map)->allocation.height/2;              priv->map_y = pixel_y - GTK_WIDGET(map)->allocation.height/2;
2948              priv->center_coord_set = FALSE;              center_coord_update(map);
2949          }          }
2950      }      }
2951    
# Line 3238  osm_gps_map_geographic_to_screen (OsmGps Line 3004  osm_gps_map_geographic_to_screen (OsmGps
3004      priv = map->priv;      priv = map->priv;
3005    
3006      if (pixel_x)      if (pixel_x)
3007          *pixel_x = lon2pixel(priv->map_zoom, deg2rad(longitude)) - priv->map_x;          *pixel_x = lon2pixel(priv->map_zoom, deg2rad(longitude)) -
3008                priv->map_x + priv->drag_mouse_dx;
3009      if (pixel_y)      if (pixel_y)
3010          *pixel_y = lat2pixel(priv->map_zoom, deg2rad(latitude)) - priv->map_y;          *pixel_y = lat2pixel(priv->map_zoom, deg2rad(latitude)) -
3011                priv->map_y + priv->drag_mouse_dy;
3012  }  }
3013    
3014  void  void
# Line 3251  osm_gps_map_scroll (OsmGpsMap *map, gint Line 3019  osm_gps_map_scroll (OsmGpsMap *map, gint
3019      g_return_if_fail (OSM_IS_GPS_MAP (map));      g_return_if_fail (OSM_IS_GPS_MAP (map));
3020      priv = map->priv;      priv = map->priv;
3021    
     priv->center_coord_set = FALSE;  
3022      priv->map_x += dx;      priv->map_x += dx;
3023      priv->map_y += dy;      priv->map_y += dy;
3024        center_coord_update(map);
3025    
3026    #ifdef ENABLE_OSD
3027        /* OSD may contain a coordinate, so we may have to re-render it */
3028        if(priv->osd && OSM_IS_GPS_MAP (priv->osd->widget))
3029            priv->osd->render (priv->osd);
3030    #endif
3031    
3032      osm_gps_map_map_redraw_idle (map);      osm_gps_map_map_redraw_idle (map);
3033  }  }
# Line 3263  osm_gps_map_get_scale(OsmGpsMap *map) Line 3037  osm_gps_map_get_scale(OsmGpsMap *map)
3037  {  {
3038      OsmGpsMapPrivate *priv;      OsmGpsMapPrivate *priv;
3039    
3040      g_return_val_if_fail (OSM_IS_GPS_MAP (map), OSM_NAN);      g_return_val_if_fail (OSM_IS_GPS_MAP (map), OSM_GPS_MAP_INVALID);
3041      priv = map->priv;      priv = map->priv;
3042    
3043      return osm_gps_map_get_scale_at_point(priv->map_zoom, priv->center_rlat, priv->center_rlon);      return osm_gps_map_get_scale_at_point(priv->map_zoom, priv->center_rlat, priv->center_rlon);
3044  }  }
3045    
3046  #ifdef ENABLE_BALLOON  char * osm_gps_map_get_default_cache_directory(void)
 void  
 osm_gps_map_draw_balloon (OsmGpsMap *map, float latitude, float longitude,  
                           OsmGpsMapBalloonCallback cb, gpointer data)  
3047  {  {
3048      OsmGpsMapPrivate *priv;      return g_build_filename(
3049                            g_get_user_cache_dir(),
3050      /* remove and previously installed balloon */                          "osmgpsmap",
3051      osm_gps_map_clear_balloon (map);                          NULL);
3052    }
3053    
3054    void osm_gps_map_set_keyboard_shortcut(OsmGpsMap *map, OsmGpsMapKey_t key, guint keyval)
3055    {
3056      g_return_if_fail (OSM_IS_GPS_MAP (map));      g_return_if_fail (OSM_IS_GPS_MAP (map));
3057      priv = map->priv;      g_return_if_fail(key < OSM_GPS_MAP_KEY_MAX);
3058    
3059      priv->balloon.coo->rlat = deg2rad(latitude);      map->priv->keybindings[key] = keyval;
3060      priv->balloon.coo->rlon = deg2rad(longitude);      map->priv->keybindings_enabled = TRUE;
3061      priv->balloon.valid = TRUE;  }
3062    
3063      priv->balloon.cb = cb;  #ifdef ENABLE_OSD
     priv->balloon.data = data;  
3064    
3065      // this redraws the map  void
3066    osm_gps_map_redraw (OsmGpsMap *map)
3067    {
3068      osm_gps_map_map_redraw_idle(map);      osm_gps_map_map_redraw_idle(map);
3069  }  }
3070    
3071    osm_gps_map_osd_t *
3072    osm_gps_map_osd_get(OsmGpsMap *map)
3073    {
3074        g_return_val_if_fail (OSM_IS_GPS_MAP (map), NULL);
3075        return map->priv->osd;
3076    }
3077    
3078  void  void
3079  osm_gps_map_clear_balloon (OsmGpsMap *map)  osm_gps_map_register_osd(OsmGpsMap *map, osm_gps_map_osd_t *osd)
3080  {  {
3081      OsmGpsMapPrivate *priv;      OsmGpsMapPrivate *priv;
3082    
3083      g_return_if_fail (OSM_IS_GPS_MAP (map));      g_return_if_fail (OSM_IS_GPS_MAP (map));
3084    
3085      priv = map->priv;      priv = map->priv;
3086        g_return_if_fail (!priv->osd);
3087    
3088      priv->balloon.valid = FALSE;      priv->osd = osd;
   
     osm_gps_map_map_redraw_idle(map);  
3089  }  }
 #endif  
   
 #ifdef ENABLE_OSD  
 void osm_gps_map_osd_enable_gps (OsmGpsMap *map, OsmGpsMapOsdGpsCallback cb, gpointer data) {  
     OsmGpsMapPrivate *priv;  
3090    
3091      g_return_if_fail (OSM_IS_GPS_MAP (map));  void
3092      priv = map->priv;  osm_gps_map_repaint (OsmGpsMap *map)
3093    {
3094      priv->osd.cb = cb;      osm_gps_map_expose (GTK_WIDGET(map), NULL);
3095      priv->osd.data = data;  }
3096    
3097      /* this may have changed the state of the gps button */  coord_t *
3098      /* we thus re-render the overlay */  osm_gps_map_get_gps (OsmGpsMap *map)
3099      osm_gps_map_osd_render(priv);  {
3100        g_return_val_if_fail (OSM_IS_GPS_MAP (map), NULL);
3101    
3102      osm_gps_map_map_redraw_idle(map);      if(!map->priv->gps_valid)
3103            return NULL;
3104    
3105        return map->priv->gps;
3106  }  }
3107    
3108  #endif  #endif

Legend:
Removed from v.68  
changed lines
  Added in v.280