]> git.street.me.uk Git - andy/viking.git/blobdiff - src/vikwindow.c
SF BugsZZ#123: Fix bzip2 decompression on Windows.
[andy/viking.git] / src / vikwindow.c
index 8ae5efae513d488eb26230ca4ca8be483e7322fa..6d4ccf443472b27f2e1fea55c255fc0c6c8f9982 100644 (file)
@@ -76,6 +76,10 @@ static GSList *window_list = NULL;
 #define DRAW_IMAGE_DEFAULT_HEIGHT 1024
 #define DRAW_IMAGE_DEFAULT_SAVE_AS_PNG TRUE
 
+// The last used directories
+static gchar *last_folder_files_uri = NULL;
+static gchar *last_folder_images_uri = NULL;
+
 static void window_finalize ( GObject *gob );
 static GObjectClass *parent_class;
 
@@ -204,9 +208,6 @@ struct _VikWindow {
   gboolean modified;
   VikLoadType_t loaded_type;
 
-  GtkWidget *open_dia, *save_dia;
-  GtkWidget *save_img_dia, *save_img_dir_dia;
-
   gboolean only_updating_coord_mode_ui; /* hack for a bug in GTK */
   GtkUIManager *uim;
 
@@ -305,12 +306,17 @@ static gboolean statusbar_idle_update ( statusbar_idle_data *sid )
  */
 void vik_window_statusbar_update ( VikWindow *vw, const gchar* message, vik_statusbar_type_t vs_type )
 {
+  GThread *thread = vik_window_get_thread ( vw );
+  if ( !thread )
+    // Do nothing
+    return;
+
   statusbar_idle_data *sid = g_malloc ( sizeof (statusbar_idle_data) );
   sid->vs = vw->viking_vs;
   sid->vs_type = vs_type;
   sid->message = g_strdup ( message );
 
-  if ( g_thread_self() == vik_window_get_thread ( vw ) ) {
+  if ( g_thread_self() == thread ) {
     g_idle_add ( (GSourceFunc) statusbar_idle_update, sid );
   }
   else {
@@ -323,8 +329,11 @@ void vik_window_statusbar_update ( VikWindow *vw, const gchar* message, vik_stat
 static void destroy_window ( GtkWidget *widget,
                              gpointer   data )
 {
-    if ( ! --window_count )
+    if ( ! --window_count ) {
+      g_free ( last_folder_files_uri );
+      g_free ( last_folder_images_uri );
       gtk_main_quit ();
+    }
 }
 
 #define VIK_SETTINGS_WIN_SIDEPANEL "window_sidepanel"
@@ -474,7 +483,8 @@ void vik_window_new_window_finish ( VikWindow *vw )
 
       vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_INFO, _("Trying to determine location...") );
 
-      a_background_thread ( GTK_WINDOW(vw),
+      a_background_thread ( BACKGROUND_POOL_REMOTE,
+                            GTK_WINDOW(vw),
                             _("Determining location"),
                             (vik_thr_func) determine_location_thread,
                             vw,
@@ -575,7 +585,7 @@ static void zoom_changed (GtkMenuShell *menushell,
   GtkWidget *aw = gtk_menu_get_active ( GTK_MENU (menushell) );
   gint active = GPOINTER_TO_INT(g_object_get_data ( G_OBJECT (aw), "position" ));
 
-  gdouble zoom_request = pow (2, active-2 );
+  gdouble zoom_request = pow (2, active-5 );
 
   // But has it really changed?
   gdouble current_zoom = vik_viewport_get_zoom ( vw->viking_vvp );
@@ -592,7 +602,7 @@ static void zoom_changed (GtkMenuShell *menushell,
 static GtkWidget *create_zoom_menu_all_levels ( gdouble mpp )
 {
   GtkWidget *menu = gtk_menu_new ();
-  char *itemLabels[] = { "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384", "32768" };
+  char *itemLabels[] = { "0.031", "0.063", "0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384", "32768" };
 
   int i;
   for (i = 0 ; i < G_N_ELEMENTS(itemLabels) ; i++)
@@ -603,7 +613,7 @@ static GtkWidget *create_zoom_menu_all_levels ( gdouble mpp )
       g_object_set_data (G_OBJECT (item), "position", GINT_TO_POINTER(i));
     }
 
-  gint active = 2 + round ( log (mpp) / log (2) );
+  gint active = 5 + round ( log (mpp) / log (2) );
   // Ensure value derived from mpp is in bounds of the menu
   if ( active >= G_N_ELEMENTS(itemLabels) )
     active = G_N_ELEMENTS(itemLabels) - 1;
@@ -830,7 +840,7 @@ static void vik_window_init ( VikWindow *vw )
   center_changed_cb ( vw );
 
   vw->hpaned = gtk_hpaned_new ();
-  gtk_paned_pack1 ( GTK_PANED(vw->hpaned), GTK_WIDGET (vw->viking_vlp), FALSE, FALSE );
+  gtk_paned_pack1 ( GTK_PANED(vw->hpaned), GTK_WIDGET (vw->viking_vlp), FALSE, TRUE );
   gtk_paned_pack2 ( GTK_PANED(vw->hpaned), GTK_WIDGET (vw->viking_vvp), TRUE, TRUE );
 
   /* This packs the button into the window (a gtk container). */
@@ -889,11 +899,6 @@ static void vik_window_init ( VikWindow *vw )
 
   gtk_window_set_default_size ( GTK_WINDOW(vw), width, height );
 
-  vw->open_dia = NULL;
-  vw->save_dia = NULL;
-  vw->save_img_dia = NULL;
-  vw->save_img_dir_dia = NULL;
-
   vw->show_side_panel = TRUE;
   vw->show_statusbar = TRUE;
   vw->show_toolbar = TRUE;
@@ -2147,42 +2152,56 @@ static void click_layer_selected (VikLayer *vl, clicker *ck)
        ck->cont = !vik_layer_get_interface(vl->type)->select_click ( vl, ck->event, ck->vvp, ck->tool_edit );
 }
 
+#ifdef WINDOWS
+// Hopefully Alt keys by default
+#define VIK_MOVE_MODIFIER GDK_MOD1_MASK
+#else
+// Alt+mouse on Linux desktops tend to be used by the desktop manager
+// Thus use an alternate modifier - you may need to set something into this group
+#define VIK_MOVE_MODIFIER GDK_MOD5_MASK
+#endif
+
 static VikLayerToolFuncStatus selecttool_click (VikLayer *vl, GdkEventButton *event, tool_ed_t *t)
 {
   t->vw->select_move = FALSE;
   /* Only allow selection on primary button */
   if ( event->button == 1 ) {
-    /* Enable click to apply callback to potentially all track/waypoint layers */
-    /* Useful as we can find things that aren't necessarily in the currently selected layer */
-    GList* gl = vik_layers_panel_get_all_layers_of_type ( t->vw->viking_vlp, VIK_LAYER_TRW, FALSE ); // Don't get invisible layers
-    clicker ck;
-    ck.cont = TRUE;
-    ck.vvp = t->vw->viking_vvp;
-    ck.event = event;
-    ck.tool_edit = t;
-    g_list_foreach ( gl, (GFunc) click_layer_selected, &ck );
-    g_list_free ( gl );
-
-    // If nothing found then deselect & redraw screen if necessary to remove the highlight
-    if ( ck.cont ) {
-      GtkTreeIter iter;
-      VikTreeview *vtv = vik_layers_panel_get_treeview ( t->vw->viking_vlp );
-
-      if ( vik_treeview_get_selected_iter ( vtv, &iter ) ) {
-       // Only clear if selected thing is a TrackWaypoint layer or a sublayer
-       gint type = vik_treeview_item_get_type ( vtv, &iter );
-       if ( type == VIK_TREEVIEW_TYPE_SUBLAYER ||
-            VIK_LAYER(vik_treeview_item_get_pointer ( vtv, &iter ))->type == VIK_LAYER_TRW ) {
+
+    if ( event->state & VIK_MOVE_MODIFIER )
+      vik_window_pan_click ( t->vw, event );
+    else {
+      /* Enable click to apply callback to potentially all track/waypoint layers */
+      /* Useful as we can find things that aren't necessarily in the currently selected layer */
+      GList* gl = vik_layers_panel_get_all_layers_of_type ( t->vw->viking_vlp, VIK_LAYER_TRW, FALSE ); // Don't get invisible layers
+      clicker ck;
+      ck.cont = TRUE;
+      ck.vvp = t->vw->viking_vvp;
+      ck.event = event;
+      ck.tool_edit = t;
+      g_list_foreach ( gl, (GFunc) click_layer_selected, &ck );
+      g_list_free ( gl );
+
+      // If nothing found then deselect & redraw screen if necessary to remove the highlight
+      if ( ck.cont ) {
+        GtkTreeIter iter;
+        VikTreeview *vtv = vik_layers_panel_get_treeview ( t->vw->viking_vlp );
+
+        if ( vik_treeview_get_selected_iter ( vtv, &iter ) ) {
+          // Only clear if selected thing is a TrackWaypoint layer or a sublayer
+          gint type = vik_treeview_item_get_type ( vtv, &iter );
+          if ( type == VIK_TREEVIEW_TYPE_SUBLAYER ||
+            VIK_LAYER(vik_treeview_item_get_pointer ( vtv, &iter ))->type == VIK_LAYER_TRW ) {
    
-         vik_treeview_item_unselect ( vtv, &iter );
-         if ( vik_window_clear_highlight ( t->vw ) )
-           draw_update ( t->vw );
-       }
+            vik_treeview_item_unselect ( vtv, &iter );
+            if ( vik_window_clear_highlight ( t->vw ) )
+              draw_update ( t->vw );
+          }
+        }
+      }
+      else {
+        // Something found - so enable movement
+        t->vw->select_move = TRUE;
       }
-    }
-    else {
-      // Something found - so enable movement
-      t->vw->select_move = TRUE;
     }
   }
   else if ( ( event->button == 3 ) && ( vl && ( vl->type == VIK_LAYER_TRW ) ) ) {
@@ -2204,19 +2223,30 @@ static VikLayerToolFuncStatus selecttool_move (VikLayer *vl, GdkEventMotion *eve
       if ( vik_layer_get_interface(VIK_LAYER_TRW)->select_move )
         vik_layer_get_interface(VIK_LAYER_TRW)->select_move ( vl, event, t->vvp, t );
   }
+  else
+    // Optional Panning
+    if ( event->state & VIK_MOVE_MODIFIER )
+      vik_window_pan_move ( t->vw, event );
+
   return VIK_LAYER_TOOL_ACK;
 }
 
 static VikLayerToolFuncStatus selecttool_release (VikLayer *vl, GdkEventButton *event, tool_ed_t *t)
 {
-  /* Only allow deselection on primary button */
-  if ( event->button == 1 ) {
+  if ( t->vw->select_move ) {
     // Don't care about vl here
     if ( t->vtl )
       if ( vik_layer_get_interface(VIK_LAYER_TRW)->select_release )
         vik_layer_get_interface(VIK_LAYER_TRW)->select_release ( (VikLayer*)t->vtl, event, t->vvp, t );
   }
 
+  if ( event->button == 1 && (event->state & VIK_MOVE_MODIFIER) )
+      vik_window_pan_release ( t->vw, event );
+
+  // Force pan off incase it was on
+  t->vw->pan_move = FALSE;
+  t->vw->pan_x = t->vw->pan_y = -1;
+
   // End of this select movement
   t->vw->select_move = FALSE;
 
@@ -3153,77 +3183,75 @@ static void load_file ( GtkAction *a, VikWindow *vw )
     g_critical("Houston, we've had a problem.");
     return;
   }
-    
-  if ( ! vw->open_dia )
-  {
-    vw->open_dia = gtk_file_chooser_dialog_new (_("Please select a GPS data file to open. "),
-                                                GTK_WINDOW(vw),
-                                                GTK_FILE_CHOOSER_ACTION_OPEN,
-                                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                                                GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
-                                                NULL);
-    gchar *cwd = g_get_current_dir();
-    if ( cwd ) {
-      gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER(vw->open_dia), cwd );
-      g_free ( cwd );
-    }
 
-    GtkFileFilter *filter;
-    // NB file filters are listed this way for alphabetical ordering
+  GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Please select a GPS data file to open. "),
+                                                   GTK_WINDOW(vw),
+                                                   GTK_FILE_CHOOSER_ACTION_OPEN,
+                                                   GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                                   GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+                                                   NULL);
+  if ( last_folder_files_uri )
+    gtk_file_chooser_set_current_folder_uri ( GTK_FILE_CHOOSER(dialog), last_folder_files_uri );
+
+  GtkFileFilter *filter;
+  // NB file filters are listed this way for alphabetical ordering
 #ifdef VIK_CONFIG_GEOCACHES
-    filter = gtk_file_filter_new ();
-    gtk_file_filter_set_name( filter, _("Geocaching") );
-    gtk_file_filter_add_pattern ( filter, "*.loc" ); // No MIME type available
-    gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->open_dia), filter);
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name( filter, _("Geocaching") );
+  gtk_file_filter_add_pattern ( filter, "*.loc" ); // No MIME type available
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
 #endif
 
-    filter = gtk_file_filter_new ();
-    gtk_file_filter_set_name( filter, _("Google Earth") );
-    gtk_file_filter_add_mime_type ( filter, "application/vnd.google-earth.kml+xml");
-    gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->open_dia), filter);
-
-    filter = gtk_file_filter_new ();
-    gtk_file_filter_set_name( filter, _("GPX") );
-    gtk_file_filter_add_pattern ( filter, "*.gpx" ); // No MIME type available
-    gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->open_dia), filter);
-
-    filter = gtk_file_filter_new ();
-    gtk_file_filter_set_name ( filter, _("JPG") );
-    gtk_file_filter_add_mime_type ( filter, "image/jpeg");
-    gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->open_dia), filter);
-
-    filter = gtk_file_filter_new ();
-    gtk_file_filter_set_name( filter, _("Viking") );
-    gtk_file_filter_add_pattern ( filter, "*.vik" );
-    gtk_file_filter_add_pattern ( filter, "*.viking" );
-    gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->open_dia), filter);
-
-    // NB could have filters for gpspoint (*.gps,*.gpsoint?) + gpsmapper (*.gsm,*.gpsmapper?)
-    // However assume this are barely used and thus not worthy of inclusion
-    //   as they'll just make the options too many and have no clear file pattern
-    //   one can always use the all option
-    filter = gtk_file_filter_new ();
-    gtk_file_filter_set_name( filter, _("All") );
-    gtk_file_filter_add_pattern ( filter, "*" );
-    gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->open_dia), filter);
-    // Default to any file - same as before open filters were added
-    gtk_file_chooser_set_filter (GTK_FILE_CHOOSER(vw->open_dia), filter);
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name( filter, _("Google Earth") );
+  gtk_file_filter_add_mime_type ( filter, "application/vnd.google-earth.kml+xml");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name( filter, _("GPX") );
+  gtk_file_filter_add_pattern ( filter, "*.gpx" ); // No MIME type available
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name ( filter, _("JPG") );
+  gtk_file_filter_add_mime_type ( filter, "image/jpeg");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name( filter, _("Viking") );
+  gtk_file_filter_add_pattern ( filter, "*.vik" );
+  gtk_file_filter_add_pattern ( filter, "*.viking" );
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
+
+  // NB could have filters for gpspoint (*.gps,*.gpsoint?) + gpsmapper (*.gsm,*.gpsmapper?)
+  // However assume this are barely used and thus not worthy of inclusion
+  //   as they'll just make the options too many and have no clear file pattern
+  //   one can always use the all option
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name( filter, _("All") );
+  gtk_file_filter_add_pattern ( filter, "*" );
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
+  // Default to any file - same as before open filters were added
+  gtk_file_chooser_set_filter (GTK_FILE_CHOOSER(dialog), filter);
+
+  gtk_file_chooser_set_select_multiple ( GTK_FILE_CHOOSER(dialog), TRUE );
+  gtk_window_set_transient_for ( GTK_WINDOW(dialog), GTK_WINDOW(vw) );
+  gtk_window_set_destroy_with_parent ( GTK_WINDOW(dialog), TRUE );
 
-    gtk_file_chooser_set_select_multiple ( GTK_FILE_CHOOSER(vw->open_dia), TRUE );
-    gtk_window_set_transient_for ( GTK_WINDOW(vw->open_dia), GTK_WINDOW(vw) );
-    gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->open_dia), TRUE );
-  }
-  if ( gtk_dialog_run ( GTK_DIALOG(vw->open_dia) ) == GTK_RESPONSE_ACCEPT )
+  if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
   {
-    gtk_widget_hide ( vw->open_dia );
+    g_free ( last_folder_files_uri );
+    last_folder_files_uri = gtk_file_chooser_get_current_folder_uri ( GTK_FILE_CHOOSER(dialog) );
+
 #ifdef VIKING_PROMPT_IF_MODIFIED
     if ( (vw->modified || vw->filename) && newwindow )
 #else
     if ( vw->filename && newwindow )
 #endif
-      g_signal_emit ( G_OBJECT(vw), window_signals[VW_OPENWINDOW_SIGNAL], 0, gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER(vw->open_dia) ) );
+      g_signal_emit ( G_OBJECT(vw), window_signals[VW_OPENWINDOW_SIGNAL], 0, gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER(dialog) ) );
     else {
-      files = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER(vw->open_dia) );
+
+      files = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER(dialog) );
       gboolean change_fn = newwindow && (g_slist_length(files)==1); /* only change fn if one file */
       gboolean first_vik_file = TRUE;
       cur_file = files;
@@ -3253,65 +3281,64 @@ static void load_file ( GtkAction *a, VikWindow *vw )
       g_slist_free (files);
     }
   }
-  else
-    gtk_widget_hide ( vw->open_dia );
+  gtk_widget_destroy ( dialog );
 }
 
 static gboolean save_file_as ( GtkAction *a, VikWindow *vw )
 {
   gboolean rv = FALSE;
   const gchar *fn;
-  if ( ! vw->save_dia )
-  {
-    vw->save_dia = gtk_file_chooser_dialog_new (_("Save as Viking File."),
-                                                GTK_WINDOW(vw),
-                                                GTK_FILE_CHOOSER_ACTION_SAVE,
-                                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                                                GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
-                                                NULL);
-    gchar *cwd = g_get_current_dir();
-    if ( cwd ) {
-      gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER(vw->save_dia), cwd );
-      g_free ( cwd );
-    }
 
-    GtkFileFilter *filter;
-    filter = gtk_file_filter_new ();
-    gtk_file_filter_set_name( filter, _("All") );
-    gtk_file_filter_add_pattern ( filter, "*" );
-    gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->save_dia), filter);
+  GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Save as Viking File."),
+                                                   GTK_WINDOW(vw),
+                                                   GTK_FILE_CHOOSER_ACTION_SAVE,
+                                                   GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                                   GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+                                                   NULL);
+  if ( last_folder_files_uri )
+    gtk_file_chooser_set_current_folder_uri ( GTK_FILE_CHOOSER(dialog), last_folder_files_uri );
+
+  GtkFileFilter *filter;
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name( filter, _("All") );
+  gtk_file_filter_add_pattern ( filter, "*" );
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name( filter, _("Viking") );
+  gtk_file_filter_add_pattern ( filter, "*.vik" );
+  gtk_file_filter_add_pattern ( filter, "*.viking" );
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
+  // Default to a Viking file
+  gtk_file_chooser_set_filter (GTK_FILE_CHOOSER(dialog), filter);
 
-    filter = gtk_file_filter_new ();
-    gtk_file_filter_set_name( filter, _("Viking") );
-    gtk_file_filter_add_pattern ( filter, "*.vik" );
-    gtk_file_filter_add_pattern ( filter, "*.viking" );
-    gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->save_dia), filter);
-    // Default to a Viking file
-    gtk_file_chooser_set_filter (GTK_FILE_CHOOSER(vw->save_dia), filter);
+  gtk_window_set_transient_for ( GTK_WINDOW(dialog), GTK_WINDOW(vw) );
+  gtk_window_set_destroy_with_parent ( GTK_WINDOW(dialog), TRUE );
 
-    gtk_window_set_transient_for ( GTK_WINDOW(vw->save_dia), GTK_WINDOW(vw) );
-    gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->save_dia), TRUE );
-  }
   // Auto append / replace extension with '.vik' to the suggested file name as it's going to be a Viking File
   gchar* auto_save_name = g_strdup ( window_get_filename ( vw ) );
   if ( ! a_file_check_ext ( auto_save_name, ".vik" ) )
     auto_save_name = g_strconcat ( auto_save_name, ".vik", NULL );
 
-  gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(vw->save_dia), auto_save_name);
+  gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(dialog), auto_save_name);
 
-  while ( gtk_dialog_run ( GTK_DIALOG(vw->save_dia) ) == GTK_RESPONSE_ACCEPT )
+  while ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
   {
-    fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(vw->save_dia) );
-    if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE || a_dialog_yes_or_no ( GTK_WINDOW(vw->save_dia), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
+    fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog) );
+    if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE || a_dialog_yes_or_no ( GTK_WINDOW(dialog), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
     {
       window_set_filename ( vw, fn );
       rv = window_save ( vw );
-      vw->modified = FALSE;
+      if ( rv ) {
+        vw->modified = FALSE;
+        g_free ( last_folder_files_uri );
+        last_folder_files_uri = gtk_file_chooser_get_current_folder_uri ( GTK_FILE_CHOOSER(dialog) );
+      }
       break;
     }
   }
   g_free ( auto_save_name );
-  gtk_widget_hide ( vw->save_dia );
+  gtk_widget_destroy ( dialog );
   return rv;
 }
 
@@ -3964,55 +3991,52 @@ static gchar* draw_image_filename ( VikWindow *vw, gboolean one_image_only )
   if ( one_image_only )
   {
     // Single file
-    if (!vw->save_img_dia) {
-      vw->save_img_dia = gtk_file_chooser_dialog_new (_("Save Image"),
-                                                      GTK_WINDOW(vw),
-                                                      GTK_FILE_CHOOSER_ACTION_SAVE,
-                                                      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                                                      GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
-                                                      NULL);
-
-      gchar *cwd = g_get_current_dir();
-      if ( cwd ) {
-        gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER(vw->save_img_dia), cwd );
-        g_free ( cwd );
-      }
+    GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Save Image"),
+                                                     GTK_WINDOW(vw),
+                                                     GTK_FILE_CHOOSER_ACTION_SAVE,
+                                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                                     GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+                                                     NULL);
+    if ( last_folder_images_uri )
+      gtk_file_chooser_set_current_folder_uri ( GTK_FILE_CHOOSER(dialog), last_folder_images_uri );
+
+    GtkFileChooser *chooser = GTK_FILE_CHOOSER ( dialog );
+    /* Add filters */
+    GtkFileFilter *filter;
+    filter = gtk_file_filter_new ();
+    gtk_file_filter_set_name ( filter, _("All") );
+    gtk_file_filter_add_pattern ( filter, "*" );
+    gtk_file_chooser_add_filter ( chooser, filter );
 
-      GtkFileChooser *chooser = GTK_FILE_CHOOSER ( vw->save_img_dia );
-      /* Add filters */
-      GtkFileFilter *filter;
-      filter = gtk_file_filter_new ();
-      gtk_file_filter_set_name ( filter, _("All") );
-      gtk_file_filter_add_pattern ( filter, "*" );
-      gtk_file_chooser_add_filter ( chooser, filter );
+    filter = gtk_file_filter_new ();
+    gtk_file_filter_set_name ( filter, _("JPG") );
+    gtk_file_filter_add_mime_type ( filter, "image/jpeg");
+    gtk_file_chooser_add_filter ( chooser, filter );
 
-      filter = gtk_file_filter_new ();
-      gtk_file_filter_set_name ( filter, _("JPG") );
-      gtk_file_filter_add_mime_type ( filter, "image/jpeg");
-      gtk_file_chooser_add_filter ( chooser, filter );
+    if ( !vw->draw_image_save_as_png )
+      gtk_file_chooser_set_filter ( chooser, filter );
 
-      if ( !vw->draw_image_save_as_png )
-        gtk_file_chooser_set_filter ( chooser, filter );
+    filter = gtk_file_filter_new ();
+    gtk_file_filter_set_name ( filter, _("PNG") );
+    gtk_file_filter_add_mime_type ( filter, "image/png");
+    gtk_file_chooser_add_filter ( chooser, filter );
 
-      filter = gtk_file_filter_new ();
-      gtk_file_filter_set_name ( filter, _("PNG") );
-      gtk_file_filter_add_mime_type ( filter, "image/png");
-      gtk_file_chooser_add_filter ( chooser, filter );
+    if ( vw->draw_image_save_as_png )
+      gtk_file_chooser_set_filter ( chooser, filter );
 
-      if ( vw->draw_image_save_as_png )
-        gtk_file_chooser_set_filter ( chooser, filter );
+    gtk_window_set_transient_for ( GTK_WINDOW(dialog), GTK_WINDOW(vw) );
+    gtk_window_set_destroy_with_parent ( GTK_WINDOW(dialog), TRUE );
 
-      gtk_window_set_transient_for ( GTK_WINDOW(vw->save_img_dia), GTK_WINDOW(vw) );
-      gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->save_img_dia), TRUE );
-    }
+    if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) {
+      g_free ( last_folder_images_uri );
+      last_folder_images_uri = gtk_file_chooser_get_current_folder_uri ( GTK_FILE_CHOOSER(dialog) );
 
-    if ( gtk_dialog_run ( GTK_DIALOG(vw->save_img_dia) ) == GTK_RESPONSE_ACCEPT ) {
-      fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(vw->save_img_dia) );
+      fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog) );
       if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) )
-       if ( ! a_dialog_yes_or_no ( GTK_WINDOW(vw->save_img_dia), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
-         fn = NULL;
+        if ( ! a_dialog_yes_or_no ( GTK_WINDOW(dialog), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
+          fn = NULL;
     }
-    gtk_widget_hide ( vw->save_img_dia );
+    gtk_widget_destroy ( dialog );
   }
   else {
     // A directory
@@ -4022,21 +4046,19 @@ static gchar* draw_image_filename ( VikWindow *vw, gboolean one_image_only )
       return fn;
     }
 
-    if (!vw->save_img_dir_dia) {
-      vw->save_img_dir_dia = gtk_file_chooser_dialog_new (_("Choose a directory to hold images"),
-                                                          GTK_WINDOW(vw),
-                                                          GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
-                                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                                                          GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
-                                                          NULL);
-      gtk_window_set_transient_for ( GTK_WINDOW(vw->save_img_dir_dia), GTK_WINDOW(vw) );
-      gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->save_img_dir_dia), TRUE );
-    }
-
-    if ( gtk_dialog_run ( GTK_DIALOG(vw->save_img_dir_dia) ) == GTK_RESPONSE_ACCEPT ) {
-      fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(vw->save_img_dir_dia) );
+    GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Choose a directory to hold images"),
+                                                     GTK_WINDOW(vw),
+                                                     GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+                                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                                     GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+                                                     NULL);
+    gtk_window_set_transient_for ( GTK_WINDOW(dialog), GTK_WINDOW(vw) );
+    gtk_window_set_destroy_with_parent ( GTK_WINDOW(dialog), TRUE );
+
+    if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) {
+      fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog) );
     }
-    gtk_widget_hide ( vw->save_img_dir_dia );
+    gtk_widget_destroy ( dialog );
   }
   return fn;
 }
@@ -4344,7 +4366,7 @@ static GtkActionEntry entries[] = {
   { "Save",      GTK_STOCK_SAVE,         N_("_Save"),                         "<control>S", N_("Save the file"),                                (GCallback)save_file             },
   { "SaveAs",    GTK_STOCK_SAVE_AS,      N_("Save _As..."),                      NULL,  N_("Save the file under different name"),           (GCallback)save_file_as          },
   { "FileProperties", NULL,              N_("Properties..."),                    NULL,  N_("File Properties"),                              (GCallback)file_properties_cb },
-  { "GenImg",    GTK_STOCK_CLEAR,        N_("_Generate Image File..."),          NULL,  N_("Save a snapshot of the workspace into a file"), (GCallback)draw_to_image_file_cb },
+  { "GenImg",    GTK_STOCK_FILE,         N_("_Generate Image File..."),          NULL,  N_("Save a snapshot of the workspace into a file"), (GCallback)draw_to_image_file_cb },
   { "GenImgDir", GTK_STOCK_DND_MULTIPLE, N_("Generate _Directory of Images..."), NULL,  N_("Generate _Directory of Images"),                (GCallback)draw_to_image_dir_cb },
   { "Print",    GTK_STOCK_PRINT,        N_("_Print..."),          NULL,         N_("Print maps"), (GCallback)print_cb },
   { "Exit",      GTK_STOCK_QUIT,         N_("E_xit"),                         "<control>W", N_("Exit the program"),                             (GCallback)window_close          },
@@ -4770,7 +4792,12 @@ gboolean vik_window_clear_highlight ( VikWindow *vw )
   return need_redraw;
 }
 
+/**
+ * May return NULL if the window no longer exists
+ */
 GThread *vik_window_get_thread ( VikWindow *vw )
 {
-  return vw->thread;
+  if ( vw )
+    return vw->thread;
+  return NULL;
 }