+static gboolean rt_gpsd_try_connect(gpointer *data)
+{
+ VikGpsLayer *vgl = (VikGpsLayer *)data;
+#if GPSD_API_MAJOR_VERSION == 3
+ struct gps_data_t *gpsd = gps_open(vgl->gpsd_host, vgl->gpsd_port);
+
+ if (gpsd == NULL) {
+#elif GPSD_API_MAJOR_VERSION == 4
+ vgl->vgpsd = g_malloc(sizeof(VglGpsd));
+
+ if (gps_open_r(vgl->gpsd_host, vgl->gpsd_port, /*(struct gps_data_t *)*/vgl->vgpsd) != 0) {
+#elif GPSD_API_MAJOR_VERSION == 5
+ vgl->vgpsd = g_malloc(sizeof(VglGpsd));
+ if (gps_open(vgl->gpsd_host, vgl->gpsd_port, &vgl->vgpsd->gpsd) != 0) {
+#else
+// Delibrately break compilation...
+#endif
+ g_warning("Failed to connect to gpsd at %s (port %s). Will retry in %d seconds",
+ vgl->gpsd_host, vgl->gpsd_port, vgl->gpsd_retry_interval);
+ return TRUE; /* keep timer running */
+ }
+
+#if GPSD_API_MAJOR_VERSION == 3
+ vgl->vgpsd = realloc(gpsd, sizeof(VglGpsd));
+#endif
+ vgl->vgpsd->vgl = vgl;
+
+ vgl->realtime_fix.dirty = vgl->last_fix.dirty = FALSE;
+ /* track alt/time graph uses VIK_DEFAULT_ALTITUDE (0.0) as invalid */
+ vgl->realtime_fix.fix.altitude = vgl->last_fix.fix.altitude = VIK_DEFAULT_ALTITUDE;
+ vgl->realtime_fix.fix.speed = vgl->last_fix.fix.speed = NAN;
+
+ if (vgl->realtime_record) {
+ VikTrwLayer *vtl = vgl->trw_children[TRW_REALTIME];
+ vgl->realtime_track = vik_track_new();
+ vgl->realtime_track->visible = TRUE;
+ vik_trw_layer_add_track(vtl, make_track_name(vtl), vgl->realtime_track);
+ }
+
+#if GPSD_API_MAJOR_VERSION == 3 || GPSD_API_MAJOR_VERSION == 4
+ gps_set_raw_hook(&vgl->vgpsd->gpsd, gpsd_raw_hook);
+#endif
+
+ vgl->realtime_io_channel = g_io_channel_unix_new(vgl->vgpsd->gpsd.gps_fd);
+ vgl->realtime_io_watch_id = g_io_add_watch( vgl->realtime_io_channel,
+ G_IO_IN | G_IO_ERR | G_IO_HUP, gpsd_data_available, vgl);
+
+#if GPSD_API_MAJOR_VERSION == 3
+ gps_query(&vgl->vgpsd->gpsd, "w+x");
+#endif
+#if GPSD_API_MAJOR_VERSION == 4 || GPSD_API_MAJOR_VERSION == 5
+ gps_stream(&vgl->vgpsd->gpsd, WATCH_ENABLE, NULL);
+#endif
+
+ return FALSE; /* no longer called by timeout */
+}
+
+static gboolean rt_ask_retry(VikGpsLayer *vgl)
+{
+ GtkWidget *dialog = gtk_message_dialog_new (VIK_GTK_WINDOW_FROM_LAYER(vgl),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ "Failed to connect to gpsd at %s (port %s)\n"
+ "Should Viking keep trying (every %d seconds)?",
+ vgl->gpsd_host, vgl->gpsd_port,
+ vgl->gpsd_retry_interval);
+
+ gint res = gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ return (res == GTK_RESPONSE_YES);
+}
+
+static gboolean rt_gpsd_connect(VikGpsLayer *vgl, gboolean ask_if_failed)
+{
+ vgl->realtime_retry_timer = 0;
+ if (rt_gpsd_try_connect((gpointer *)vgl)) {
+ if (vgl->gpsd_retry_interval <= 0) {
+ g_warning("Failed to connect to gpsd but will not retry because retry intervel was set to %d (which is 0 or negative)", vgl->gpsd_retry_interval);
+ return FALSE;
+ }
+ else if (ask_if_failed && !rt_ask_retry(vgl))
+ return FALSE;
+ else
+ vgl->realtime_retry_timer = g_timeout_add_seconds(vgl->gpsd_retry_interval,
+ (GSourceFunc)rt_gpsd_try_connect, (gpointer *)vgl);
+ }
+ return TRUE;
+}
+
+static void rt_gpsd_disconnect(VikGpsLayer *vgl)
+{
+ if (vgl->realtime_retry_timer) {
+ g_source_remove(vgl->realtime_retry_timer);
+ vgl->realtime_retry_timer = 0;
+ }
+ if (vgl->realtime_io_watch_id) {
+ g_source_remove(vgl->realtime_io_watch_id);
+ vgl->realtime_io_watch_id = 0;
+ }
+ if (vgl->realtime_io_channel) {
+ GError *error = NULL;
+ g_io_channel_shutdown (vgl->realtime_io_channel, FALSE, &error);
+ vgl->realtime_io_channel = NULL;
+ }
+ if (vgl->vgpsd) {
+#if GPSD_API_MAJOR_VERSION == 4 || GPSD_API_MAJOR_VERSION == 5
+ gps_stream(&vgl->vgpsd->gpsd, WATCH_DISABLE, NULL);
+#endif
+ gps_close(&vgl->vgpsd->gpsd);
+#if GPSD_API_MAJOR_VERSION == 3
+ free(vgl->vgpsd);
+#elif GPSD_API_MAJOR_VERSION == 4 || GPSD_API_MAJOR_VERSION == 5
+ g_free(vgl->vgpsd);
+#endif
+ vgl->vgpsd = NULL;
+ }
+
+ if (vgl->realtime_record && vgl->realtime_track) {
+ if ((vgl->realtime_track->trackpoints == NULL) || (vgl->realtime_track->trackpoints->next == NULL))
+ vik_trw_layer_delete_track(vgl->trw_children[TRW_REALTIME], vgl->realtime_track);
+ vgl->realtime_track = NULL;
+ }
+}
+