]> git.street.me.uk Git - andy/viking.git/commitdiff
Threading rewrite to remove use of unsupported cross platform threading update of...
authorRob Norris <rw_norris@hotmail.com>
Sat, 23 Apr 2016 11:18:50 +0000 (12:18 +0100)
committerRob Norris <rw_norris@hotmail.com>
Mon, 13 Mar 2017 23:39:01 +0000 (23:39 +0000)
When Viking is run on a real Windows system (i.e. not just under wine)
 that has been built via the new cross build mechanism, it will lock up whenever a window is moved.

Remove all use of gdk_threads_enter() / gdk_threads_leave() and always use the main thread to update the GUI.
Thus make extensive changes to ensure updates are directed through gdk_threads_add_idle() or gtk_idle_add()
 and protection to prevent use of data that has gone out of scope.

This should be more reliable.

src/background.c
src/bingmapsource.c
src/datasource_gps.c
src/main.c
src/vikdemlayer.c
src/vikgpslayer.c
src/viktrwlayer.c
src/vikwindow.c

index c49e517ff3463985f29785fa71133e3a9bd8fa79..24c035765bd77d71c6cf06ea7e88df022cff60bc 100644 (file)
@@ -38,10 +38,11 @@ static GThreadPool *thread_pool_local_mapnik = NULL;
 #endif
 static gboolean stop_all_threads = FALSE;
 
-static GtkWidget *bgwindow = NULL;
-static GtkWidget *bgtreeview = NULL;
+// A single store of background items for all Windows
+// Must always be accessed in the main thread
 static GtkListStore *bgstore = NULL;
 
+G_LOCK_DEFINE_STATIC(window_list);
 // Still only actually updating the statusbar though
 static GSList *windows_to_update = NULL;
 
@@ -64,15 +65,37 @@ void a_background_update_status ( VikWindow *vw, gpointer data )
   vik_window_statusbar_update ( vw, buf, VIK_STATUSBAR_ITEMS );
 }
 
+// NB can be called from any thread
 static void background_thread_update ()
 {
+  G_LOCK(window_list);
   g_slist_foreach ( windows_to_update, (GFunc) a_background_update_status, NULL );
+  G_UNLOCK(window_list);
+}
+
+typedef struct {
+  GtkTreeIter *iter;
+  gdouble percent;
+} progress_t;
+
+// In main thread
+static gboolean idle_progress_update ( gpointer user_data )
+{
+  progress_t *progress = user_data;
+  if ( bgstore )
+    gtk_list_store_set ( GTK_LIST_STORE(bgstore), progress->iter, PROGRESS_COLUMN, progress->percent, -1 );
+  g_free ( progress );
+  return FALSE;
 }
 
 /**
  * a_background_thread_progress:
  * @callbackdata: Thread data
  * @fraction:     The value should be between 0.0 and 1.0 indicating percentage of the task complete
+ *
+ * Called from other threads
+ *
+ * Returns a non zero number if the thread should be terminated
  */
 int a_background_thread_progress ( gpointer callbackdata, gdouble fraction )
 {
@@ -82,9 +105,10 @@ int a_background_thread_progress ( gpointer callbackdata, gdouble fraction )
     gdouble myfraction = fabs(fraction);
     if ( myfraction > 1.0 )
       myfraction = 1.0;
-    gdk_threads_enter();
-    gtk_list_store_set( GTK_LIST_STORE(bgstore), (GtkTreeIter *) args[5], PROGRESS_COLUMN, myfraction*100, -1 );
-    gdk_threads_leave();
+    progress_t *progress = g_malloc0 ( sizeof(progress_t) );
+    progress->percent = myfraction * 100;
+    progress->iter = (GtkTreeIter*)args[5];
+    gdk_threads_add_idle ( idle_progress_update, progress );
   }
 
   args[6] = GINT_TO_POINTER(GPOINTER_TO_INT(args[6])-1);
@@ -106,10 +130,11 @@ static void thread_die ( gpointer args[VIK_BG_NUM_ARGS] )
     background_thread_update ();
   }
 
-  g_free ( args[5] ); /* free iter */
   g_free ( args );
 }
 
+// Called from other threads
+// Returns a non zero number if the thread should be terminated
 int a_background_testcancel ( gpointer callbackdata )
 {
   gpointer *args = (gpointer *) callbackdata;
@@ -125,6 +150,21 @@ int a_background_testcancel ( gpointer callbackdata )
   return 0;
 }
 
+typedef struct {
+  GtkTreeIter *iter;
+} remove_t;
+
+// Called from the main thread
+static gboolean idle_remove ( gpointer user_data )
+{
+  remove_t *remove = user_data;
+  if ( bgstore )
+    gtk_list_store_remove ( bgstore, remove->iter );
+  g_free ( remove->iter );
+  return FALSE;
+}
+
+// Called from other threads
 static void thread_helper ( gpointer args[VIK_BG_NUM_ARGS], gpointer user_data )
 {
   /* unpack args */
@@ -135,11 +175,11 @@ static void thread_helper ( gpointer args[VIK_BG_NUM_ARGS], gpointer user_data )
 
   func ( userdata, args );
 
-  gdk_threads_enter();
-  if ( ! args[0] )
-    gtk_list_store_remove ( bgstore, (GtkTreeIter *) args[5] );
-  gdk_threads_leave();
-
+  if ( ! args[0] ) {
+    remove_t *remove = g_malloc0 ( sizeof(remove_t) );
+    remove->iter = args[5];
+    gdk_threads_add_idle ( idle_remove, remove );
+  }
   thread_die ( args );
 }
 
@@ -191,16 +231,7 @@ void a_background_thread ( Background_Pool_Type bp, GtkWindow *parent, const gch
     g_thread_pool_push( thread_pool_local, args, NULL );
 }
 
-/**
- * a_background_show_window:
- *
- * Display the background window.
- */
-void a_background_show_window ()
-{
-  gtk_widget_show_all ( bgwindow );
-}
-
+// In main thread
 static void cancel_job_with_iter ( GtkTreeIter *piter )
 {
     gpointer *args;
@@ -214,35 +245,36 @@ static void cancel_job_with_iter ( GtkTreeIter *piter )
     args[0] = GINT_TO_POINTER(1); /* set killswitch */
 
     gtk_list_store_remove ( bgstore, piter );
+    g_free ( piter );
     args[5] = NULL;
 }
 
-static void bgwindow_response (GtkDialog *dialog, gint arg1 )
+// In main thread
+static void bgwindow_response (GtkDialog *dialog, gint response_id, GtkTreeView *bgtreeview )
 {
-  /* note this function is a signal handler called back from the GTK main loop, 
-   * so GDK is already locked.  We need to release the lock before calling 
-   * thread-safe routines
-   */
-  if ( arg1 == 1 ) /* cancel */
+  switch ( response_id ) {
+  case GTK_RESPONSE_DELETE_EVENT:
+    // Delibrate fall through
+  case GTK_RESPONSE_CLOSE:
+    gtk_widget_destroy ( GTK_WIDGET(dialog) );
+    break;
+  case 1: // Delete / Cancel selected item
     {
       GtkTreeIter iter;
-      if ( gtk_tree_selection_get_selected ( gtk_tree_view_get_selection ( GTK_TREE_VIEW(bgtreeview) ), NULL, &iter ) )
-       cancel_job_with_iter ( &iter );
-      gdk_threads_leave();
+      if ( gtk_tree_selection_get_selected ( gtk_tree_view_get_selection(bgtreeview), NULL, &iter ) )
+        cancel_job_with_iter ( &iter );
       background_thread_update();
-      gdk_threads_enter();
     }
-  else if ( arg1 == 2 ) /* clear */
+    break;
+  case 2: // Clear All jobs
     {
       GtkTreeIter iter;
       while ( gtk_tree_model_get_iter_first ( GTK_TREE_MODEL(bgstore), &iter ) )
-       cancel_job_with_iter ( &iter );
-      gdk_threads_leave();
+        cancel_job_with_iter ( &iter );
       background_thread_update();
-      gdk_threads_enter();
     }
-  else /* OK */
-    gtk_widget_hide ( bgwindow );
+    default: break;
+  }
 }
 
 #define VIK_SETTINGS_BACKGROUND_MAX_THREADS "background_max_threads"
@@ -302,14 +334,23 @@ void a_background_post_init()
   thread_pool_local_mapnik = g_thread_pool_new ( (GFunc) thread_helper, NULL, mapnik_threads, FALSE, NULL );
 #endif
 
+  bgstore = gtk_list_store_new ( N_COLUMNS, G_TYPE_STRING, G_TYPE_DOUBLE, G_TYPE_POINTER );
+}
+
+/**
+ * a_background_show_window:
+ *
+ * Display the background window.
+ */
+void a_background_show_window ()
+{
+  GtkWidget *bgwindow = NULL;
+  GtkWidget *bgtreeview = NULL;
   GtkCellRenderer *renderer;
   GtkTreeViewColumn *column;
   GtkWidget *scrolled_window;
 
-  g_debug(__FUNCTION__);
-
   /* store & treeview */
-  bgstore = gtk_list_store_new ( N_COLUMNS, G_TYPE_STRING, G_TYPE_DOUBLE, G_TYPE_POINTER );
   bgtreeview = gtk_tree_view_new_with_model ( GTK_TREE_MODEL(bgstore) );
   gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (bgtreeview), TRUE);
   gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (bgtreeview)),
@@ -329,7 +370,7 @@ void a_background_post_init()
   gtk_container_add ( GTK_CONTAINER(scrolled_window), bgtreeview );
   gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
 
-  bgwindow = gtk_dialog_new_with_buttons ( "", NULL, 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_DELETE, 1, GTK_STOCK_CLEAR, 2, NULL );
+  bgwindow = gtk_dialog_new_with_buttons ( _("Viking Background Jobs"), NULL, 0, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, GTK_STOCK_DELETE, 1, GTK_STOCK_CLEAR, 2, NULL );
   gtk_dialog_set_default_response ( GTK_DIALOG(bgwindow), GTK_RESPONSE_ACCEPT );
   GtkWidget *response_w = NULL;
 #if GTK_CHECK_VERSION (2, 20, 0)
@@ -337,14 +378,14 @@ void a_background_post_init()
 #endif
   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(bgwindow))), scrolled_window, TRUE, TRUE, 0 );
   gtk_window_set_default_size ( GTK_WINDOW(bgwindow), 400, 400 );
-  gtk_window_set_title ( GTK_WINDOW(bgwindow), _("Viking Background Jobs") );
   if ( response_w )
     gtk_widget_grab_focus ( response_w );
-  /* don't destroy win */
-  g_signal_connect ( G_OBJECT(bgwindow), "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL );
 
-  g_signal_connect ( G_OBJECT(bgwindow), "response", G_CALLBACK(bgwindow_response), 0 );
+  g_signal_connect ( G_OBJECT(bgwindow), "response", G_CALLBACK(bgwindow_response), GTK_TREE_VIEW(bgtreeview) );
+
+  gtk_widget_show_all ( bgwindow );
 
+  gtk_dialog_set_default_response ( GTK_DIALOG(bgwindow), GTK_RESPONSE_CLOSE );
 }
 
 /**
@@ -355,26 +396,27 @@ void a_background_post_init()
 void a_background_uninit()
 {
   stop_all_threads = TRUE;
-  // wait until these threads stop
-  g_thread_pool_free ( thread_pool_remote, TRUE, TRUE );
-  // Don't wait for these
+  // Don't wait for these threads to complete - i.e. end now.
+  g_thread_pool_free ( thread_pool_remote, TRUE, FALSE );
   g_thread_pool_free ( thread_pool_local, TRUE, FALSE );
 #ifdef HAVE_LIBMAPNIK
   g_thread_pool_free ( thread_pool_local_mapnik, TRUE, FALSE );
 #endif
-
   gtk_list_store_clear ( bgstore );
   g_object_unref ( bgstore );
-
-  gtk_widget_destroy ( bgwindow );
+  bgstore = NULL;
 }
 
 void a_background_add_window (VikWindow *vw)
 {
+  G_LOCK(window_list);
   windows_to_update = g_slist_prepend(windows_to_update,vw);
+  G_UNLOCK(window_list);
 }
 
 void a_background_remove_window (VikWindow *vw)
 {
+  G_LOCK(window_list);
   windows_to_update = g_slist_remove(windows_to_update,vw);
+  G_UNLOCK(window_list);
 }
index c999ac754aa6f6215246c1bcae432dc72a41bbf9..0c9fd99587ea46545bb3a2dd9faf4696057afc62 100644 (file)
@@ -482,15 +482,12 @@ done:
        return ret;
 }
 
-static int
+static gboolean
 _emit_update ( gpointer data )
 {
-       gdk_threads_enter();
-       /* TODO
-       vik_layers_panel_emit_update ( VIK_LAYERS_PANEL (data) );
-       */
-       gdk_threads_leave();
-       return 0;
+       //if ( data )
+       //      vik_layers_panel_emit_update ( VIK_LAYERS_PANEL (data) );
+       return FALSE;
 }
 
 static int
@@ -502,10 +499,9 @@ _load_attributions_thread ( BingMapSource *self, gpointer threaddata )
                return -1; /* Abort thread */
 
        /* Emit update */
-       /* As we are on a download thread,
-        * it's better to fire the update from the main loop.
-        */
-       g_idle_add ( (GSourceFunc)_emit_update, NULL /* FIXME */ );
+       // As we are on a download thread, must the update GUI from the main loop
+       // TODO: have reference to the window/viewport/layerspanel to update...
+       (void)gdk_threads_add_idle ( _emit_update, NULL );
 
        return 0;
 }
index 8e545d824ce18f7f5a69c45bd6914708308a5978..e051f133c69023e29f9a0ea5e25cdeaae95eeb3e 100644 (file)
@@ -99,19 +99,26 @@ typedef struct {
 
   /* progress dialog */
   GtkWidget *gps_label;
-  GtkWidget *ver_label;
-  GtkWidget *id_label;
-  GtkWidget *wp_label;
+  GtkWidget *wpt_label;
   GtkWidget *trk_label;
   GtkWidget *rte_label;
-  GtkWidget *progress_label;
   vik_gps_xfer_type progress_type;
 
-  /* state */
-  int total_count;
-  int count;
+  // Maintain separate counts for each type
+  int wpt_total_count;
+  int wpt_count;
+  int trk_total_count;
+  int trk_count;
+  int rte_total_count;
+  int rte_count;
+  gchar *info;
   // Know which way xfer is so xfer setting types are only stored for download
   vik_gps_dir direction;
+  // GUI Updates
+  gint id_status;
+  gint id_info;
+  gint id_total_count;
+  gint id_count;
 } gps_user_data_t;
 
 #define VIK_SETTINGS_GPS_GET_TRACKS "gps_download_tracks"
@@ -123,7 +130,7 @@ typedef struct {
 
 static gpointer datasource_gps_init_func ( acq_vik_t *avt )
 {
-  gps_user_data_t *gps_ud = g_malloc (sizeof(gps_user_data_t));
+  gps_user_data_t *gps_ud = g_malloc0 (sizeof(gps_user_data_t));
   gps_ud->direction = GPS_DOWN;
   return gps_ud;
 }
@@ -308,7 +315,18 @@ static void datasource_gps_off ( gpointer user_data, gchar **babelargs, gchar **
 
 static void datasource_gps_cleanup ( gpointer user_data )
 {
-  g_free ( user_data );
+  gps_user_data_t *gud = (gps_user_data_t *)user_data;
+  // Remove any outstanding GUI update requests
+  if ( gud->id_status )
+    g_source_remove ( gud->id_status );
+  if ( gud->id_info )
+    g_source_remove ( gud->id_info );
+  if ( gud->id_total_count )
+    g_source_remove ( gud->id_total_count );
+  if ( gud->id_count )
+    g_source_remove ( gud->id_count );
+  g_free ( gud->info );
+  g_free ( gud );
   gps_acquire_in_progress = FALSE;
 }
 
@@ -322,69 +340,95 @@ void datasource_gps_clean_up ( gpointer user_data )
   datasource_gps_cleanup ( user_data );
 }
 
-static void set_total_count(gint cnt, acq_dialog_widgets_t *w)
+static gboolean show_total_count(acq_dialog_widgets_t *w)
 {
-  gchar *s = NULL;
-  gdk_threads_enter();
+  gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
   if (w->running) {
-    gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
+    gint tmp_count;
+    GtkWidget *progress_label;
     const gchar *tmp_str;
     switch (gps_data->progress_type) {
-    case WPT: tmp_str = ngettext("Downloading %d waypoint...", "Downloading %d waypoints...", cnt); gps_data->total_count = cnt; break;
-    case TRK: tmp_str = ngettext("Downloading %d trackpoint...", "Downloading %d trackpoints...", cnt); gps_data->total_count = cnt; break;
+    case WPT:
+      progress_label = gps_data->wpt_label;
+      tmp_str = ngettext("Downloading %d waypoint...", "Downloading %d waypoints...", gps_data->wpt_total_count);
+      tmp_count = gps_data->wpt_total_count;
+      break;
+    case TRK:
+      progress_label = gps_data->trk_label;
+      tmp_str = ngettext("Downloading %d trackpoint...", "Downloading %d trackpoints...", gps_data->trk_total_count);
+      tmp_count = gps_data->trk_total_count;
+      break;
     default:
-      {
-        // Maybe a gpsbabel bug/feature (upto at least v1.4.3 or maybe my Garmin device) but the count always seems x2 too many for routepoints
-        gint mycnt = (cnt / 2) + 1;
-        tmp_str = ngettext("Downloading %d routepoint...", "Downloading %d routepoints...", mycnt);
-        gps_data->total_count = mycnt;
-        break;
-      }
+      progress_label = gps_data->rte_label;
+      tmp_str = ngettext("Downloading %d routepoint...", "Downloading %d routepoints...", gps_data->rte_total_count);
+      tmp_count = gps_data->rte_total_count;
+      break;
     }
-    s = g_strdup_printf(tmp_str, cnt);
-    gtk_label_set_text ( GTK_LABEL(gps_data->progress_label), s );
-    gtk_widget_show ( gps_data->progress_label );
+    gchar *s = g_strdup_printf(tmp_str, tmp_count);
+    gtk_label_set_text ( GTK_LABEL(progress_label), s );
+    gtk_widget_show ( progress_label );
+    g_free(s);
   }
-  g_free(s); s = NULL;
-  gdk_threads_leave();
+  gps_data->id_total_count = 0;
+  return FALSE;
 }
 
-static void set_current_count(gint cnt, acq_dialog_widgets_t *w)
+static gboolean show_current_count(acq_dialog_widgets_t *w)
 {
-  gchar *s = NULL;
-  gdk_threads_enter();
+  gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
   if (w->running) {
-    gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
-
-    if (cnt < gps_data->total_count) {
-      switch (gps_data->progress_type) {
-      case WPT: s = g_strdup_printf(_("Downloaded %d out of %d %s..."), cnt, gps_data->total_count, "waypoints"); break;
-      case TRK: s = g_strdup_printf(_("Downloaded %d out of %d %s..."), cnt, gps_data->total_count, "trackpoints"); break;
-      default: s = g_strdup_printf(_("Downloaded %d out of %d %s..."), cnt, gps_data->total_count, "routepoints"); break;
-      }
-    } else {
-      switch (gps_data->progress_type) {
-      case WPT: s = g_strdup_printf(_("Downloaded %d %s."), cnt, "waypoints"); break;
-      case TRK: s = g_strdup_printf(_("Downloaded %d %s."), cnt, "trackpoints"); break;
-      default: s = g_strdup_printf(_("Downloaded %d %s."), cnt, "routepoints"); break;
-      }
+    GtkWidget *progress_label;
+    gchar *s = NULL;
+    switch (gps_data->progress_type) {
+      case WPT:
+        progress_label = gps_data->wpt_label;
+        if ( gps_data->wpt_count < gps_data->wpt_total_count )
+          s = g_strdup_printf(_("Downloaded %d out of %d %s..."), gps_data->wpt_count, gps_data->wpt_total_count, "waypoints");
+        else
+          s = g_strdup_printf(_("Downloaded %d %s."), gps_data->wpt_count, "waypoints");
+        break;
+      case TRK:
+        progress_label = gps_data->trk_label;
+        if ( gps_data->trk_count < gps_data->trk_total_count )
+          s = g_strdup_printf(_("Downloaded %d out of %d %s..."), gps_data->trk_count, gps_data->trk_total_count, "trackpoints");
+        else
+          s = g_strdup_printf(_("Downloaded %d %s."), gps_data->trk_count, "trackpoints");
+        break;
+      default:
+        progress_label = gps_data->rte_label;
+        if ( gps_data->rte_count < gps_data->rte_total_count )
+          s = g_strdup_printf(_("Downloaded %d out of %d %s..."), gps_data->rte_count, gps_data->rte_total_count, "routepoints");
+        else
+          s = g_strdup_printf(_("Downloaded %d %s."), gps_data->rte_count, "routepoints");
+        break;
     }
-    gtk_label_set_text ( GTK_LABEL(gps_data->progress_label), s );
+    gtk_label_set_text ( GTK_LABEL(progress_label), s );
+    g_free(s);
+  }
+  gps_data->id_count = 0;
+  return FALSE;
+}
+
+static gboolean show_gps_info(acq_dialog_widgets_t *w)
+{
+  gps_user_data_t *gps_data = (gps_user_data_t*)w->user_data;
+  if (w->running) {
+    gchar *s = g_strdup_printf ( _("GPS Device: %s"), gps_data->info );
+    gtk_label_set_text ( GTK_LABEL(gps_data->gps_label), s );
+    g_free(s);
   }
-  g_free(s); s = NULL;
-  gdk_threads_leave();
+  gps_data->id_info = 0;
+  return FALSE;
 }
 
-static void set_gps_info(const gchar *info, acq_dialog_widgets_t *w)
+static gboolean show_gps_status(acq_dialog_widgets_t *w)
 {
-  gchar *s = NULL;
-  gdk_threads_enter();
+  gps_user_data_t *gps_data = (gps_user_data_t*)w->user_data;
   if (w->running) {
-    s = g_strdup_printf(_("GPS Device: %s"), info);
-    gtk_label_set_text ( GTK_LABEL(((gps_user_data_t *)w->user_data)->gps_label), s );
+    gtk_label_set_text ( GTK_LABEL(w->status), _("Status: Working...") );
   }
-  g_free(s); s = NULL;
-  gdk_threads_leave();
+  gps_data->id_status = 0;
+  return FALSE;
 }
 
 /* 
@@ -401,23 +445,16 @@ static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_di
   case BABEL_DIAG_OUTPUT:
     line = (gchar *)data;
 
-    gdk_threads_enter();
-    if (w->running) {
-      gtk_label_set_text ( GTK_LABEL(w->status), _("Status: Working...") );
-    }
-    gdk_threads_leave();
+    gps_data->id_status = gdk_threads_add_idle ( (GSourceFunc)show_gps_status, w );
 
     /* tells us the type of items that will follow */
     if (strstr(line, "Xfer Wpt")) {
-      gps_data->progress_label = gps_data->wp_label;
       gps_data->progress_type = WPT;
     }
     if (strstr(line, "Xfer Trk")) {
-      gps_data->progress_label = gps_data->trk_label;
       gps_data->progress_type = TRK;
     }
     if (strstr(line, "Xfer Rte")) {
-      gps_data->progress_label = gps_data->rte_label;
       gps_data->progress_type = RTE;
     }
 
@@ -438,7 +475,8 @@ static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_di
          info[ilen++] = ch;
         }
         info[ilen++] = 0;
-        set_gps_info(info, w);
+        gps_data->info = g_strdup (info);
+        gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
       }
       g_strfreev(tokens);
     }
@@ -450,7 +488,8 @@ static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_di
         n_tokens++;
 
       if (n_tokens > 1) {
-        set_gps_info(tokens[1], w);
+        gps_data->info = g_strdup (tokens[1]);
+        gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
       }
       g_strfreev(tokens);
     }
@@ -462,13 +501,33 @@ static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_di
        sscanf(line+17, "%x", &lsb); 
        sscanf(line+20, "%x", &msb);
        cnt = lsb + msb * 256;
-       set_total_count(cnt, w);
-       gps_data->count = 0;
+       if ( gps_data->progress_type == RTE ) {
+          // Maybe a gpsbabel bug/feature (upto at least v1.4.3 or maybe my Garmin device) but the count always seems x2 too many for routepoints
+          gint mycnt = (cnt / 2) + 1;
+          gps_data->rte_total_count = mycnt;
+          gps_data->rte_count = 0;
+       }
+       else if ( gps_data->progress_type == TRK ) {
+         gps_data->trk_total_count = cnt;
+         gps_data->trk_count = 0;
+       }
+       else {
+          gps_data->wpt_total_count = cnt;
+          gps_data->wpt_count = 0;
+       }
+
+       gps_data->id_total_count = gdk_threads_add_idle ( (GSourceFunc)show_total_count, w);
       }
     }
     if ( strstr(line, "WPTDAT") || strstr(line, "TRKHDR") || strstr(line, "TRKDAT") || strstr(line, "RTEHDR") || strstr(line, "RTEWPT") ) {
-      gps_data->count++;
-      set_current_count(gps_data->count, w);
+      if ( strstr(line, "WPTDAT") )
+        gps_data->wpt_count++;
+      else if ( strstr(line, "TRKHDR") || strstr(line, "TRKDAT") )
+        gps_data->trk_count++;
+      else
+        // "RTEHDR" || "RTEWPT"
+        gps_data->rte_count++;
+      gps_data->id_count = gdk_threads_add_idle ( (GSourceFunc)show_current_count, w);
     }
     break;
   case BABEL_DONE:
@@ -671,29 +730,17 @@ gpointer datasource_gps_setup ( GtkWidget *dialog, vik_gps_xfer_type xfer, gbool
 
 void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data )
 {
-  GtkWidget *gpslabel, *verlabel, *idlabel, *wplabel, *trklabel, *rtelabel;
-
   gps_user_data_t *w_gps = (gps_user_data_t *)user_data;
 
-  gpslabel = gtk_label_new (_("GPS device: N/A"));
-  verlabel = gtk_label_new ("");
-  idlabel = gtk_label_new ("");
-  wplabel = gtk_label_new ("");
-  trklabel = gtk_label_new ("");
-  rtelabel = gtk_label_new ("");
+  w_gps->gps_label = gtk_label_new (_("GPS device: N/A"));
+  w_gps->wpt_label = gtk_label_new ("");
+  w_gps->trk_label = gtk_label_new ("");
+  w_gps->rte_label = gtk_label_new ("");
 
-  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), gpslabel, FALSE, FALSE, 5 );
-  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), wplabel, FALSE, FALSE, 5 );
-  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), trklabel, FALSE, FALSE, 5 );
-  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), rtelabel, FALSE, FALSE, 5 );
+  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), w_gps->gps_label, FALSE, FALSE, 5 );
+  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), w_gps->wpt_label, FALSE, FALSE, 5 );
+  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), w_gps->trk_label, FALSE, FALSE, 5 );
+  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), w_gps->rte_label, FALSE, FALSE, 5 );
 
   gtk_widget_show_all ( dialog );
-
-  w_gps->gps_label = gpslabel;
-  w_gps->id_label = idlabel;
-  w_gps->ver_label = verlabel;
-  w_gps->progress_label = w_gps->wp_label = wplabel;
-  w_gps->trk_label = trklabel;
-  w_gps->rte_label = rtelabel;
-  w_gps->total_count = -1;
 }
index e5400f06b506b4776687710b4605a6ce27d17585..effecbe37ccabaeb13f3ebd205a5ecf4cff83892 100644 (file)
@@ -133,7 +133,6 @@ int main( int argc, char *argv[] )
 #if ! GLIB_CHECK_VERSION (2, 32, 0)
   g_thread_init ( NULL );
 #endif
-  gdk_threads_init ();
 
   gui_initialized = gtk_init_with_args (&argc, &argv, "files+", entries, NULL, &error);
   if (!gui_initialized)
@@ -228,8 +227,6 @@ int main( int argc, char *argv[] )
   main_icon = gdk_pixbuf_from_pixdata(&viking_pixbuf, FALSE, NULL);
   gtk_window_set_default_icon(main_icon);
 
-  gdk_threads_enter ();
-
   // Ask for confirmation of default settings on first run
   vu_set_auto_features_on_first_run ();
 
@@ -275,7 +272,6 @@ int main( int argc, char *argv[] )
   vu_command_line ( first_window, latitude, longitude, zoom_level_osm, map_id );
 
   gtk_main ();
-  gdk_threads_leave ();
 
   a_babel_uninit ();
   a_toolbar_uninit ();
index 7df1a57ad735c6bfe45293cf59cca4c6bf7e1f53..12d52145c8490b7aa82c551477ed0631fbd4bceb 100644 (file)
@@ -345,11 +345,9 @@ static int dem_layer_load_list_thread ( dem_load_thread_data *dltd, gpointer thr
 
   // ATM as each file is processed the screen is not updated (no mechanism exposed to a_dems_load_list)
   // Thus force draw only at the end, as loading is complete/aborted
-  //gdk_threads_enter();
   // Test is helpful to prevent Gtk-CRITICAL warnings if the program is exitted whilst loading
   if ( IS_VIK_LAYER(dltd->vdl) )
-    vik_layer_emit_update ( VIK_LAYER(dltd->vdl) ); // NB update from background thread
-  //gdk_threads_leave();
+    vik_layer_emit_update ( VIK_LAYER(dltd->vdl) ); // NB update requested from background thread
 
   return result;
 }
@@ -1181,16 +1179,14 @@ static void dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
   else
     return;
 
-  //gdk_threads_enter();
   g_mutex_lock ( p->mutex );
   if ( p->vdl ) {
     g_object_weak_unref ( G_OBJECT(p->vdl), weak_ref_cb, p );
 
     if ( dem_layer_add_file ( p->vdl, p->dest ) )
-      vik_layer_emit_update ( VIK_LAYER(p->vdl) ); // NB update from background thread
+      vik_layer_emit_update ( VIK_LAYER(p->vdl) ); // NB update requested from background thread
   }
   g_mutex_unlock ( p->mutex );
-  //gdk_threads_leave();
 }
 
 
index 4f3b78e0d4644177dd9bd2627eafb3a73c1f16e1..f30e1a7fd2fc9b90b2712c47cfe3dc09b8f2101b 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
  * Copyright (C) 2006-2008, Quy Tonthat <qtonthat@gmail.com>
+ * Copyright (C) 2016, Rob Norris <rw_norris@hotmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -96,25 +97,34 @@ static gchar * old_params_ports[] = {"/dev/ttyS0", "/dev/ttyS1", "/dev/ttyUSB0",
 
 typedef struct {
   GMutex *mutex;
+  gboolean ok;
+  gboolean thread_complete;
   vik_gps_dir direction;
   gchar *port;
-  gboolean ok;
-  gint total_count;
-  gint count;
+  gint wpt_total_count;
+  gint wpt_count;
+  gint trk_total_count;
+  gint trk_count;
+  gint rte_total_count;
+  gint rte_count;
   VikTrwLayer *vtl;
   VikTrack *track;
   gchar *babelargs;
-  gchar *window_title;
   GtkWidget *dialog;
   GtkWidget *status_label;
   GtkWidget *gps_label;
-  GtkWidget *ver_label;
-  GtkWidget *id_label;
-  GtkWidget *wp_label;
+  GtkWidget *wpt_label;
   GtkWidget *trk_label;
   GtkWidget *rte_label;
-  GtkWidget *progress_label;
   vik_gps_xfer_type progress_type;
+  gboolean result;
+  gchar *info;
+  // GUI Updates
+  gint id_status_working;
+  gint id_status_end;
+  gint id_info;
+  gint id_total_count;
+  gint id_count;
   VikViewport *vvp;
 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
   gboolean realtime_tracking;
@@ -916,110 +926,208 @@ gboolean vik_gps_layer_is_empty ( VikGpsLayer *vgl )
 static void gps_session_delete(GpsSession *sess)
 {
   vik_mutex_free(sess->mutex);
+  // Remove any outstanding GUI update requests
+  if ( sess->id_status_working )
+    g_source_remove ( sess->id_status_working );
+  if ( sess->id_status_end )
+    g_source_remove ( sess->id_status_end );
+  if ( sess->id_info )
+    g_source_remove ( sess->id_info );
+  if ( sess->id_total_count )
+    g_source_remove ( sess->id_total_count );
+  if ( sess->id_count )
+    g_source_remove ( sess->id_count );
   g_free(sess->babelargs);
+  g_free(sess->info);
+  g_free(sess->port);
   g_free(sess);
 }
 
-static void set_total_count(gint cnt, GpsSession *sess)
+static gboolean show_total_count(GpsSession *sess)
 {
-  gchar s[128];
-  gdk_threads_enter();
   g_mutex_lock(sess->mutex);
   if (sess->ok) {
     const gchar *tmp_str;
+    gint tc;
+    GtkWidget *progress_label;
     if (sess->direction == GPS_DOWN)
     {
       switch (sess->progress_type) {
-      case WPT: tmp_str = ngettext("Downloading %d waypoint...", "Downloading %d waypoints...", cnt); sess->total_count = cnt; break;
-      case TRK: tmp_str = ngettext("Downloading %d trackpoint...", "Downloading %d trackpoints...", cnt); sess->total_count = cnt; break;
+      case WPT:
+        tmp_str = ngettext("Downloading %d waypoint...", "Downloading %d waypoints...", sess->wpt_total_count);
+        tc = sess->wpt_total_count;
+        progress_label = sess->wpt_label;
+        break;
+      case TRK:
+        tmp_str = ngettext("Downloading %d trackpoint...", "Downloading %d trackpoints...", sess->trk_total_count);
+        tc = sess->trk_total_count;
+        progress_label = sess->trk_label;
+        break;
       default:
+        tmp_str = ngettext("Downloading %d routepoint...", "Downloading %d routepoints...", sess->rte_total_count);
+        tc = sess->rte_total_count;
+        progress_label = sess->rte_label;
+        break;
+/*
         {
           // Maybe a gpsbabel bug/feature (upto at least v1.4.3 or maybe my Garmin device) but the count always seems x2 too many for routepoints
           gint mycnt = (cnt / 2) + 1;
           tmp_str = ngettext("Downloading %d routepoint...", "Downloading %d routepoints...", mycnt);
-          sess->total_count = mycnt;
+          tc = mycnt;
           break;
         }
+        */
       }
     }
     else
     {
       switch (sess->progress_type) {
-      case WPT: tmp_str = ngettext("Uploading %d waypoint...", "Uploading %d waypoints...", cnt); break;
-      case TRK: tmp_str = ngettext("Uploading %d trackpoint...", "Uploading %d trackpoints...", cnt); break;
-      default: tmp_str = ngettext("Uploading %d routepoint...", "Uploading %d routepoints...", cnt); break;
+      case WPT:
+        tmp_str = ngettext("Uploading %d waypoint...", "Uploading %d waypoints...", sess->wpt_total_count);
+        tc = sess->wpt_total_count;
+        progress_label = sess->wpt_label;
+        break;
+      case TRK:
+        tmp_str = ngettext("Uploading %d trackpoint...", "Uploading %d trackpoints...", sess->trk_total_count);
+        tc = sess->trk_total_count;
+        progress_label = sess->trk_label;
+        break;
+      default:
+        tmp_str = ngettext("Uploading %d routepoint...", "Uploading %d routepoints...", sess->rte_total_count);
+        tc = sess->rte_total_count;
+        progress_label = sess->rte_label;
+        break;
       }
     }
 
-    g_snprintf(s, 128, tmp_str, cnt);
-    gtk_label_set_text ( GTK_LABEL(sess->progress_label), s );
-    gtk_widget_show ( sess->progress_label );
-    sess->total_count = cnt;
+    gchar s[128];
+    g_snprintf(s, 128, tmp_str, tc);
+    gtk_label_set_text ( GTK_LABEL(progress_label), s );
+    gtk_widget_show ( progress_label );
   }
+  sess->id_total_count = 0;
   g_mutex_unlock(sess->mutex);
-  gdk_threads_leave();
+  return FALSE;
 }
 
-static void set_current_count(gint cnt, GpsSession *sess)
+static gboolean show_current_count(GpsSession *sess)
 {
-  gchar s[128];
-  const gchar *tmp_str;
-
-  gdk_threads_enter();
   g_mutex_lock(sess->mutex);
   if (sess->ok) {
-    if (cnt < sess->total_count) {
-      if (sess->direction == GPS_DOWN)
-      {
+    gchar s[128];
+    gint count, total_count;
+    const gchar *tmp_str;
+    GtkWidget *progress_label;
+    if (sess->wpt_count < sess->wpt_total_count) {
+      if (sess->direction == GPS_DOWN) {
         switch (sess->progress_type) {
-        case WPT: tmp_str = ngettext("Downloaded %d out of %d waypoint...", "Downloaded %d out of %d waypoints...", sess->total_count); break;
-        case TRK: tmp_str = ngettext("Downloaded %d out of %d trackpoint...", "Downloaded %d out of %d trackpoints...", sess->total_count); break;
-        default: tmp_str = ngettext("Downloaded %d out of %d routepoint...", "Downloaded %d out of %d routepoints...", sess->total_count); break;
+        case WPT:
+         tmp_str = ngettext("Downloaded %d out of %d waypoint...", "Downloaded %d out of %d waypoints...", sess->wpt_total_count);
+         count = sess->wpt_count;
+         total_count = sess->wpt_total_count;
+         progress_label = sess->wpt_label;
+         break;
+        case TRK:
+         tmp_str = ngettext("Downloaded %d out of %d trackpoint...", "Downloaded %d out of %d trackpoints...", sess->trk_total_count);
+         count = sess->trk_count;
+         total_count = sess->trk_total_count;
+         progress_label = sess->trk_label;
+         break;
+        default:
+         tmp_str = ngettext("Downloaded %d out of %d routepoint...", "Downloaded %d out of %d routepoints...", sess->rte_total_count);
+         count = sess->rte_count;
+         total_count = sess->rte_total_count;
+         progress_label = sess->rte_label;
+         break;
         }
       }
       else {
         switch (sess->progress_type) {
-        case WPT: tmp_str = ngettext("Uploaded %d out of %d waypoint...", "Uploaded %d out of %d waypoints...", sess->total_count); break;
-        case TRK: tmp_str = ngettext("Uploaded %d out of %d trackpoint...", "Uploaded %d out of %d trackpoints...", sess->total_count); break;
-        default: tmp_str = ngettext("Uploaded %d out of %d routepoint...", "Uploaded %d out of %d routepoints...", sess->total_count); break;
-       }
+        case WPT:
+         tmp_str = ngettext("Uploaded %d out of %d waypoint...", "Uploaded %d out of %d waypoints...", sess->wpt_total_count);
+         count = sess->wpt_count;
+         total_count = sess->wpt_total_count;
+         progress_label = sess->wpt_label;
+         break;
+        case TRK:
+         tmp_str = ngettext("Uploaded %d out of %d trackpoint...", "Uploaded %d out of %d trackpoints...", sess->trk_total_count);
+         count = sess->trk_count;
+         total_count = sess->trk_total_count;
+         progress_label = sess->trk_label;
+         break;
+        default:
+         tmp_str = ngettext("Uploaded %d out of %d routepoint...", "Uploaded %d out of %d routepoints...", sess->rte_total_count);
+         count = sess->rte_count;
+         total_count = sess->rte_total_count;
+         progress_label = sess->rte_label;
+         break;
+        }
       }
-      g_snprintf(s, 128, tmp_str, cnt, sess->total_count);
     } else {
-      if (sess->direction == GPS_DOWN)
-      {
+      if (sess->direction == GPS_DOWN) {
         switch (sess->progress_type) {
-        case WPT: tmp_str = ngettext("Downloaded %d waypoint", "Downloaded %d waypoints", cnt); break;
-        case TRK: tmp_str = ngettext("Downloaded %d trackpoint", "Downloaded %d trackpoints", cnt); break;
-        default: tmp_str = ngettext("Downloaded %d routepoint", "Downloaded %d routepoints", cnt); break;
-       }
+        case WPT:
+         tmp_str = ngettext("Downloaded %d waypoint", "Downloaded %d waypoints", sess->wpt_count);
+         count = sess->wpt_count;
+         total_count = sess->wpt_total_count;
+         progress_label = sess->wpt_label;
+         break;
+        case TRK:
+         tmp_str = ngettext("Downloaded %d trackpoint", "Downloaded %d trackpoints", sess->trk_count);
+         count = sess->trk_count;
+         total_count = sess->trk_total_count;
+         progress_label = sess->trk_label;
+         break;
+        default:
+         tmp_str = ngettext("Downloaded %d routepoint", "Downloaded %d routepoints", sess->rte_count);
+         count = sess->rte_count;
+         total_count = sess->rte_total_count;
+         progress_label = sess->rte_label;
+         break;
+        }
       }
       else {
         switch (sess->progress_type) {
-        case WPT: tmp_str = ngettext("Uploaded %d waypoint", "Uploaded %d waypoints", cnt); break;
-        case TRK: tmp_str = ngettext("Uploaded %d trackpoint", "Uploaded %d trackpoints", cnt); break;
-        default: tmp_str = ngettext("Uploaded %d routepoint", "Uploaded %d routepoints", cnt); break;
-       }
+        case WPT:
+         tmp_str = ngettext("Uploaded %d waypoint", "Uploaded %d waypoints", sess->wpt_count);
+         count = sess->wpt_count;
+         total_count = sess->wpt_total_count;
+         progress_label = sess->wpt_label;
+         break;
+        case TRK:
+         tmp_str = ngettext("Uploaded %d trackpoint", "Uploaded %d trackpoints", sess->trk_count);
+         count = sess->trk_count;
+         total_count = sess->trk_total_count;
+         progress_label = sess->trk_label;
+         break;
+        default:
+         tmp_str = ngettext("Uploaded %d routepoint", "Uploaded %d routepoints", sess->rte_count);
+         count = sess->rte_count;
+         total_count = sess->rte_total_count;
+         progress_label = sess->rte_label;
+         break;
+        }
       }
-      g_snprintf(s, 128, tmp_str, cnt);
-    }    
-    gtk_label_set_text ( GTK_LABEL(sess->progress_label), s );
+    }
+    g_snprintf(s, 128, tmp_str, count, total_count);
+    gtk_label_set_text ( GTK_LABEL(progress_label), s );
   }
+  sess->id_count = 0;
   g_mutex_unlock(sess->mutex);
-  gdk_threads_leave();
+  return FALSE;
 }
 
-static void set_gps_info(const gchar *info, GpsSession *sess)
+static gboolean show_gps_info(GpsSession *sess)
 {
-  gchar s[256];
-  gdk_threads_enter();
   g_mutex_lock(sess->mutex);
   if (sess->ok) {
-    g_snprintf(s, 256, _("GPS Device: %s"), info);
+    gchar s[256];
+    g_snprintf(s, 256, _("GPS Device: %s"), sess->info);
     gtk_label_set_text ( GTK_LABEL(sess->gps_label), s );
   }
+  sess->id_info = 0;
   g_mutex_unlock(sess->mutex);
-  gdk_threads_leave();
+  return FALSE;
 }
 
 /*
@@ -1048,7 +1156,8 @@ static void process_line_for_gps_info ( const gchar *line, GpsSession *sess )
         info[ilen++] = ch;
       }
       info[ilen++] = 0;
-      set_gps_info(info, sess);
+      sess->info = g_strdup (info);
+      sess->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, sess );
     }
     g_strfreev(tokens);
   }
@@ -1061,50 +1170,48 @@ static void process_line_for_gps_info ( const gchar *line, GpsSession *sess )
       n_tokens++;
 
     if (n_tokens > 1) {
-      set_gps_info(tokens[1], sess);
+      sess->info = g_strdup (tokens[1]);
+      sess->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, sess );
     }
     g_strfreev(tokens);
   }
+
+static gboolean show_gps_status_working ( GpsSession *sess )
+{
+  g_mutex_lock(sess->mutex);
+  if ( sess->ok ) {
+    gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Status: Working...") );
+  }
+  sess->id_status_working = 0;
+  g_mutex_unlock(sess->mutex);
+  return FALSE;
 }
 
 static void gps_download_progress_func(BabelProgressCode c, gpointer data, GpsSession * sess )
 {
   gchar *line;
 
-  gdk_threads_enter ();
-  g_mutex_lock(sess->mutex);
-  if (!sess->ok) {
-    g_mutex_unlock(sess->mutex);
-    gps_session_delete(sess);
-    gdk_threads_leave();
+  if ( !sess->ok ) {
+    //gps_session_delete(sess);
+    sess->thread_complete = TRUE;
+    g_debug ("THREAD EXIT INTERUPPT");
     g_thread_exit ( NULL );
   }
-  g_mutex_unlock(sess->mutex);
-  gdk_threads_leave ();
 
   switch(c) {
   case BABEL_DIAG_OUTPUT:
     line = (gchar *)data;
 
-    gdk_threads_enter();
-    g_mutex_lock(sess->mutex);
-    if (sess->ok) {
-      gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Status: Working...") );
-    }
-    g_mutex_unlock(sess->mutex);
-    gdk_threads_leave();
+    sess->id_status_working = gdk_threads_add_idle ( (GSourceFunc)show_gps_status_working, sess );
 
     /* tells us the type of items that will follow */
     if (strstr(line, "Xfer Wpt")) {
-      sess->progress_label = sess->wp_label;
       sess->progress_type = WPT;
     }
     if (strstr(line, "Xfer Trk")) {
-      sess->progress_label = sess->trk_label;
       sess->progress_type = TRK;
     }
     if (strstr(line, "Xfer Rte")) {
-      sess->progress_label = sess->rte_label;
       sess->progress_type = RTE;
     }
 
@@ -1117,13 +1224,32 @@ static void gps_download_progress_func(BabelProgressCode c, gpointer data, GpsSe
         sscanf(line+17, "%x", &lsb); 
         sscanf(line+20, "%x", &msb);
         cnt = lsb + msb * 256;
-        set_total_count(cnt, sess);
-        sess->count = 0;
+        if ( sess->progress_type == RTE ) {
+          // Maybe a gpsbabel bug/feature (upto at least v1.4.3 or maybe my Garmin device) but the count always seems x2 too many for routepoints
+          gint mycnt = (cnt / 2) + 1;
+          sess->rte_total_count = mycnt;
+          sess->rte_count = 0;
+        }
+        else if ( sess->progress_type == WPT ) {
+          sess->wpt_total_count = cnt;
+          sess->wpt_count = 0;
+        }
+        else {
+          sess->trk_total_count = cnt;
+          sess->trk_count = 0;
+        }
+        sess->id_total_count = gdk_threads_add_idle ( (GSourceFunc)show_total_count, sess);
       }
     }
     if ( strstr(line, "WPTDAT") || strstr(line, "TRKHDR") || strstr(line, "TRKDAT") || strstr(line, "RTEHDR") || strstr(line, "RTEWPT") ) {
-      sess->count++;
-      set_current_count(sess->count, sess);
+      if ( strstr(line, "WPTDAT") )
+        sess->wpt_count++;
+      else if ( strstr(line, "TRKHDR") || strstr(line, "TRKDAT") )
+        sess->trk_count++;
+      else
+        // "RTEHDR" || "RTEWPT"
+        sess->rte_count++;
+      sess->id_count = gdk_threads_add_idle ( (GSourceFunc)show_current_count, sess);
     }
     break;
   case BABEL_DONE:
@@ -1131,7 +1257,6 @@ static void gps_download_progress_func(BabelProgressCode c, gpointer data, GpsSe
   default:
     break;
   }
-
 }
 
 static void gps_upload_progress_func(BabelProgressCode c, gpointer data, GpsSession * sess )
@@ -1139,28 +1264,17 @@ static void gps_upload_progress_func(BabelProgressCode c, gpointer data, GpsSess
   gchar *line;
   static int cnt = 0;
 
-  gdk_threads_enter ();
-  g_mutex_lock(sess->mutex);
-  if (!sess->ok) {
-    g_mutex_unlock(sess->mutex);
-    gps_session_delete(sess);
-    gdk_threads_leave();
+  if ( !sess->ok ) {
+    //gps_session_delete(sess);
+    sess->thread_complete = TRUE;
     g_thread_exit ( NULL );
   }
-  g_mutex_unlock(sess->mutex);
-  gdk_threads_leave ();
 
   switch(c) {
   case BABEL_DIAG_OUTPUT:
     line = (gchar *)data;
 
-    gdk_threads_enter();
-    g_mutex_lock(sess->mutex);
-    if (sess->ok) {
-      gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Status: Working...") );
-    }
-    g_mutex_unlock(sess->mutex);
-    gdk_threads_leave();
+    sess->id_status_working = gdk_threads_add_idle ( (GSourceFunc)show_gps_status_working, sess );
 
     process_line_for_gps_info ( line, sess );
 
@@ -1171,39 +1285,36 @@ static void gps_upload_progress_func(BabelProgressCode c, gpointer data, GpsSess
         sscanf(line+17, "%x", &lsb); 
         sscanf(line+20, "%x", &msb);
         cnt = lsb + msb * 256;
-        /* set_total_count(cnt, sess); */
-        sess->count = 0;
+        //sess->count = 0; ?? wpt, trk and/or rte?? or none
       }
     }
     if ( strstr(line, "WPTDAT")) {
-      if (sess->count == 0) {
-        sess->progress_label = sess->wp_label;
-        sess->progress_type = WPT;
-        set_total_count(cnt, sess);
+      sess->progress_type = WPT;
+      if (sess->wpt_count == 0) {
+        sess->wpt_total_count = cnt;
+        sess->id_total_count = gdk_threads_add_idle ( (GSourceFunc)show_total_count, sess );
       }
-      sess->count++;
-      set_current_count(sess->count, sess);
+      sess->wpt_count++;
+      sess->id_count = gdk_threads_add_idle ( (GSourceFunc)show_current_count, sess );
     }
     if ( strstr(line, "RTEHDR") || strstr(line, "RTEWPT") ) {
-       if (sess->count == 0) {
-         sess->progress_label = sess->rte_label;
-         sess->progress_type = RTE;
-         // Maybe a gpsbabel bug/feature (upto at least v1.4.3 or maybe my Garmin device) but the count always seems x2 too many for routepoints
-         // Anyway since we're uploading - we should know how many points we're going to put!
-         cnt = (cnt / 2) + 1;
-         set_total_count(cnt, sess);
-       }
-       sess->count++;
-       set_current_count(sess->count, sess);
+      sess->progress_type = RTE;
+      if (sess->rte_count == 0) {
+        // Maybe a gpsbabel bug/feature (upto at least v1.4.3 or maybe my Garmin device) but the count always seems x2 too many for routepoints
+        // Anyway since we're uploading - we should know how many points we're going to put!
+        cnt = (cnt / 2) + 1;
+        sess->id_total_count = gdk_threads_add_idle ( (GSourceFunc)show_total_count, sess);
+      }
+      sess->rte_count++;
+      sess->id_count = gdk_threads_add_idle ( (GSourceFunc)show_current_count, sess);
     }
     if ( strstr(line, "TRKHDR") || strstr(line, "TRKDAT") ) {
-      if (sess->count == 0) {
-        sess->progress_label = sess->trk_label;
-       sess->progress_type = TRK;
-        set_total_count(cnt, sess);
+      sess->progress_type = TRK;
+      if (sess->trk_count == 0) {
+        sess->id_total_count = gdk_threads_add_idle ( (GSourceFunc)show_total_count, sess);
       }
-      sess->count++;
-      set_current_count(sess->count, sess);
+      sess->trk_count++;
+      sess->id_count = gdk_threads_add_idle ( (GSourceFunc)show_current_count, sess);
     }
     break;
   case BABEL_DONE:
@@ -1211,32 +1322,45 @@ static void gps_upload_progress_func(BabelProgressCode c, gpointer data, GpsSess
   default:
     break;
   }
+}
 
+static gboolean show_gps_status_end ( GpsSession *sess )
+{
+  g_mutex_lock(sess->mutex);
+  // (Download)Failure could be due to a number of reasons: such as no/wrong device attached or GPSBabel not installed
+  if (!sess->result) {
+    gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Error: No result.") );
+  }
+  else {
+    if (sess->ok) {
+      gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Done.") );
+      gtk_dialog_set_response_sensitive ( GTK_DIALOG(sess->dialog), GTK_RESPONSE_ACCEPT, TRUE );
+      gtk_dialog_set_response_sensitive ( GTK_DIALOG(sess->dialog), GTK_RESPONSE_REJECT, FALSE );
+    }
+  }
+  sess->id_status_end = 0;
+  g_mutex_unlock(sess->mutex);
+  return FALSE;
 }
 
+/**
+ *
+ */
 static void gps_comm_thread(GpsSession *sess)
 {
-  gboolean result;
-
   if (sess->direction == GPS_DOWN) {
     ProcessOptions po = { sess->babelargs, sess->port, NULL, NULL, NULL, NULL };
-    result = a_babel_convert_from (sess->vtl, &po, (BabelStatusFunc) gps_download_progress_func, sess, NULL);
+    sess->result = a_babel_convert_from (sess->vtl, &po, (BabelStatusFunc) gps_download_progress_func, sess, NULL);
   }
   else {
-    result = a_babel_convert_to (sess->vtl, sess->track, sess->babelargs, sess->port,
+    sess->result = a_babel_convert_to (sess->vtl, sess->track, sess->babelargs, sess->port,
         (BabelStatusFunc) gps_upload_progress_func, sess);
   }
 
-  if (!result) {
-    gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Error: couldn't find gpsbabel.") );
-  } 
-  else {
-    g_mutex_lock(sess->mutex);
+  sess->id_status_end = gdk_threads_add_idle ( (GSourceFunc)show_gps_status_end, sess );
+  
+  if (sess->result) {
     if (sess->ok) {
-      gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Done.") );
-      gtk_dialog_set_response_sensitive ( GTK_DIALOG(sess->dialog), GTK_RESPONSE_ACCEPT, TRUE );
-      gtk_dialog_set_response_sensitive ( GTK_DIALOG(sess->dialog), GTK_RESPONSE_REJECT, FALSE );
-
       /* Do not change the view if we are following the current GPS position */
 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
       if (!sess->realtime_tracking)
@@ -1246,24 +1370,20 @@ static void gps_comm_thread(GpsSession *sess)
           vik_layer_post_read ( VIK_LAYER(sess->vtl), sess->vvp, TRUE );
           /* View the data available */
           vik_trw_layer_auto_set_view ( sess->vtl, sess->vvp ) ;
-          vik_layer_emit_update ( VIK_LAYER(sess->vtl) ); // NB update from background thread
+          vik_layer_emit_update ( VIK_LAYER(sess->vtl) ); // NB update request from background thread
         }
       }
     } else {
-      /* canceled */
+      /* cancelled */
     }
-    g_mutex_unlock(sess->mutex);
   }
 
-  g_mutex_lock(sess->mutex);
   if (sess->ok) {
+    // Thread has completed successfully, but now set to false to avoid 'tell thread to stop' test after dialog run
     sess->ok = FALSE;
-    g_mutex_unlock(sess->mutex);
-  }
-  else {
-    g_mutex_unlock(sess->mutex);
-    gps_session_delete(sess);
   }
+
+  sess->thread_complete = TRUE;
   g_thread_exit(NULL);
 }
 
@@ -1296,7 +1416,7 @@ gint vik_gps_comm ( VikTrwLayer *vtl,
                     gboolean do_waypoints,
                    gboolean turn_off )
 {
-  GpsSession *sess = g_malloc(sizeof(GpsSession));
+  GpsSession *sess = g_malloc0(sizeof(GpsSession));
   char *tracks = NULL;
   char *routes = NULL;
   char *waypoints = NULL;
@@ -1307,7 +1427,6 @@ gint vik_gps_comm ( VikTrwLayer *vtl,
   sess->track = track;
   sess->port = g_strdup(port);
   sess->ok = TRUE;
-  sess->window_title = (dir == GPS_DOWN) ? _("GPS Download") : _("GPS Upload");
   sess->vvp = vvp;
 
   // This must be done inside the main thread as the uniquify causes screen updates
@@ -1343,34 +1462,32 @@ gint vik_gps_comm ( VikTrwLayer *vtl,
   tracks = NULL;
   waypoints = NULL;
 
+  GtkWidget *dialog = NULL;
+
   // Only create dialog if we're going to do some transferring
   if ( do_tracks || do_waypoints || do_routes ) {
-    sess->dialog = gtk_dialog_new_with_buttons ( "", VIK_GTK_WINDOW_FROM_LAYER(vtl), 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL );
+    dialog = gtk_dialog_new_with_buttons ( "", VIK_GTK_WINDOW_FROM_LAYER(vtl), 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL );
+    sess->dialog = dialog;
     gtk_dialog_set_response_sensitive ( GTK_DIALOG(sess->dialog),
                                         GTK_RESPONSE_ACCEPT, FALSE );
-    gtk_window_set_title ( GTK_WINDOW(sess->dialog), sess->window_title );
+    gtk_window_set_title ( GTK_WINDOW(sess->dialog), (dir == GPS_DOWN) ? _("GPS Download") : _("GPS Upload") );
 
     sess->status_label = gtk_label_new (_("Status: detecting gpsbabel"));
     gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->status_label, FALSE, FALSE, 5 );
-    gtk_widget_show_all(sess->status_label);
 
     sess->gps_label = gtk_label_new (_("GPS device: N/A"));
-    sess->ver_label = gtk_label_new ("");
-    sess->id_label = gtk_label_new ("");
-    sess->wp_label = gtk_label_new ("");
+    sess->wpt_label = gtk_label_new ("");
     sess->trk_label = gtk_label_new ("");
     sess->rte_label = gtk_label_new ("");
 
     gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->gps_label, FALSE, FALSE, 5 );
-    gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->wp_label, FALSE, FALSE, 5 );
+    gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->wpt_label, FALSE, FALSE, 5 );
     gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->trk_label, FALSE, FALSE, 5 );
     gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->rte_label, FALSE, FALSE, 5 );
 
     gtk_widget_show_all(sess->dialog);
 
-    sess->progress_label = sess->wp_label;
-    sess->total_count = -1;
-
+    gtk_dialog_set_default_response ( GTK_DIALOG(sess->dialog), GTK_RESPONSE_ACCEPT );
     // Starting gps read/write thread
 #if GLIB_CHECK_VERSION (2, 32, 0)
     g_thread_try_new ( "gps_comm_thread", (GThreadFunc)gps_comm_thread, sess, NULL );
@@ -1378,21 +1495,15 @@ gint vik_gps_comm ( VikTrwLayer *vtl,
     g_thread_create ( (GThreadFunc)gps_comm_thread, sess, FALSE, NULL );
 #endif
 
-    gtk_dialog_set_default_response ( GTK_DIALOG(sess->dialog), GTK_RESPONSE_ACCEPT );
-    gtk_dialog_run(GTK_DIALOG(sess->dialog));
-
-    gtk_widget_destroy(sess->dialog);
+    gtk_dialog_run(GTK_DIALOG(dialog));
   }
   else {
     if ( !turn_off )
       a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No GPS items selected for transfer.") );
   }
 
-  g_mutex_lock(sess->mutex);
-
   if (sess->ok) {
     sess->ok = FALSE;   /* tell thread to stop */
-    g_mutex_unlock(sess->mutex);
   }
   else {
     if ( turn_off ) {
@@ -1404,10 +1515,15 @@ gint vik_gps_comm ( VikTrwLayer *vtl,
         a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not turn off device.") );
       g_free ( device_off );
     }
-    g_mutex_unlock(sess->mutex);
-    gps_session_delete(sess);
   }
 
+  if ( dialog ) {
+    while ( !sess->thread_complete ) {
+      g_usleep (G_USEC_PER_SEC/10);
+    }
+    gtk_widget_destroy(dialog);
+  }
+  gps_session_delete(sess);
   return 0;
 }
 
index 00055b1c461f9e93974d52d519d827a7cb61c270..25bb2a98544b73336592e136d7588819e82c51ff 100644 (file)
@@ -9535,10 +9535,8 @@ static gboolean tool_sync_done = TRUE;
 static gboolean tool_sync(gpointer data)
 {
   VikViewport *vvp = data;
-  gdk_threads_enter();
   vik_viewport_sync(vvp);
   tool_sync_done = TRUE;
-  gdk_threads_leave();
   return FALSE;
 }
 
@@ -9780,13 +9778,11 @@ static gboolean draw_sync ( gpointer data )
   //  normally because another update has taken precedent such as panning the display
   //   which means this pixmap is no longer valid
   if ( ds->vtl->draw_sync_do ) {
-    gdk_threads_enter();
     gdk_draw_drawable (ds->drawable,
                        ds->gc,
                        ds->pixmap,
                        0, 0, 0, 0, -1, -1);
     ds->vtl->draw_sync_done = TRUE;
-    gdk_threads_leave();
   }
   g_free ( ds );
   return FALSE;
index f6ff4fbf01394d896b855270a5dbe0805be840a8..875b52852a978180e374ed557809cee3f470b05e 100644 (file)
@@ -1205,11 +1205,9 @@ gboolean draw_buf_done = TRUE;
 static gboolean draw_buf(gpointer data)
 {
   gpointer *pass_along = data;
-  gdk_threads_enter();
   gdk_draw_drawable (pass_along[0], pass_along[1],
                     pass_along[2], 0, 0, 0, 0, -1, -1);
   draw_buf_done = TRUE;
-  gdk_threads_leave();
   return FALSE;
 }