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 199 by harbaum, Thu Nov 19 13:33:35 2009 UTC
# Line 23  Line 23 
23  #include <sys/types.h>  #include <sys/types.h>
24  #include <sys/wait.h>  #include <sys/wait.h>
25  #include <errno.h>  #include <errno.h>
26    #include <math.h>
27    
28  #define BUFFER_SIZE  1500  #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR >= 5)
29    #include <hildon/hildon-entry.h>
30    #endif
31    
32    #define GEOTOAD "/usr/bin/geotoad"
33    
34    #define COLOR_ERR     "red"
35    #define COLOR_OK      "darkgreen"
36    #define COLOR_SYSTEM  "darkblue"
37    
38    #define BUFFER_SIZE  256
39    
40  typedef struct {  typedef struct {
41      appdata_t *appdata;
42    
43      GtkWidget *dialog;
44    
45    char buf[BUFFER_SIZE];    char buf[BUFFER_SIZE];
46    int bused;    int bused;
47    
# Line 34  typedef struct { Line 49  typedef struct {
49    gint stdout_tag, stderr_tag;    gint stdout_tag, stderr_tag;
50    gint stdin_fd, stdout_fd, stderr_fd;    gint stdin_fd, stdout_fd, stderr_fd;
51    
52      struct log_s {
53        GtkTextBuffer *buffer;
54        GtkWidget *view;
55      } log;
56    
57      GtkWidget *username, *password, *filename;
58      GtkWidget *lat, *lon, *dst;
59    
60  } gt_context_t;  } gt_context_t;
61    
62    static void appendf(struct log_s *log, char *colname,
63                        const char *fmt, ...) {
64      va_list args;
65      va_start( args, fmt );
66      char *buf = g_strdup_vprintf(fmt, args);
67      va_end( args );
68    
69      printf("append: %s", buf);
70    
71      GtkTextTag *tag = NULL;
72      if(colname)
73        tag = gtk_text_buffer_create_tag(log->buffer, NULL,
74                                         "foreground", colname,
75                                         NULL);
76    
77      GtkTextIter end;
78      gtk_text_buffer_get_end_iter(log->buffer, &end);
79      if(tag)
80        gtk_text_buffer_insert_with_tags(log->buffer, &end, buf, -1, tag, NULL);
81      else
82        gtk_text_buffer_insert(log->buffer, &end, buf, -1);
83    
84      g_free(buf);
85    
86      gtk_text_buffer_get_end_iter(log->buffer, &end);
87      gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(log->view),
88                                   &end, 0.0, FALSE, 0, 0);
89    }
90    
91  /* watch child process and receive events */  /* watch child process and receive events */
92  static void child_state_cb(GPid pid, gint status, gpointer data) {  static void child_state_cb(GPid pid, gint status, gpointer data) {
93      gt_context_t *context = (gt_context_t*)data;
94    
95    puts("child state");    puts("child state");
96    
97    if(WIFEXITED(status)) {    if(WIFEXITED(status)) {
98    }      printf("child exited with return code %d\n", WEXITSTATUS(status));
99      } else
100        printf("child failed\n");
101    
102    puts("gt exited");    puts("gt exited");
103    
104      appendf(&context->log, COLOR_SYSTEM, "GeoToad finished\n");
105    
106      appendf(&context->log, COLOR_SYSTEM, "TODO: free context!!!\n");
107      //    printf("freeing context\n");
108      //    g_free(context);
109    
110    /* Reap child if needed. */    /* Reap child if needed. */
111    waitpid (pid, NULL, WNOHANG);    waitpid (pid, NULL, WNOHANG);
112  }  }
113    
114  static void child_input_cb(gpointer data, int fd, GdkInputCondition cond) {  static gboolean child_input_cb(GIOChannel *source,
115                                   GIOCondition condition,
116                                   gpointer data) {
117    gt_context_t *context = (gt_context_t*)data;    gt_context_t *context = (gt_context_t*)data;
118      int fd = g_io_channel_unix_get_fd(source);
119    ssize_t bytes;    ssize_t bytes;
   int errnosave=0;  
120    
121    if(cond != GDK_INPUT_READ) {    g_assert(condition == G_IO_IN);
     puts("fixme");  
     return;  
   }  
122    
123    /* append to current buffer content */    /* append to current buffer content */
124    while( (bytes = read(fd, context->buf+context->bused,    while( (bytes = read(fd, context->buf+context->bused,
# Line 75  static void child_input_cb(gpointer data Line 134  static void child_input_cb(gpointer data
134        char *p = strchr(ptr, '\n');        char *p = strchr(ptr, '\n');
135        *p = '\0';        *p = '\0';
136    
137        printf("line: %s\n", ptr);        char *color = NULL;
138          if(strstr(ptr, "Saved to ") != NULL)
139            color = COLOR_OK;
140    
141          appendf(&context->log, color, "%s\n", ptr);
142    
143        ptr = p+1;        ptr = p+1;
144      }      }
# Line 91  static void child_input_cb(gpointer data Line 154  static void child_input_cb(gpointer data
154      }      }
155    }    }
156    
157    /* save errno from read */    return TRUE;
   errnosave=errno;  
   
   if(errnosave != EAGAIN && errnosave != 0) {  
     /* we probably hit EOF */  
     puts("removing io");  
   
     // TODO: fixme, make sure process is dead! kill it otherwise, but dont  
     // issue an vpnc_disconnect(NULL) !!!!  
   
     gdk_input_remove(context->stdout_tag);  
     gdk_input_remove(context->stderr_tag);  
   
     printf("freeing context\n");  
     g_free(context);  
   }  
158  }  }
   
 void geotoad(appdata_t *appdata) {  
   gt_context_t *context = g_new0(gt_context_t, 1);  
   
   printf("geoToad\n");  
159    
160    static void run(gt_context_t *context) {
161    /* setup context */    /* setup context */
162    context->bused = 0;    context->bused = 0;
163    context->stdout_tag = -1;    context->stdout_tag = -1;
# Line 122  void geotoad(appdata_t *appdata) { Line 166  void geotoad(appdata_t *appdata) {
166    context->stderr_fd = -1;    context->stderr_fd = -1;
167    context->stderr_fd = -1;    context->stderr_fd = -1;
168    
169    /* build list of arguments */    /* build list of arguments to call geotoad */
170    GPtrArray *gt_argv = g_ptr_array_new();    GPtrArray *gt_argv = g_ptr_array_new();
171    g_ptr_array_add (gt_argv, "/usr/bin/env");    g_ptr_array_add (gt_argv, GEOTOAD);
172    //  g_ptr_array_add (gt_argv, "/tmp");    g_ptr_array_add (gt_argv, "--distanceMax=1.0");
173      g_ptr_array_add (gt_argv, "--output=gtoad.gpx");
174      g_ptr_array_add (gt_argv, "--password=winterblume");
175      g_ptr_array_add (gt_argv, "--queryType=coord");
176      g_ptr_array_add (gt_argv, "--user=Tantil");
177    
178      /* check if we need to add proxy config */
179      char *proxy = NULL;
180      if(context->appdata->proxy && context->appdata->proxy->host) {
181        if(context->appdata->proxy->use_authentication &&
182           context->appdata->proxy->authentication_user &&
183           context->appdata->proxy->authentication_password)
184          proxy = g_strdup_printf("--proxy=http://%s:%s@%s:%d",
185                                  context->appdata->proxy->authentication_user,
186                                  context->appdata->proxy->authentication_password,
187                                  context->appdata->proxy->host,
188                                  context->appdata->proxy->port);
189        else
190          proxy = g_strdup_printf("--proxy=http://%s:%d",
191                                  context->appdata->proxy->host,
192                                  context->appdata->proxy->port);
193    
194        appendf(&context->log, COLOR_SYSTEM, "Using proxy: %s\n", proxy);
195        g_ptr_array_add (gt_argv, proxy);
196      }
197    
198      g_ptr_array_add (gt_argv, "N49 00.000 E008 23.000");
199    g_ptr_array_add (gt_argv, NULL);    g_ptr_array_add (gt_argv, NULL);
200    
201    GError *error=NULL;    GError *error=NULL;
202    GPid pid;    GPid pid;
203    GSource *gt_watch;    GSource *gt_watch;
# Line 144  void geotoad(appdata_t *appdata) { Line 214  void geotoad(appdata_t *appdata) {
214                                   &context->stderr_fd,                                   &context->stderr_fd,
215                                   &error)) {                                   &error)) {
216      g_ptr_array_free(gt_argv, TRUE);      g_ptr_array_free(gt_argv, TRUE);
217      errorf(_("GeoToad failed to start.\n\nError: '%s'"), error->message);      if(proxy) g_free(proxy);
218        appendf(&context->log, COLOR_ERR,
219                _("GeoToad failed to start!\n%s\n"), error->message);
220      g_error_free(error);      g_error_free(error);
221      return;      return;
222    }    }
   g_ptr_array_free (gt_argv, TRUE);  
223    
224    printf("GeoToad: pid = %d\n", pid);    g_ptr_array_free (gt_argv, TRUE);
225      if(proxy) g_free(proxy);
226    
227    gt_watch = g_child_watch_source_new(pid);    gt_watch = g_child_watch_source_new(pid);
228    g_source_set_callback(gt_watch, (GSourceFunc) child_state_cb, NULL, NULL);    g_source_set_callback(gt_watch, (GSourceFunc) child_state_cb, context, NULL);
229    
230    g_source_attach(gt_watch, NULL);    g_source_attach(gt_watch, NULL);
231    g_source_unref(gt_watch);    g_source_unref(gt_watch);
# Line 165  void geotoad(appdata_t *appdata) { Line 237  void geotoad(appdata_t *appdata) {
237    if(fcntl(context->stderr_fd, F_SETFL, O_NONBLOCK) == -1)    if(fcntl(context->stderr_fd, F_SETFL, O_NONBLOCK) == -1)
238      perror("fcntl failed");      perror("fcntl failed");
239    
240    /* use gdk to monitor read end of stdout */    GIOChannel *ioc = g_io_channel_unix_new(context->stdout_fd);
241    context->stdout_tag =    g_io_channel_set_close_on_unref (ioc, TRUE);
242      gdk_input_add(context->stdout_fd, GDK_INPUT_READ, child_input_cb, context);    g_io_channel_set_encoding (ioc, NULL, NULL);
243    context->stderr_tag =    g_io_add_watch(ioc, G_IO_IN,  child_input_cb, context);
244      gdk_input_add(context->stderr_fd, GDK_INPUT_READ, child_input_cb, context);    g_io_channel_unref(ioc);
245    
246      //  ioc = g_io_channel_unix_new(context->stderr_fd);
247      //  g_io_add_watch(ioc, G_IO_IN,  child_input_cb, context);
248      //  g_io_channel_unref(ioc);
249  }  }
250    
251    /* show text window and display output of running geotoad */
252    static void gui_run(gt_context_t *context) {
253      GtkWidget *dialog = gtk_dialog_new_with_buttons(_("GeoToad - Run"),
254                              GTK_WINDOW(context->appdata->window),
255                              GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
256                              GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
257                              NULL);
258    
259      gtk_window_set_default_size(GTK_WINDOW(dialog), 640, 480);
260    
261    #ifndef USE_PANNABLE_AREA
262      GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
263      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
264                                     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
265    #else
266      GtkWidget *pannable_area = hildon_pannable_area_new();
267    #endif
268    
269      context->log.buffer = gtk_text_buffer_new(NULL);
270    
271    #ifndef USE_HILDON_TEXT_VIEW
272      context->log.view = gtk_text_view_new_with_buffer(context->log.buffer);
273    #else
274      context->log.view = hildon_text_view_new();
275      hildon_text_view_set_buffer(HILDON_TEXT_VIEW(context->log.view),
276                                  context->log.buffer);
277    #endif
278    
279    #ifndef USE_PANNABLE_AREA
280      gtk_container_add(GTK_CONTAINER(scrolled_window), context->log.view);
281      gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(scrolled_window),
282                                           GTK_SHADOW_IN);
283    
284      gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
285                         scrolled_window, TRUE, TRUE, 0);
286    #else
287      gtk_container_add(GTK_CONTAINER(pannable_area), context->log.view);
288      gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
289                         pannable_area, TRUE, TRUE, 0);
290    #endif
291    
292      gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE);
293    
294      gtk_widget_show_all(dialog);
295    
296      appendf(&context->log, COLOR_SYSTEM, "Running GeoToad\n");
297      run(context);
298    
299      gtk_dialog_run(GTK_DIALOG(dialog));
300    
301      gtk_widget_destroy(dialog);
302    }
303    
304    static void on_browse(GtkWidget *widget, gpointer data) {
305      gt_context_t *context = (gt_context_t*)data;
306    
307      printf("Browse %p\n", context->dialog);
308    
309    #ifdef USE_MAEMO
310      GtkWidget *dialog = hildon_file_chooser_dialog_new(GTK_WINDOW(context->dialog),
311                                              GTK_FILE_CHOOSER_ACTION_SAVE);
312    #else
313      GtkWidget *dialog = gtk_file_chooser_dialog_new(_("Save GPX file"),
314                                           GTK_WINDOW(context->dialog),
315                                           GTK_FILE_CHOOSER_ACTION_SAVE,
316                                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
317                                           GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
318                                           NULL);
319    #endif
320    
321      printf("set filename <%s>\n", context->appdata->gt.filename);
322    
323      if(!g_file_test(context->appdata->gt.filename, G_FILE_TEST_EXISTS)) {
324        char *last_sep = strrchr(context->appdata->gt.filename, '/');
325        if(last_sep) {
326          *last_sep = 0;  // seperate path from file
327    
328          /* the user just created a new document */
329          gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
330                                              context->appdata->gt.filename);
331          gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), last_sep+1);
332    
333          /* restore full filename */
334          *last_sep = '/';
335        }
336      } else
337        gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
338                                      context->appdata->gt.filename);
339    
340      if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_FM_OK) {
341        gchar *name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
342        gtk_label_set_text(GTK_LABEL(context->filename), name);
343      }
344    
345      gtk_widget_destroy (dialog);
346    }
347    
348    static gboolean gui_setup(gt_context_t *context) {
349      appdata_t *appdata = context->appdata;
350      gboolean ok = FALSE;
351    
352      /* if no filename has been setup yet, create one */
353      if(!appdata->gt.filename && appdata->path) {
354        printf("creating path\n");
355        appdata->gt.filename =
356          g_strdup_printf("%s/gtoad.gpx", appdata->path);
357      }
358    
359      context->dialog = gtk_dialog_new_with_buttons(_("GeoToad - Setup"),
360                            GTK_WINDOW(appdata->window),
361                            GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
362                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
363                            GTK_STOCK_OK,     GTK_RESPONSE_OK,
364                            NULL);
365    
366      /* ------------------- Coordinates ------------------------- */
367      GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
368    
369      GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
370      gtk_box_pack_start_defaults(GTK_BOX(vbox), left_label_new(_("Position:")));
371      gtk_box_pack_start_defaults(GTK_BOX(vbox), left_label_new(_("Distance:")));
372      gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
373    
374      /* setup default positions */
375      pos_t *refpos = get_pos(appdata);
376      if((isnan(appdata->gt.lat) || isnan(appdata->gt.lat)) && refpos) {
377        appdata->gt.lat = refpos->lat;
378        appdata->gt.lon = refpos->lon;
379      }
380    
381      vbox = gtk_vbox_new(FALSE, 0);
382      GtkWidget *ihbox = gtk_hbox_new(FALSE, 0);
383      context->lat = lat_entry_new(appdata->gt.lat);
384      gtk_box_pack_start_defaults(GTK_BOX(ihbox), context->lat);
385      context->lon = lon_entry_new(appdata->gt.lon);
386      gtk_box_pack_start_defaults(GTK_BOX(ihbox), context->lon);
387      gtk_box_pack_start_defaults(GTK_BOX(vbox), ihbox);
388      context->dst = dist_entry_new(appdata->gt.distance, appdata->imperial);
389      gtk_box_pack_start_defaults(GTK_BOX(vbox), context->dst);
390      gtk_box_pack_start_defaults(GTK_BOX(hbox), vbox);
391    
392      gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(context->dialog)->vbox), hbox);
393    
394      /* ------------------- file name ------------------------- */
395      hbox = gtk_hbox_new(FALSE, 0);
396    
397      context->filename = gtk_label_new(appdata->gt.filename);
398      gtk_misc_set_alignment(GTK_MISC(context->filename), 0.f, 0.5f);
399      gtk_label_set_ellipsize(GTK_LABEL(context->filename), PANGO_ELLIPSIZE_MIDDLE);
400      gtk_box_pack_start_defaults(GTK_BOX(hbox), context->filename);
401    
402      GtkWidget *button = gtk_button_new_with_label(_("Browse"));
403    #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
404      hildon_gtk_widget_set_theme_size(button,
405               (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
406    #endif
407      gtk_signal_connect(GTK_OBJECT(button), "clicked",
408                         GTK_SIGNAL_FUNC(on_browse), context);
409      gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
410    
411      gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(context->dialog)->vbox), hbox);
412    
413    
414      /* ------------------- Username/Password ------------------------- */
415      hbox = gtk_hbox_new(FALSE, 0);
416      vbox = gtk_vbox_new(FALSE, 0);
417      gtk_box_pack_start_defaults(GTK_BOX(vbox), left_label_new(_("Username:")));
418      gtk_box_pack_start_defaults(GTK_BOX(vbox), left_label_new(_("Password:")));
419      gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
420    
421      vbox = gtk_vbox_new(FALSE, 0);
422    #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
423      context->username = gtk_entry_new();
424      context->password = gtk_entry_new();
425    #else
426      context->username = hildon_entry_new(HILDON_SIZE_AUTO);
427      hildon_gtk_entry_set_input_mode(GTK_ENTRY(context->username),
428                                      HILDON_GTK_INPUT_MODE_FULL);
429      context->password = hildon_entry_new(HILDON_SIZE_AUTO);
430      hildon_gtk_entry_set_input_mode(GTK_ENTRY(context->password),
431                                      HILDON_GTK_INPUT_MODE_FULL);
432    #endif
433      gtk_entry_set_visibility(GTK_ENTRY(context->password), FALSE);
434    
435      /* set saved defaults */
436      if(appdata->gt.username)
437        gtk_entry_set_text(GTK_ENTRY(context->username),
438                           appdata->gt.username);
439    
440      if(appdata->gt.password)
441        gtk_entry_set_text(GTK_ENTRY(context->password),
442                           appdata->gt.password);
443    
444      gtk_box_pack_start_defaults(GTK_BOX(vbox), context->username);
445      gtk_box_pack_start_defaults(GTK_BOX(vbox), context->password);
446      gtk_box_pack_start_defaults(GTK_BOX(hbox), vbox);
447    
448      gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(context->dialog)->vbox), hbox);
449    
450      gtk_dialog_set_default_response(GTK_DIALOG(context->dialog), GTK_RESPONSE_OK);
451    
452      gtk_widget_show_all(context->dialog);
453    
454      if(gtk_dialog_run(GTK_DIALOG(context->dialog)) == GTK_RESPONSE_OK) {
455    
456        /* save values */
457        if(appdata->gt.username) g_free(appdata->gt.username);
458        appdata->gt.username =
459          g_strdup(gtk_entry_get_text(GTK_ENTRY(context->username)));
460    
461        if(appdata->gt.password) g_free(appdata->gt.password);
462        appdata->gt.password =
463          g_strdup(gtk_entry_get_text(GTK_ENTRY(context->password)));
464    
465        if(appdata->gt.filename) g_free(appdata->gt.filename);
466        appdata->gt.filename =
467          g_strdup(gtk_label_get_text(GTK_LABEL(context->filename)));
468    
469        ok = TRUE;
470      }
471    
472      gtk_widget_destroy(context->dialog);
473    
474      return ok;
475    }
476    
477    void geotoad(appdata_t *appdata) {
478      if(!geotoad_available()) {
479        errorf(_("GeoToad is not installed on this device.\n"
480                 "You need to install it in order to be able to use it."));
481        return;
482      }
483    
484      gt_context_t *context = g_new0(gt_context_t, 1);
485      context->appdata = appdata;
486    
487      printf("geoToad\n");
488    
489      if(gui_setup(context))
490        gui_run(context);
491    }
492    
493    gboolean geotoad_available(void) {
494      /* before doing anything make sure geotoad is installed */
495      return g_file_test(GEOTOAD, G_FILE_TEST_IS_EXECUTABLE);
496    }
497    
498    

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