Diff of /trunk/src/geotoad.c

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

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

Legend:
Removed from v.193  
changed lines
  Added in v.211