Diff of /trunk/src/geotoad.c

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

revision 199 by harbaum, Thu Nov 19 13:33:35 2009 UTC revision 221 by harbaum, Mon Nov 30 21:28:04 2009 UTC
# Line 19  Line 19 
19    
20  #include "gpxview.h"  #include "gpxview.h"
21    
22    #define __USE_GNU
23    #include <string.h>
24    
25  #include <fcntl.h>  #include <fcntl.h>
26  #include <sys/types.h>  #include <sys/types.h>
27  #include <sys/wait.h>  #include <sys/wait.h>
# Line 37  Line 40 
40    
41  #define BUFFER_SIZE  256  #define BUFFER_SIZE  256
42    
43    typedef enum {
44      GT_STATE_ILLEGAL = 0,
45      GT_STATE_STARTED,
46      GT_STATE_PREMATURE_END,
47      GT_STATE_SAVE_FOUND,
48    } gt_state_t;
49    
50  typedef struct {  typedef struct {
51    appdata_t *appdata;    appdata_t *appdata;
52    
53      GPtrArray *argv;
54      gchar *info, *color;
55      GMutex *update_mutex;
56      GCond *update_cond;
57    
58    GtkWidget *dialog;    gt_state_t state;
59    
60    char buf[BUFFER_SIZE];    GtkWidget *dialog;
   int bused;  
61    
62    /** gdk input tag for async IO */    long pid;
   gint stdout_tag, stderr_tag;  
   gint stdin_fd, stdout_fd, stderr_fd;  
63    
64    struct log_s {    struct log_s {
65      GtkTextBuffer *buffer;      GtkTextBuffer *buffer;
# Line 56  typedef struct { Line 68  typedef struct {
68    
69    GtkWidget *username, *password, *filename;    GtkWidget *username, *password, *filename;
70    GtkWidget *lat, *lon, *dst;    GtkWidget *lat, *lon, *dst;
71    
72      int use_cnt;
73    
74  } gt_context_t;  } gt_context_t;
75    
76    static void arg_free(gpointer data, gpointer user_data) {
77      if(data) g_free(data);
78    }
79    
80    static void context_free(gt_context_t *context) {
81      context->use_cnt--;
82    
83      if(context->use_cnt > 0)
84        printf("still in use by %d, keeping context\n", context->use_cnt);
85      else {
86        printf("freeing context\n");
87    
88        if(context->info) g_free(context->info);
89    
90        if(context->argv) {
91          g_ptr_array_foreach(context->argv, arg_free, NULL);
92          g_ptr_array_free (context->argv, TRUE);
93        }
94    
95        g_free(context);
96      }
97    }
98    
99  static void appendf(struct log_s *log, char *colname,  static void appendf(struct log_s *log, char *colname,
100                      const char *fmt, ...) {                      const char *fmt, ...) {
101    va_list args;    va_list args;
# Line 66  static void appendf(struct log_s *log, c Line 103  static void appendf(struct log_s *log, c
103    char *buf = g_strdup_vprintf(fmt, args);    char *buf = g_strdup_vprintf(fmt, args);
104    va_end( args );    va_end( args );
105    
106    printf("append: %s", buf);    //  printf("append: %s", buf);
107    
108    GtkTextTag *tag = NULL;    GtkTextTag *tag = NULL;
109    if(colname)    if(colname)
# Line 83  static void appendf(struct log_s *log, c Line 120  static void appendf(struct log_s *log, c
120    
121    g_free(buf);    g_free(buf);
122    
   gtk_text_buffer_get_end_iter(log->buffer, &end);  
123    gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(log->view),    gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(log->view),
124                                 &end, 0.0, FALSE, 0, 0);                                 &end, 0.0, TRUE, 1.0, 1.0);
125  }  }
126    
127  /* watch child process and receive events */  // This function receives a requst from a worker thread asking to
128  static void child_state_cb(GPid pid, gint status, gpointer data) {  // update the gui with the required info.
129    gt_context_t *context = (gt_context_t*)data;  gboolean cb_update_job(gt_context_t *context) {
130      if (context->info) {
131    puts("child state");  
132        /* check if client reports "saved to ..." */
133        if(strstr(context->info, "Saved to "))
134          context->state = GT_STATE_SAVE_FOUND;
135    
136    if(WIFEXITED(status)) {      appendf(&context->log, context->color, context->info);
137      printf("child exited with return code %d\n", WEXITSTATUS(status));  
138    } else      g_free(context->info);
139      printf("child failed\n");      context->info = NULL;
140      }
141    
142      // Indicate that the update is done
143      g_mutex_lock(context->update_mutex);
144      g_cond_signal(context->update_cond);
145      g_mutex_unlock(context->update_mutex);
146    
147      return FALSE;
148    }
149    
150    puts("gt exited");  // A helper function run in the job thread receiving the string that
151    // should be displayed in the textview.
152    void append_parentf(gt_context_t *context, char *colname,
153                 const char *fmt, ...) {
154      va_list args;
155      va_start( args, fmt );
156      context->info = g_strdup_vprintf(fmt, args);
157      va_end( args );
158    
159    appendf(&context->log, COLOR_SYSTEM, "GeoToad finished\n");    if(colname)
160        context->color = colname;
161      else
162        context->color = NULL;
163    
164    appendf(&context->log, COLOR_SYSTEM, "TODO: free context!!!\n");    // Lock mutex to make sure that we will receive the condition signal
165    //    printf("freeing context\n");    g_mutex_lock(context->update_mutex);
   //    g_free(context);  
166    
167    /* Reap child if needed. */    g_idle_add((GSourceFunc)cb_update_job, context);
168    waitpid (pid, NULL, WNOHANG);  
169      // Wait for cb_update_job to tell me that the update is done
170      g_cond_wait(context->update_cond, context->update_mutex);
171      g_mutex_unlock(context->update_mutex);
172  }  }
173    
174  static gboolean child_input_cb(GIOChannel *source,  /* custom version of popen to get access to the pid and to be able */
175                                 GIOCondition condition,  /* to slaughter the child process */
176                                 gpointer data) {  static FILE *gt_popen(gt_context_t *context, char **args,
177    gt_context_t *context = (gt_context_t*)data;                        const char *type, long *tid) {
178    int fd = g_io_channel_unix_get_fd(source);    int   p[2];
179    ssize_t bytes;    FILE *fp;
180    
181    g_assert(condition == G_IO_IN);    if (*type != 'r' && *type != 'w')
182        return NULL;
183    /* append to current buffer content */  
184    while( (bytes = read(fd, context->buf+context->bused,    if (pipe(p) < 0)
185                   sizeof(context->buf) - context->bused - 1)) > 0) {      return NULL;
186      context->bused += bytes;  
187      context->buf[context->bused]='\0';    if ((*tid = fork()) > 0) { /* then we are the parent */
188        if (*type == 'r') {
189          close(p[1]);
190          fp = fdopen(p[0], type);
191        } else {
192          close(p[0]);
193          fp = fdopen(p[1], type);
194        }
195    
196        return fp;
197      } else if (*tid == 0) {  /* we're the child */
198    
199      /* consume line by line */      /* make our thread id the process group leader */
200      gchar *ptr = context->buf;      setpgid(0, 0);
201    
202        if (*type == 'r') {
203          fflush(stdout);
204          fflush(stderr);
205          close(1);
206          if (dup(p[1]) < 0)
207            perror("dup of write side of pipe failed");
208          close(2);
209          if (dup(p[1]) < 0)
210            perror("dup of write side of pipe failed");
211        } else {
212          close(0);
213          if (dup(p[0]) < 0)
214            perror("dup of read side of pipe failed");
215        }
216    
217        close(p[0]); /* close since we dup()'ed what we needed */
218        close(p[1]);
219    
220      /* parse as long as the buffer contains a newline */      execve(args[0], args, NULL);
221      while( strchr(ptr, '\n') != NULL) {  
222        char *p = strchr(ptr, '\n');      /* this printf will actually be redirected through the pipe */
223        *p = '\0';      printf("Error: Failed to execute!\n");
224        exit(1);
225        char *color = NULL;    } else {         /* we're having major problems... */
226        if(strstr(ptr, "Saved to ") != NULL)      close(p[0]);
227          color = COLOR_OK;      close(p[1]);
228    
229        appendf(&context->log, color, "%s\n", ptr);      /* this printf will actually be redirected through the pipe??? No! */
230        printf("Error: Failed to fork!\n");
231      }
232    
233      return NULL;
234    }
235    
236        ptr = p+1;  // The thread entry point. It will do the job, send the data to the
237      }  // GUI and self destruct when it is done.
238    static gpointer thread_worker(gt_context_t *context)
239    {
240      FILE *fh;
241      GIOStatus status;
242      GError *error = NULL;
243      gsize length;
244      gsize terminator_pos;
245      gchar *str_return;
246    
247      fh = gt_popen(context, (char**)(context->argv->pdata),"r", &context->pid);
248      if(!fh) {
249        printf("fail free\n");
250        context_free(context);
251        //    g_thread_exit(NULL);
252        return NULL;
253      }
254    
255      /* move remaining bytes down the buffer */    /* the client is running */
256      memmove(context->buf, ptr, sizeof(context->buf)-(ptr-context->buf));    printf("client inc use_cnt\n");
257      context->bused -= ptr - context->buf;    context->use_cnt++;
258    
259      /* check if buffer is full but doesn't contain any newline */    /* switch to line buffered mode */
260      if(context->bused >= sizeof(context->buf)-1) {    if(setvbuf(fh, NULL, _IOLBF, 0))
261        printf("ERROR: reply buffer overflow\n");      perror("setvbuf(_IOLBF)");
262        context->bused = 0;  
263      }    GIOChannel *gh = g_io_channel_unix_new(fileno(fh));
264    
265      while( (status = g_io_channel_read_line(gh,
266                                              &str_return,
267                                              &length,
268                                              &terminator_pos,
269                                              &error)) == G_IO_STATUS_NORMAL) {
270        char *color = NULL;
271        if(strstr(str_return, "Saved to "))  color = COLOR_OK;
272        if(strcasestr(str_return, "error"))  color = COLOR_ERR;
273    
274        append_parentf(context, color, str_return);
275        g_free(str_return);
276    }    }
277    
278      g_io_channel_unref(gh);
279      pclose(fh);
280      append_parentf(context, COLOR_SYSTEM, "Job done!");
281    
282    return TRUE;    context_free(context);
283    
284      g_thread_exit(NULL);
285      return NULL;
286    }
287    
288    
289    static void arg_dsp(gpointer data, gpointer user_data) {
290      gt_context_t *context = (gt_context_t*)user_data;
291    
292      if(data)
293        appendf(&context->log, COLOR_SYSTEM, "%s\n", data);
294  }  }
295    
296  static void run(gt_context_t *context) {  static void run(gt_context_t *context) {
297    /* setup context */    GError *error = NULL;
298    context->bused = 0;    char str[8];
   context->stdout_tag = -1;  
   context->stderr_tag = -1;  
   context->stdin_fd  = -1;  
   context->stderr_fd = -1;  
   context->stderr_fd = -1;  
299    
300    /* build list of arguments to call geotoad */    /* build list of arguments to call geotoad */
301    GPtrArray *gt_argv = g_ptr_array_new();    context->argv = g_ptr_array_new();
302    g_ptr_array_add (gt_argv, GEOTOAD);    g_ptr_array_add (context->argv, g_strdup_printf(GEOTOAD));
303    g_ptr_array_add (gt_argv, "--distanceMax=1.0");    g_ascii_dtostr(str, sizeof(str), context->appdata->gt.distance);
304    g_ptr_array_add (gt_argv, "--output=gtoad.gpx");    g_ptr_array_add (context->argv,
305    g_ptr_array_add (gt_argv, "--password=winterblume");               g_strdup_printf("--distanceMax=%s", str));
306    g_ptr_array_add (gt_argv, "--queryType=coord");    g_ptr_array_add (context->argv,
307    g_ptr_array_add (gt_argv, "--user=Tantil");               g_strdup_printf("--output=%s", context->appdata->gt.filename));
308      g_ptr_array_add (context->argv,
309                 g_strdup_printf("--password=%s", context->appdata->gt.password));
310      g_ptr_array_add (context->argv,
311                 g_strdup_printf("--queryType=coord"));
312      g_ptr_array_add (context->argv,
313                 g_strdup_printf("--user=%s", context->appdata->username));
314    
315    /* check if we need to add proxy config */    /* check if we need to add proxy config */
316    char *proxy = NULL;    char *proxy = NULL;
317    
318    if(context->appdata->proxy && context->appdata->proxy->host) {    if(context->appdata->proxy && context->appdata->proxy->host) {
319      if(context->appdata->proxy->use_authentication &&      if(context->appdata->proxy->use_authentication &&
320         context->appdata->proxy->authentication_user &&         context->appdata->proxy->authentication_user &&
321         context->appdata->proxy->authentication_password)         context->appdata->proxy->authentication_password)
322        proxy = g_strdup_printf("--proxy=http://%s:%s@%s:%d",        proxy = g_strdup_printf("--proxy=http://%s:%s@%s:%d",
323                                context->appdata->proxy->authentication_user,                                context->appdata->proxy->authentication_user,
324                                context->appdata->proxy->authentication_password,                                context->appdata->proxy->authentication_password,
325                                context->appdata->proxy->host,                                context->appdata->proxy->host,
326                                context->appdata->proxy->port);                                context->appdata->proxy->port);
327      else      else
328        proxy = g_strdup_printf("--proxy=http://%s:%d",        proxy = g_strdup_printf("--proxy=http://%s:%d",
329                                context->appdata->proxy->host,                                context->appdata->proxy->host,
330                                context->appdata->proxy->port);                                context->appdata->proxy->port);
331    
332      appendf(&context->log, COLOR_SYSTEM, "Using proxy: %s\n", proxy);    } else {
333      g_ptr_array_add (gt_argv, proxy);      /* use environment settings if preset (for scratchbox) */
334        const char *proxy_env = g_getenv("http_proxy");
335        if(proxy_env)
336          proxy = g_strdup_printf("--proxy=%s", proxy_env);
337    }    }
338    
339      if(proxy)
340        g_ptr_array_add (context->argv, proxy);
341    
342    g_ptr_array_add (gt_argv, "N49 00.000 E008 23.000");    /* convert coordinates into simple ascii format */
343    g_ptr_array_add (gt_argv, NULL);    char n = (context->appdata->gt.lat >= 0)?'N':'S';
344      char e = (context->appdata->gt.lon >= 0)?'E':'W';
345    GError *error=NULL;    float lat = fabs(context->appdata->gt.lat);
346    GPid pid;    float lon = fabs(context->appdata->gt.lon);
347    GSource *gt_watch;    float lat_mint, lat_int, lat_frac = modff(lat, &lat_int);
348      float lon_mint, lon_int, lon_frac = modff(lon, &lon_int);
349    if (!g_spawn_async_with_pipes (NULL, /* CWD */    lat_frac = modff(lat_frac*60.0, &lat_mint);
350                                   (char **) gt_argv->pdata, /* argv */    lon_frac = modff(lon_frac*60.0, &lon_mint);
351                                   NULL, /* envp */  
352                                   G_SPAWN_DO_NOT_REAP_CHILD, /* flags */    g_ptr_array_add (context->argv,
353                                   NULL, /* child setup */             g_strdup_printf("%c%02u %02u.%03u %c%03u %02u.%03u",
354                                   NULL, /* user data */             n, (int)lat_int, (int)lat_mint, (int)(lat_frac*1000.0+0.5),
355                                   &pid,             e, (int)lon_int, (int)lon_mint, (int)(lon_frac*1000.0+0.5)));
356                                   &context->stdin_fd,  
357                                   &context->stdout_fd,    g_ptr_array_add (context->argv, NULL);
358                                   &context->stderr_fd,  
359                                   &error)) {    /* show all entries */
360      g_ptr_array_free(gt_argv, TRUE);    g_ptr_array_foreach(context->argv, arg_dsp, context);
361      if(proxy) g_free(proxy);  
362      appendf(&context->log, COLOR_ERR,    g_thread_create((GThreadFunc)thread_worker, context, FALSE, &error);
363              _("GeoToad failed to start!\n%s\n"), error->message);    if (error) {
364        appendf(&context->log, COLOR_ERR, "Error: %s\n", error->message);
365      g_error_free(error);      g_error_free(error);
     return;  
366    }    }
   
   g_ptr_array_free (gt_argv, TRUE);  
   if(proxy) g_free(proxy);  
   
   gt_watch = g_child_watch_source_new(pid);  
   g_source_set_callback(gt_watch, (GSourceFunc) child_state_cb, context, NULL);  
   
   g_source_attach(gt_watch, NULL);  
   g_source_unref(gt_watch);  
   
   /* make nonblocking */  
   if(fcntl(context->stdout_fd, F_SETFL, O_NONBLOCK) == -1)  
     perror("fcntl failed");  
   
   if(fcntl(context->stderr_fd, F_SETFL, O_NONBLOCK) == -1)  
     perror("fcntl failed");  
   
   GIOChannel *ioc = g_io_channel_unix_new(context->stdout_fd);  
   g_io_channel_set_close_on_unref (ioc, TRUE);  
   g_io_channel_set_encoding (ioc, NULL, NULL);  
   g_io_add_watch(ioc, G_IO_IN,  child_input_cb, context);  
   g_io_channel_unref(ioc);  
   
   //  ioc = g_io_channel_unix_new(context->stderr_fd);  
   //  g_io_add_watch(ioc, G_IO_IN,  child_input_cb, context);  
   //  g_io_channel_unref(ioc);  
367  }  }
368    
369  /* show text window and display output of running geotoad */  /* show text window and display output of running geotoad */
# Line 384  static gboolean gui_setup(gt_context_t * Line 502  static gboolean gui_setup(gt_context_t *
502    gtk_box_pack_start_defaults(GTK_BOX(ihbox), context->lat);    gtk_box_pack_start_defaults(GTK_BOX(ihbox), context->lat);
503    context->lon = lon_entry_new(appdata->gt.lon);    context->lon = lon_entry_new(appdata->gt.lon);
504    gtk_box_pack_start_defaults(GTK_BOX(ihbox), context->lon);    gtk_box_pack_start_defaults(GTK_BOX(ihbox), context->lon);
505      GtkWidget *popup = preset_coordinate_picker(appdata, context->lat, context->lon);
506      gtk_box_pack_start_defaults(GTK_BOX(ihbox), popup);
507    gtk_box_pack_start_defaults(GTK_BOX(vbox), ihbox);    gtk_box_pack_start_defaults(GTK_BOX(vbox), ihbox);
508    context->dst = dist_entry_new(appdata->gt.distance, appdata->imperial);    float dst = appdata->gt.distance;  // distance is given in kilometers
509      if(appdata->imperial) dst /= 1.609344;
510      context->dst = dist_entry_new(dst, appdata->imperial);
511    gtk_box_pack_start_defaults(GTK_BOX(vbox), context->dst);    gtk_box_pack_start_defaults(GTK_BOX(vbox), context->dst);
512    gtk_box_pack_start_defaults(GTK_BOX(hbox), vbox);    gtk_box_pack_start_defaults(GTK_BOX(hbox), vbox);
513    
# Line 419  static gboolean gui_setup(gt_context_t * Line 541  static gboolean gui_setup(gt_context_t *
541    gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);    gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
542    
543    vbox = gtk_vbox_new(FALSE, 0);    vbox = gtk_vbox_new(FALSE, 0);
544  #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)    context->username = entry_new();
545    context->username = gtk_entry_new();    context->password = entry_new();
   context->password = gtk_entry_new();  
 #else  
   context->username = hildon_entry_new(HILDON_SIZE_AUTO);  
   hildon_gtk_entry_set_input_mode(GTK_ENTRY(context->username),  
                                   HILDON_GTK_INPUT_MODE_FULL);  
   context->password = hildon_entry_new(HILDON_SIZE_AUTO);  
   hildon_gtk_entry_set_input_mode(GTK_ENTRY(context->password),  
                                   HILDON_GTK_INPUT_MODE_FULL);  
 #endif  
546    gtk_entry_set_visibility(GTK_ENTRY(context->password), FALSE);    gtk_entry_set_visibility(GTK_ENTRY(context->password), FALSE);
547    
548    /* set saved defaults */    /* set saved defaults */
549    if(appdata->gt.username)    if(appdata->username)
550      gtk_entry_set_text(GTK_ENTRY(context->username),      gtk_entry_set_text(GTK_ENTRY(context->username),
551                         appdata->gt.username);                         appdata->username);
552    
553    if(appdata->gt.password)    if(appdata->gt.password)
554      gtk_entry_set_text(GTK_ENTRY(context->password),      gtk_entry_set_text(GTK_ENTRY(context->password),
# Line 453  static gboolean gui_setup(gt_context_t * Line 566  static gboolean gui_setup(gt_context_t *
566    
567    if(gtk_dialog_run(GTK_DIALOG(context->dialog)) == GTK_RESPONSE_OK) {    if(gtk_dialog_run(GTK_DIALOG(context->dialog)) == GTK_RESPONSE_OK) {
568    
569        /* parse coordinates */
570        appdata->gt.lat = lat_entry_get(context->lat);
571        appdata->gt.lon = lon_entry_get(context->lon);
572    
573      /* save values */      /* save values */
574      if(appdata->gt.username) g_free(appdata->gt.username);      if(appdata->username) g_free(appdata->username);
575      appdata->gt.username =      appdata->username =
576        g_strdup(gtk_entry_get_text(GTK_ENTRY(context->username)));        g_strdup(gtk_entry_get_text(GTK_ENTRY(context->username)));
577    
578      if(appdata->gt.password) g_free(appdata->gt.password);      if(appdata->gt.password) g_free(appdata->gt.password);
# Line 466  static gboolean gui_setup(gt_context_t * Line 583  static gboolean gui_setup(gt_context_t *
583      appdata->gt.filename =      appdata->gt.filename =
584        g_strdup(gtk_label_get_text(GTK_LABEL(context->filename)));        g_strdup(gtk_label_get_text(GTK_LABEL(context->filename)));
585    
586      ok = TRUE;      /* get distance in kilometers */
587        appdata->gt.distance = dist_get(context->dst, FALSE);
588    
589    
590        /* check for valid entries */
591        if(isnan(appdata->gt.lat) || isnan(appdata->gt.lon) ||
592           isnan(appdata->gt.distance) || !appdata->gt.filename ||
593           !appdata->username || !appdata->gt.password)
594          errorf(_("The GeoToad setup is not complete."));
595        else
596          ok = TRUE;
597    }    }
598    
599    gtk_widget_destroy(context->dialog);    gtk_widget_destroy(context->dialog);
# Line 483  void geotoad(appdata_t *appdata) { Line 610  void geotoad(appdata_t *appdata) {
610    
611    gt_context_t *context = g_new0(gt_context_t, 1);    gt_context_t *context = g_new0(gt_context_t, 1);
612    context->appdata = appdata;    context->appdata = appdata;
613      context->use_cnt++;          // parent still uses this
614    
615    printf("geoToad\n");    context->update_mutex = g_mutex_new();
616      context->update_cond = g_cond_new();
617    
618    if(gui_setup(context))    if(gui_setup(context))
619      gui_run(context);      gui_run(context);
620    
621      /* continue to process if something has actually been saved */
622      if(context->state == GT_STATE_SAVE_FOUND) {
623        /* download seems to be successful. Make sure the GUI is */
624        /* updated if required */
625    
626        gpx_t **gpx = &(appdata->gpx);
627        while(*gpx && strcmp((*gpx)->filename, appdata->gt.filename))
628          gpx = &(*gpx)->next;
629    
630        if(*gpx) {
631          /* return main GUI to GPX list */
632    
633    #ifdef USE_BREAD_CRUMB_TRAIL
634          while(appdata->cur_gpx)
635            hildon_bread_crumb_trail_pop(HILDON_BREAD_CRUMB_TRAIL(appdata->bct));
636    #elif defined(BCT)
637          while(appdata->cur_gpx)
638            bct_pop(appdata->bct);
639    #else
640          HildonWindowStack *stack = hildon_window_stack_get_default();
641          gint num = hildon_window_stack_size(stack)-1;
642          while(num--) {
643            GtkWidget *top = hildon_window_stack_peek(stack);
644            gtk_widget_destroy(top);
645          }
646    #endif
647    
648          GtkTreeIter iter;
649          g_assert(gpxlist_find(appdata, &iter, *gpx));
650    
651          gpx_t *next = (*gpx)->next;
652    
653          gpx_free(*gpx);
654          *gpx = gpx_parse(NULL, appdata->gt.filename, appdata->username);
655          (*gpx)->next = next;
656    
657          /* update gpxlist */
658          gpxlist_set(appdata->gpxstore, &iter, *gpx);
659    
660          /* select that row */
661          GtkTreeSelection *selection =
662            gtk_tree_view_get_selection(GTK_TREE_VIEW(appdata->gpxview));
663          gtk_tree_selection_select_iter(selection, &iter);
664          GtkTreePath *path =
665            gtk_tree_model_get_path(GTK_TREE_MODEL(appdata->gpxstore), &iter);
666          gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(appdata->gpxview),
667                                       path, NULL, TRUE, 0.0, 0.0);
668          gtk_tree_path_free(path);
669    
670        } else
671          printf("GPX file not imported\n");
672      }
673    
674      printf("main context free\n");
675      context_free(context);
676  }  }
677    
678  gboolean geotoad_available(void) {  gboolean geotoad_available(void) {

Legend:
Removed from v.199  
changed lines
  Added in v.221