Diff of /trunk/src/geotoad.c

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

revision 194 by harbaum, Wed Nov 18 11:40:31 2009 UTC revision 233 by harbaum, Wed Dec 9 19:45:36 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>
28  #include <errno.h>  #include <errno.h>
29    #include <math.h>
30    
31    #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR >= 5)
32    #include <hildon/hildon-entry.h>
33    #endif
34    
35  #define COLOR_ERR  "red"  #define GEOTOAD "/usr/bin/geotoad"
 #define COLOR_OK   "darkgreen"  
36    
37  #define BUFFER_SIZE  1500  #define COLOR_ERR     "red"
38    #define COLOR_OK      "darkgreen"
39    #define COLOR_SYSTEM  "darkblue"
40    
41    #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    char buf[BUFFER_SIZE];    gt_state_t state;
   int bused;  
59    
60    /** gdk input tag for async IO */    GtkWidget *dialog;
61    gint stdout_tag, stderr_tag;  
62    gint stdin_fd, stdout_fd, stderr_fd;    long pid;
63    
64    struct log_s {    struct log_s {
65      GtkTextBuffer *buffer;      GtkTextBuffer *buffer;
66      GtkWidget *view;      GtkWidget *view;
67    } log;    } log;
68    
69      GtkWidget *username, *password;
70      GtkWidget *lat, *lon, *dst;
71      char *filename;
72    
73      int use_cnt;
74    
75  } gt_context_t;  } gt_context_t;
76    
77    static void arg_free(gpointer data, gpointer user_data) {
78      if(data) g_free(data);
79    }
80    
81    static void context_free(gt_context_t *context) {
82      context->use_cnt--;
83    
84      if(context->use_cnt > 0)
85        printf("still in use by %d, keeping context\n", context->use_cnt);
86      else {
87        printf("freeing context\n");
88    
89        if(context->info) g_free(context->info);
90    
91        if(context->argv) {
92          g_ptr_array_foreach(context->argv, arg_free, NULL);
93          g_ptr_array_free (context->argv, TRUE);
94        }
95    
96        if(context->filename) g_free(context->filename);
97    
98        g_free(context);
99      }
100    }
101    
102  static void appendf(struct log_s *log, char *colname,  static void appendf(struct log_s *log, char *colname,
103                      const char *fmt, ...) {                      const char *fmt, ...) {
104    va_list args;    va_list args;
# Line 53  static void appendf(struct log_s *log, c Line 106  static void appendf(struct log_s *log, c
106    char *buf = g_strdup_vprintf(fmt, args);    char *buf = g_strdup_vprintf(fmt, args);
107    va_end( args );    va_end( args );
108    
109      //  printf("append: %s", buf);
110    
111    GtkTextTag *tag = NULL;    GtkTextTag *tag = NULL;
112    if(colname)    if(colname)
113      tag = gtk_text_buffer_create_tag(log->buffer, NULL,      tag = gtk_text_buffer_create_tag(log->buffer, NULL,
# Line 69  static void appendf(struct log_s *log, c Line 124  static void appendf(struct log_s *log, c
124    g_free(buf);    g_free(buf);
125    
126    gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(log->view),    gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(log->view),
127                                 &end, 0.0, FALSE, 0, 0);                                 &end, 0.0, TRUE, 1.0, 1.0);
128  }  }
129    
130  /* watch child process and receive events */  // This function receives a requst from a worker thread asking to
131  static void child_state_cb(GPid pid, gint status, gpointer data) {  // update the gui with the required info.
132    gboolean cb_update_job(gt_context_t *context) {
133    puts("child state");    if (context->info) {
134    
135    if(WIFEXITED(status)) {      /* check if client reports "saved to ..." */
136      printf("child exited with return code %d\n", WEXITSTATUS(status));      if(strstr(context->info, "Saved to "))
137    } else        context->state = GT_STATE_SAVE_FOUND;
     printf("child failed\n");  
   
   puts("gt exited");  
138    
139    /* Reap child if needed. */      appendf(&context->log, context->color, context->info);
140    waitpid (pid, NULL, WNOHANG);  
141        g_free(context->info);
142        context->info = NULL;
143      }
144    
145      // Indicate that the update is done
146      g_mutex_lock(context->update_mutex);
147      g_cond_signal(context->update_cond);
148      g_mutex_unlock(context->update_mutex);
149    
150      return FALSE;
151  }  }
152    
153  static void child_input_cb(gpointer data, int fd, GdkInputCondition cond) {  // A helper function run in the job thread receiving the string that
154    gt_context_t *context = (gt_context_t*)data;  // should be displayed in the textview.
155    void append_parentf(gt_context_t *context, char *colname,
156                 const char *fmt, ...) {
157      va_list args;
158      va_start( args, fmt );
159      context->info = g_strdup_vprintf(fmt, args);
160      va_end( args );
161    
162    ssize_t bytes;    if(colname)
163    int errnosave=0;      context->color = colname;
164      else
165        context->color = NULL;
166    
167    if(cond != GDK_INPUT_READ) {    // Lock mutex to make sure that we will receive the condition signal
168      puts("fixme");    g_mutex_lock(context->update_mutex);
     return;  
   }  
169    
170    /* append to current buffer content */    g_idle_add((GSourceFunc)cb_update_job, context);
171    while( (bytes = read(fd, context->buf+context->bused,  
172                   sizeof(context->buf) - context->bused - 1)) > 0) {    // Wait for cb_update_job to tell me that the update is done
173      context->bused += bytes;    g_cond_wait(context->update_cond, context->update_mutex);
174      context->buf[context->bused]='\0';    g_mutex_unlock(context->update_mutex);
175    }
176    
177      /* consume line by line */  /* custom version of popen to get access to the pid and to be able */
178      gchar *ptr = context->buf;  /* to slaughter the child process */
179    static FILE *gt_popen(gt_context_t *context, char **args,
180                          const char *type, long *tid) {
181      int   p[2];
182      FILE *fp;
183    
184      if (*type != 'r' && *type != 'w')
185        return NULL;
186    
187      if (pipe(p) < 0)
188        return NULL;
189    
190      if ((*tid = fork()) > 0) { /* then we are the parent */
191        if (*type == 'r') {
192          close(p[1]);
193          fp = fdopen(p[0], type);
194        } else {
195          close(p[0]);
196          fp = fdopen(p[1], type);
197        }
198    
199      /* parse as long as the buffer contains a newline */      return fp;
200      while( strchr(ptr, '\n') != NULL) {    } else if (*tid == 0) {  /* we're the child */
       char *p = strchr(ptr, '\n');  
       *p = '\0';  
201    
202        appendf(&context->log, NULL, "%s\n", ptr);      /* make our thread id the process group leader */
203        setpgid(0, 0);
204        ptr = p+1;  
205        if (*type == 'r') {
206          fflush(stdout);
207          fflush(stderr);
208          close(1);
209          if (dup(p[1]) < 0)
210            perror("dup of write side of pipe failed");
211          close(2);
212          if (dup(p[1]) < 0)
213            perror("dup of write side of pipe failed");
214        } else {
215          close(0);
216          if (dup(p[0]) < 0)
217            perror("dup of read side of pipe failed");
218      }      }
219    
220        close(p[0]); /* close since we dup()'ed what we needed */
221        close(p[1]);
222    
223        execve(args[0], args, NULL);
224    
225        /* this printf will actually be redirected through the pipe */
226        printf("Error: Failed to execute!\n");
227        exit(1);
228      } else {         /* we're having major problems... */
229        close(p[0]);
230        close(p[1]);
231    
232      /* move remaining bytes down the buffer */      /* this printf will actually be redirected through the pipe??? No! */
233      memmove(context->buf, ptr, sizeof(context->buf)-(ptr-context->buf));      printf("Error: Failed to fork!\n");
     context->bused -= ptr - context->buf;  
   
     /* check if buffer is full but doesn't contain any newline */  
     if(context->bused >= sizeof(context->buf)-1) {  
       printf("ERROR: reply buffer overflow\n");  
       context->bused = 0;  
     }  
234    }    }
235    
236      return NULL;
237    }
238    
239    /* save errno from read */  // The thread entry point. It will do the job, send the data to the
240    errnosave=errno;  // GUI and self destruct when it is done.
241    static gpointer thread_worker(gt_context_t *context)
242    {
243      FILE *fh;
244      GIOStatus status;
245      GError *error = NULL;
246      gsize length;
247      gsize terminator_pos;
248      gchar *str_return;
249    
250      fh = gt_popen(context, (char**)(context->argv->pdata),"r", &context->pid);
251      if(!fh) {
252        printf("fail free\n");
253        context_free(context);
254        //    g_thread_exit(NULL);
255        return NULL;
256      }
257    
258    if(errnosave != EAGAIN && errnosave != 0) {    /* the client is running */
259      /* we probably hit EOF */    printf("client inc use_cnt\n");
260      puts("removing io");    context->use_cnt++;
261    
262      /* switch to line buffered mode */
263      if(setvbuf(fh, NULL, _IOLBF, 0))
264        perror("setvbuf(_IOLBF)");
265    
266      GIOChannel *gh = g_io_channel_unix_new(fileno(fh));
267    
268      // TODO: fixme, make sure process is dead! kill it otherwise, but dont    while( (status = g_io_channel_read_line(gh,
269      // issue an disconnect(NULL) !!!!                                            &str_return,
270                                              &length,
271                                              &terminator_pos,
272                                              &error)) == G_IO_STATUS_NORMAL) {
273        char *color = NULL;
274        if(strstr(str_return, "Saved to "))  color = COLOR_OK;
275        if(strcasestr(str_return, "error"))  color = COLOR_ERR;
276    
277      gdk_input_remove(context->stdout_tag);      append_parentf(context, color, str_return);
278      gdk_input_remove(context->stderr_tag);      g_free(str_return);
279      }
280    
281      g_io_channel_unref(gh);
282      pclose(fh);
283      append_parentf(context, COLOR_SYSTEM, "Job done!");
284    
285      context_free(context);
286    
287      g_thread_exit(NULL);
288      return NULL;
289    }
290    
     appendf(&context->log, COLOR_OK, "GeoToad finished\n");  
291    
292      appendf(&context->log, COLOR_ERR, "TODO: free context!!!\n");  static void arg_dsp(gpointer data, gpointer user_data) {
293      //    printf("freeing context\n");    gt_context_t *context = (gt_context_t*)user_data;
294      //    g_free(context);  
295    }    if(data)
296        appendf(&context->log, COLOR_SYSTEM, "%s\n", data);
297  }  }
298    
299  static void run(gt_context_t *context) {  static void run(gt_context_t *context) {
300    /* setup context */    GError *error = NULL;
301    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;  
302    
303    /* build list of arguments to call geotoad */    /* build list of arguments to call geotoad */
304    GPtrArray *gt_argv = g_ptr_array_new();    context->argv = g_ptr_array_new();
305    g_ptr_array_add (gt_argv, "/usr/bin/geotoad");    g_ptr_array_add (context->argv, g_strdup_printf(GEOTOAD));
306    g_ptr_array_add (gt_argv, "--distanceMax=1.5");    g_ascii_dtostr(str, sizeof(str), context->appdata->gt.distance);
307    g_ptr_array_add (gt_argv, "--output=gtoad.gpx");    g_ptr_array_add (context->argv,
308    g_ptr_array_add (gt_argv, "--password=winterblume");               g_strdup_printf("--distanceMax=%s", str));
309    g_ptr_array_add (gt_argv, "--queryType=coord");    g_ptr_array_add (context->argv,
310    g_ptr_array_add (gt_argv, "--user=Tantil");               g_strdup_printf("--output=%s", context->appdata->gt.filename));
311      g_ptr_array_add (context->argv,
312                 g_strdup_printf("--password=%s", context->appdata->gt.password));
313      g_ptr_array_add (context->argv,
314                 g_strdup_printf("--queryType=coord"));
315      g_ptr_array_add (context->argv,
316                 g_strdup_printf("--user=%s", context->appdata->username));
317    
318    /* check if we need to add proxy config */    /* check if we need to add proxy config */
319    char *proxy = NULL;    char *proxy = NULL;
320    
321    if(context->appdata->proxy && context->appdata->proxy->host) {    if(context->appdata->proxy && context->appdata->proxy->host) {
322      if(context->appdata->proxy->use_authentication &&      if(context->appdata->proxy->use_authentication &&
323         context->appdata->proxy->authentication_user &&         context->appdata->proxy->authentication_user &&
324         context->appdata->proxy->authentication_password)         context->appdata->proxy->authentication_password)
325        proxy = g_strdup_printf("--proxy=http://%s:%s@%s:%d",        proxy = g_strdup_printf("--proxy=http://%s:%s@%s:%d",
326                                context->appdata->proxy->authentication_user,                                context->appdata->proxy->authentication_user,
327                                context->appdata->proxy->authentication_password,                                context->appdata->proxy->authentication_password,
328                                context->appdata->proxy->host,                                context->appdata->proxy->host,
329                                context->appdata->proxy->port);                                context->appdata->proxy->port);
330      else      else
331        proxy = g_strdup_printf("--proxy=http://%s:%d",        proxy = g_strdup_printf("--proxy=http://%s:%d",
332                                context->appdata->proxy->host,                                context->appdata->proxy->host,
333                                context->appdata->proxy->port);                                context->appdata->proxy->port);
334    
335      appendf(&context->log, COLOR_OK, "Using proxy: %s\n", proxy);    } else {
336      g_ptr_array_add (gt_argv, proxy);      /* use environment settings if preset (for scratchbox) */
337        const char *proxy_env = g_getenv("http_proxy");
338        if(proxy_env)
339          proxy = g_strdup_printf("--proxy=%s", proxy_env);
340    }    }
341    
342      if(proxy)
343        g_ptr_array_add (context->argv, proxy);
344    
345      /* convert coordinates into simple ascii format */
346    g_ptr_array_add (gt_argv, "N49 00.000 E008 23.000");    char n = (context->appdata->gt.lat >= 0)?'N':'S';
347    g_ptr_array_add (gt_argv, NULL);    char e = (context->appdata->gt.lon >= 0)?'E':'W';
348      float lat = fabs(context->appdata->gt.lat);
349    GError *error=NULL;    float lon = fabs(context->appdata->gt.lon);
350    GPid pid;    float lat_mint, lat_int, lat_frac = modff(lat, &lat_int);
351    GSource *gt_watch;    float lon_mint, lon_int, lon_frac = modff(lon, &lon_int);
352      lat_frac = modff(lat_frac*60.0, &lat_mint);
353    if (!g_spawn_async_with_pipes (NULL, /* CWD */    lon_frac = modff(lon_frac*60.0, &lon_mint);
354                                   (char **) gt_argv->pdata, /* argv */  
355                                   NULL, /* envp */    g_ptr_array_add (context->argv,
356                                   G_SPAWN_DO_NOT_REAP_CHILD, /* flags */             g_strdup_printf("%c%02u %02u.%03u %c%03u %02u.%03u",
357                                   NULL, /* child setup */             n, (int)lat_int, (int)lat_mint, (int)(lat_frac*1000.0+0.5),
358                                   NULL, /* user data */             e, (int)lon_int, (int)lon_mint, (int)(lon_frac*1000.0+0.5)));
359                                   &pid,  
360                                   &context->stdin_fd,    g_ptr_array_add (context->argv, NULL);
361                                   &context->stdout_fd,  
362                                   &context->stderr_fd,    /* show all entries */
363                                   &error)) {    g_ptr_array_foreach(context->argv, arg_dsp, context);
364      g_ptr_array_free(gt_argv, TRUE);  
365      if(proxy) g_free(proxy);    g_thread_create((GThreadFunc)thread_worker, context, FALSE, &error);
366      appendf(&context->log, COLOR_ERR,    if (error) {
367              _("GeoToad failed to start: '%s'"), error->message);      appendf(&context->log, COLOR_ERR, "Error: %s\n", error->message);
368      g_error_free(error);      g_error_free(error);
     return;  
369    }    }
   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, NULL, 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");  
   
   /* use gdk to monitor read end of stdout */  
   context->stdout_tag = gdk_input_add(context->stdout_fd,  
                   GDK_INPUT_READ, child_input_cb, context);  
   context->stderr_tag = gdk_input_add(context->stderr_fd,  
                   GDK_INPUT_READ, child_input_cb, context);  
370  }  }
371    
372  void geotoad(appdata_t *appdata) {  /* show text window and display output of running geotoad */
373    gt_context_t *context = g_new0(gt_context_t, 1);  static void gui_run(gt_context_t *context) {
374    context->appdata = appdata;    GtkWidget *dialog = gtk_dialog_new_with_buttons(_("GeoToad - Run"),
375                              GTK_WINDOW(context->appdata->window),
   printf("geoToad\n");  
   
   GtkWidget *dialog = gtk_dialog_new_with_buttons(_("GeoToad"),  
                           GTK_WINDOW(appdata->window),  
376                            GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,                            GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
377                            GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,                            GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
378                            NULL);                            NULL);
# Line 286  void geotoad(appdata_t *appdata) { Line 414  void geotoad(appdata_t *appdata) {
414    
415    gtk_widget_show_all(dialog);    gtk_widget_show_all(dialog);
416    
417    appendf(&context->log, COLOR_OK, "Running GeoToad\n");    appendf(&context->log, COLOR_SYSTEM, "Running GeoToad\n");
418    run(context);    run(context);
419    
420    gtk_dialog_run(GTK_DIALOG(dialog));    gtk_dialog_run(GTK_DIALOG(dialog));
421    
422    gtk_widget_destroy(dialog);    gtk_widget_destroy(dialog);
423  }  }
424    
425    static void table_attach(GtkWidget *table, GtkWidget *child, int left, int top) {
426      gtk_table_attach_defaults(GTK_TABLE(table), child, left, left+1, top, top+1);
427    }
428    
429    
430    static gboolean gui_setup(gt_context_t *context) {
431      appdata_t *appdata = context->appdata;
432      gboolean ok = FALSE;
433    
434      /* if no filename has been setup yet, create one */
435      if(!appdata->gt.filename && appdata->path) {
436        printf("creating path\n");
437        appdata->gt.filename =
438          g_strdup_printf("%s/gtoad.gpx", appdata->path);
439      }
440    
441      if(appdata->gt.filename)
442        context->filename = g_strdup(appdata->gt.filename);
443    
444      context->dialog = gtk_dialog_new_with_buttons(_("GeoToad - Setup"),
445                            GTK_WINDOW(appdata->window),
446                            GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
447                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
448                            GTK_STOCK_OK,     GTK_RESPONSE_OK,
449                            NULL);
450    
451      GtkWidget *table = gtk_table_new(5, 2, FALSE);
452    
453      /* ------------------- Coordinates ------------------------- */
454    
455      table_attach(table, left_label_new(_("Position:")), 0, 0);
456      table_attach(table, left_label_new(_("Distance:")), 0, 1);
457    
458      /* setup default positions */
459      pos_t *refpos = get_pos(appdata);
460      if((isnan(appdata->gt.lat) || isnan(appdata->gt.lat)) && refpos) {
461        appdata->gt.lat = refpos->lat;
462        appdata->gt.lon = refpos->lon;
463      }
464    
465      GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
466      context->lat = lat_entry_new(appdata->gt.lat);
467      gtk_box_pack_start_defaults(GTK_BOX(hbox), context->lat);
468      context->lon = lon_entry_new(appdata->gt.lon);
469      gtk_box_pack_start_defaults(GTK_BOX(hbox), context->lon);
470      GtkWidget *popup = preset_coordinate_picker(appdata, context->lat, context->lon);
471      gtk_box_pack_start_defaults(GTK_BOX(hbox), popup);
472      table_attach(table, hbox, 1, 0);
473    
474      float dst = appdata->gt.distance;  // distance is given in kilometers
475      if(appdata->imperial) dst /= 1.609344;
476      context->dst = dist_entry_new(dst, appdata->imperial);
477      table_attach(table, context->dst, 1, 1);
478    
479      /* ------------------- Username/Password ------------------------- */
480      table_attach(table, left_label_new(_("Username:")), 0, 2);
481      table_attach(table, left_label_new(_("Password:")), 0, 3);
482    
483      context->username = entry_new();
484      context->password = entry_new();
485      gtk_entry_set_visibility(GTK_ENTRY(context->password), FALSE);
486    
487      /* set saved defaults */
488      if(appdata->username)
489        gtk_entry_set_text(GTK_ENTRY(context->username),
490                           appdata->username);
491    
492      if(appdata->gt.password)
493        gtk_entry_set_text(GTK_ENTRY(context->password),
494                           appdata->gt.password);
495    
496      table_attach(table, context->username, 1, 2);
497      table_attach(table, context->password, 1, 3);
498    
499      /* ------------------- file name ------------------------- */
500      gtk_table_attach_defaults(GTK_TABLE(table),
501                export_file(_("Save GPX file"), &context->filename),
502                   0, 2, 4, 5);
503    
504      /* ---------------------------------------------------------------- */
505      gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(context->dialog)->vbox),
506                                  table);
507    
508      gtk_dialog_set_default_response(GTK_DIALOG(context->dialog),
509                                      GTK_RESPONSE_OK);
510    
511      gtk_widget_show_all(context->dialog);
512    
513      if(gtk_dialog_run(GTK_DIALOG(context->dialog)) == GTK_RESPONSE_OK) {
514    
515        /* parse coordinates */
516        appdata->gt.lat = lat_entry_get(context->lat);
517        appdata->gt.lon = lon_entry_get(context->lon);
518    
519        /* save values */
520        if(appdata->username) g_free(appdata->username);
521        appdata->username =
522          g_strdup(gtk_entry_get_text(GTK_ENTRY(context->username)));
523    
524        if(appdata->gt.password) g_free(appdata->gt.password);
525        appdata->gt.password =
526          g_strdup(gtk_entry_get_text(GTK_ENTRY(context->password)));
527    
528        if(appdata->gt.filename) g_free(appdata->gt.filename);
529        if(context->filename)
530          appdata->gt.filename = g_strdup(context->filename);
531    
532        /* get distance in kilometers */
533        appdata->gt.distance = dist_entry_get(context->dst, FALSE);
534    
535    
536        /* check for valid entries */
537        if(isnan(appdata->gt.lat) || isnan(appdata->gt.lon) ||
538           isnan(appdata->gt.distance) || !appdata->gt.filename ||
539           !appdata->username || !appdata->gt.password)
540          errorf(_("The GeoToad setup is not complete."));
541        else
542          ok = TRUE;
543      }
544    
545      gtk_widget_destroy(context->dialog);
546    
547      return ok;
548    }
549    
550    void geotoad(appdata_t *appdata) {
551      if(!geotoad_available()) {
552        errorf(_("GeoToad is not installed on this device.\n"
553                 "You need to install it in order to be able to use it."));
554        return;
555      }
556    
557      gt_context_t *context = g_new0(gt_context_t, 1);
558      context->appdata = appdata;
559      context->use_cnt++;          // parent still uses this
560    
561      context->update_mutex = g_mutex_new();
562      context->update_cond = g_cond_new();
563    
564      if(gui_setup(context))
565        gui_run(context);
566    
567      /* continue to process if something has actually been saved */
568      if(context->state == GT_STATE_SAVE_FOUND) {
569        /* download seems to be successful. Make sure the GUI is */
570        /* updated if required */
571    
572        gpx_t **gpx = &(appdata->gpx);
573        while(*gpx && strcmp((*gpx)->filename, appdata->gt.filename))
574          gpx = &(*gpx)->next;
575    
576        /* return main GUI to GPX list */
577    #ifdef USE_BREAD_CRUMB_TRAIL
578        while(appdata->cur_gpx)
579          hildon_bread_crumb_trail_pop(HILDON_BREAD_CRUMB_TRAIL(appdata->bct));
580    #elif defined(BCT)
581        while(appdata->cur_gpx)
582          bct_pop(appdata->bct);
583    #else
584        HildonWindowStack *stack = hildon_window_stack_get_default();
585        gint num = hildon_window_stack_size(stack)-1;
586        while(num--) {
587          GtkWidget *top = hildon_window_stack_peek(stack);
588          gtk_widget_destroy(top);
589        }
590    #endif
591    
592        /* replace an existing entry or add to end of list */
593        if(*gpx) {
594          GtkTreeIter iter;
595          g_assert(gpxlist_find(appdata, &iter, *gpx));
596    
597          gpx_t *next = (*gpx)->next;
598    
599          gpx_free(*gpx);
600          *gpx = gpx_parse(NULL, appdata->gt.filename, appdata->username);
601          (*gpx)->next = next;
602    
603          /* update gpxlist */
604          gpxlist_set(appdata->gpxstore, &iter, *gpx);
605    
606          /* select that row */
607          GtkTreeSelection *selection =
608            gtk_tree_view_get_selection(GTK_TREE_VIEW(appdata->gpxview));
609          gtk_tree_selection_select_iter(selection, &iter);
610          GtkTreePath *path =
611            gtk_tree_model_get_path(GTK_TREE_MODEL(appdata->gpxstore), &iter);
612          gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(appdata->gpxview),
613                                       path, NULL, TRUE, 0.0, 0.0);
614          gtk_tree_path_free(path);
615        } else {
616          gpx_t *new = gpx_parse(NULL, appdata->gt.filename, appdata->username);
617          if(new) gpxlist_add(appdata, new);
618        }
619      }
620    
621      printf("main context free\n");
622      context_free(context);
623    }
624    
625    gboolean geotoad_available(void) {
626      /* before doing anything make sure geotoad is installed */
627      return g_file_test(GEOTOAD, G_FILE_TEST_IS_EXECUTABLE);
628    }
629    
630    

Legend:
Removed from v.194  
changed lines
  Added in v.233