Added copyright lines for files I've edited this year.
[synfig.git] / synfig-studio / trunk / src / gtkmm / app.cpp
index 77298fb..871ac9a 100644 (file)
@@ -2,10 +2,11 @@
 /*!    \file app.cpp
 **     \brief writeme
 **
-**     $Id: app.cpp,v 1.11 2005/03/24 21:47:28 darco Exp $
+**     $Id$
 **
 **     \legal
 **     Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+**     Copyright (c) 2007, 2008 Chris Moore
 **
 **     This package is free software; you can redistribute it and/or
 **     modify it under the terms of the GNU General Public License as
@@ -32,6 +33,7 @@
 #include <fstream>
 #include <iostream>
 #include <locale>
+#include <cstring>
 
 #ifdef HAVE_SYS_ERRNO_H
 #include <sys/errno.h>
 #include <gtk/gtk.h>
 
 #include <synfig/loadcanvas.h>
+#include <synfig/savecanvas.h>
 
 #include "app.h"
 #include "about.h"
+#include "splash.h"
 #include "instance.h"
 #include "canvasview.h"
 #include "dialog_setup.h"
@@ -82,6 +86,7 @@
 
 #include "devicetracker.h"
 #include "dialog_tooloptions.h"
+#include "widget_enum.h"
 
 #include "autorecover.h"
 
 #include <gtkmm/filechooser.h>
 #include <gtkmm/filechooserdialog.h>
 
+#include "general.h"
+
 #endif
 
 /* === U S I N G =========================================================== */
@@ -136,8 +143,10 @@ using namespace studio;
 #ifndef SYNFIG_USER_APP_DIR
 #ifdef __APPLE__
 #define SYNFIG_USER_APP_DIR    "Library/Synfig"
-#else
+#elif defined(_WIN32)
 #define SYNFIG_USER_APP_DIR    "Synfig"
+#else
+#define SYNFIG_USER_APP_DIR    ".synfig"
 #endif
 #endif
 
@@ -216,6 +225,8 @@ const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_i
 etl::handle<Instance> App::selected_instance;
 etl::handle<CanvasView> App::selected_canvas_view;
 
+studio::About *studio::App::about=NULL;
+
 studio::Toolbox *studio::App::toolbox=NULL;
 
 studio::AutoRecover *studio::App::auto_recover=NULL;
@@ -250,6 +261,8 @@ studio::Dock_Curves* dock_curves;
 std::list< etl::handle< studio::Module > > module_list_;
 
 bool studio::App::use_colorspace_gamma=true;
+bool studio::App::single_threaded=false;
+bool studio::App::restrict_radius_ducks=false;
 
 static int max_recent_files_=25;
 int studio::App::get_max_recent_files() { return max_recent_files_; }
@@ -258,6 +271,25 @@ void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
 static synfig::String app_base_path_;
 
 namespace studio {
+
+bool
+really_delete_widget(Gtk::Widget *widget)
+{
+       // synfig::info("really delete %p", (void*)widget);
+       delete widget;
+       return false;
+}
+
+// nasty workaround - when we've finished with a popup menu, we want to delete it
+// attaching to the signal_hide() signal gets us here before the action on the menu has run,
+// so schedule the real delete to happen in 50ms, giving the action a chance to run
+void
+delete_widget(Gtk::Widget *widget)
+{
+       // synfig::info("delete %p", (void*)widget);
+       Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
+}
+
 }; // END of namespace studio
 studio::StateManager* state_manager;
 
@@ -350,7 +382,7 @@ public:
        }
 
        virtual bool
-       amount_complete(int current, int total)
+       amount_complete(int /*current*/, int /*total*/)
        {
                while(studio::App::events_pending())studio::App::iteration(false);
                return true;
@@ -359,149 +391,6 @@ public:
 
 /* === P R O C E D U R E S ================================================= */
 
-typedef unsigned char U8;
-typedef unsigned short U16;
-typedef unsigned long U32;
-
-typedef union {
-       struct {
-               U32 serial;
-               U32 checksum;
-       } element;
-       U8      raw[8];
-} V_KeyUnwound;
-
-static inline U32 hash_U32(U32 i)
-{
-       i=i*1664525+1013904223;
-       i=i*1664525+1013904223;
-       i=i*1664525+1013904223;
-       return i;
-}
-
-#ifdef BIG_ENDIAN
-static const int endian_fix_table[8] = { 3, 2, 1, 0, 7, 6, 5, 4 } ;
-#define endian_fix(x) (endian_fix_table[x])
-#else
-#define endian_fix(x) (x)
-#endif
-
-int v_unwind_key(V_KeyUnwound* unwound, const char* key)
-{
-       int i;
-       unwound->element.serial=0;
-       unwound->element.checksum=0;
-
-       for(i=0;i<16;i++)
-       {
-               U8 data;
-
-               switch(key[i])
-               {
-                       case '0': data=0; break;
-                       case '1': data=1; break;
-                       case '2': data=2; break;
-                       case '3': data=3; break;
-                       case '4': data=4; break;
-                       case '5': data=5; break;
-                       case '6': data=6; break;
-                       case '7': data=7; break;
-                       case '8': data=8; break;
-                       case '9': data=9; break;
-                       case 'a': case 'A':  data=10; break;
-                       case 'b': case 'B':  data=11; break;
-                       case 'c': case 'C':  data=12; break;
-                       case 'd': case 'D':  data=13; break;
-                       case 'e': case 'E':  data=14; break;
-                       case 'f': case 'F':  data=15; break;
-                       default: return 0; break;
-               }
-               int bit=i*2;
-               unwound->element.checksum|=(((U32)data&3)<<bit);
-               unwound->element.serial|=(((U32)(data>>2)&3)<<bit);
-       }
-       return 1;
-}
-
-int v_key_check(const char* key, U32* serial, U32 appid)
-{
-       V_KeyUnwound unwound_key;
-       U32 appid_mask_a=hash_U32(appid);
-       U32 appid_mask_b=hash_U32(appid_mask_a);
-
-       if(!v_unwind_key(&unwound_key, key))
-       {
-               // Invalid characters in key
-               return 0;
-       }
-
-
-       // Undo obfuscation pass
-       {
-               U32 next=hash_U32(unwound_key.raw[endian_fix(7)]);
-               int i;
-               for(i=0;i<7;i++)
-               {
-                       next=hash_U32(next);
-                       unwound_key.raw[endian_fix(i)]^=(next>>24);
-               }
-       }
-
-       unwound_key.element.serial^=appid_mask_a;
-       unwound_key.element.checksum^=appid_mask_b;
-
-       *serial=unwound_key.element.serial;
-
-       return unwound_key.element.checksum==hash_U32(unwound_key.element.serial);
-}
-
-
-int check_license(String basedir)
-{
-#ifdef LICENSE_KEY_REQUIRED
-       String key;
-       String license_file;
-
-#ifndef _WIN32
-       license_file="/usr/local/etc/.synfiglicense";
-#else
-       license_file=basedir+"\\etc\\.synfiglicense";
-#endif
-
-       try {
-               key=Glib::file_get_contents(license_file);
-       } catch (Glib::FileError) { }
-       U32 serial(0);
-       if(!v_key_check(key.c_str(),&serial,0xdeadbeef))
-       {
-               while(!v_key_check(key.c_str(),&serial,0xdeadbeef))
-               {
-                       key.clear();
-
-                       if(!App::dialog_entry(
-                               _("Synfig Studio Authentication"),
-                               _("Please enter your license key below. You will not\nbe able to use this software without a valid license key."),
-                               key
-                       ))
-                               throw String("No License");
-               }
-
-               FILE* file=fopen(license_file.c_str(),"w");
-               if(file)
-               {
-                       fprintf(file,"%s",key.c_str());
-                       fclose(file);
-               }
-               else
-                       synfig::error("Unable to save license key!");
-       }
-       synfig::info("License Authenticated -- Serial #%05d",serial);
-       return serial;
-#else
-       return 1;
-#endif
-}
-
 /*
 void
 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
@@ -529,30 +418,24 @@ studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib
 {
        ui_manager->insert_action_group(group,0);
        return;
-       DEBUGPOINT();
        std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
        std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
 
-       DEBUGPOINT();
        for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
        {
-               DEBUGPOINT();
                if(*iter && (*iter)->get_name()!="menus")
                {
                        synfig::info("Removing action group "+(*iter)->get_name());
                        ui_manager->remove_action_group(*iter);
                }
        }
-       DEBUGPOINT();
        ui_manager->insert_action_group(group,0);
 
-       DEBUGPOINT();
        for(;!prev_groups.empty();prev_groups.pop_front())
        {
                if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
                        ui_manager->insert_action_group(prev_groups.front(),1);
        }
-       DEBUGPOINT();
 }
 */
 class Preferences : public synfigapp::Settings
@@ -590,11 +473,21 @@ public:
                        value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
                        return true;
                }
+               if(key=="single_threaded")
+               {
+                       value=strprintf("%i",(int)App::single_threaded);
+                       return true;
+               }
                if(key=="auto_recover_backup_interval")
                {
                        value=strprintf("%i",App::auto_recover->get_timeout());
                        return true;
                }
+               if(key=="restrict_radius_ducks")
+               {
+                       value=strprintf("%i",(int)App::restrict_radius_ducks);
+                       return true;
+               }
 
                return synfigapp::Settings::get_value(key,value);
        }
@@ -645,6 +538,18 @@ public:
                        App::distance_system=Distance::ident_system(value);;
                        return true;
                }
+               if(key=="single_threaded")
+               {
+                       int i(atoi(value.c_str()));
+                       App::single_threaded=i;
+                       return true;
+               }
+               if(key=="restrict_radius_ducks")
+               {
+                       int i(atoi(value.c_str()));
+                       App::restrict_radius_ducks=i;
+                       return true;
+               }
 
                return synfigapp::Settings::set_value(key,value);
        }
@@ -657,7 +562,9 @@ public:
                ret.push_back("distance_system");
                ret.push_back("file_history.size");
                ret.push_back("use_colorspace_gamma");
+               ret.push_back("single_threaded");
                ret.push_back("auto_recover_backup_interval");
+               ret.push_back("restrict_radius_ducks");
                return ret;
        }
 };
@@ -673,18 +580,19 @@ init_ui_manager()
 
        Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
 
-       menus_action_group->add( Gtk::Action::create("menu-file", "_File") );
-       menus_action_group->add( Gtk::Action::create("menu-edit", "_Edit") );
-       menus_action_group->add( Gtk::Action::create("menu-view", "_View") );
-       menus_action_group->add( Gtk::Action::create("menu-canvas", "_Canvas") );
-       menus_action_group->add( Gtk::Action::create("menu-layer", "_Layer") );
-       menus_action_group->add( Gtk::Action::create("menu-duck-mask", "Show/Hide Ducks") );
-       menus_action_group->add( Gtk::Action::create("menu-preview-quality", "Preview Quality") );
-       menus_action_group->add( Gtk::Action::create("menu-layer-new", "New Layer") );
-       menus_action_group->add( Gtk::Action::create("menu-keyframe", "Keyframe") );
-       menus_action_group->add( Gtk::Action::create("menu-group", "Group") );
-       menus_action_group->add( Gtk::Action::create("menu-state", "State") );
-       menus_action_group->add( Gtk::Action::create("menu-toolbox", "Toolbox") );
+       menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
+       menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
+       menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
+       menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
+       menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
+       menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
+       menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
+       menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
+       menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
+       menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
+       menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
+       menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
+       menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
 
        // Add the synfigapp actions...
        synfigapp::Action::Book::iterator iter;
@@ -703,6 +611,7 @@ init_ui_manager()
 
        DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
        DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
+       DEFINE_ACTION("new", Gtk::Stock::NEW);
        DEFINE_ACTION("open", Gtk::Stock::OPEN);
        DEFINE_ACTION("save", Gtk::Stock::SAVE);
        DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
@@ -717,7 +626,9 @@ init_ui_manager()
        DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
        DEFINE_ACTION("sound", _("Sound File"));
        DEFINE_ACTION("options", _("Options"));
-       DEFINE_ACTION("close", _("Close"));
+       DEFINE_ACTION("close", _("Close View"));
+       DEFINE_ACTION("close-document", _("Close Document"));
+       DEFINE_ACTION("quit", Gtk::Stock::QUIT);
 
 
        DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
@@ -746,13 +657,17 @@ init_ui_manager()
        DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
        DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
        DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
+       for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
+               DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
        DEFINE_ACTION("play", _("Play"));
-       DEFINE_ACTION("pause", _("Pause"));
+       // DEFINE_ACTION("pause", _("Pause"));
        DEFINE_ACTION("stop", _("Stop"));
        DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
        DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
        DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
        DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
+       DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
+       DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
        DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
        DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
        DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
@@ -820,6 +735,8 @@ init_ui_manager()
 "      </popup>"
 "      <popup name='menu-main' action='menu-main'>"
 "      <menu action='menu-file'>"
+"              <menuitem action='new' />"
+"              <menuitem action='open' />"
 "              <menuitem action='save' />"
 "              <menuitem action='save-as' />"
 "              <menuitem action='revert' />"
@@ -837,6 +754,8 @@ init_ui_manager()
 "              <separator name='bleh04'/>"
 "              <menuitem action='options' />"
 "              <menuitem action='close' />"
+"              <menuitem action='close-document' />"
+"              <menuitem action='quit' />"
 "      </menu>"
 "      <menu action='menu-edit'>"
 "              <menuitem action='undo'/>"
@@ -873,9 +792,20 @@ init_ui_manager()
 "                      <menuitem action='quality-09' />"
 "                      <menuitem action='quality-10' />"
 "              </menu>"
+"              <menu action='menu-lowres-pixel'>"
+"              <menuitem action='decrease-low-res-pixel-size'/>"
+"              <menuitem action='increase-low-res-pixel-size'/>"
+"              <separator name='pixel-size-separator'/>"
+;
+
+       for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
+               ui_info += strprintf("                  <menuitem action='lowres-pixel-%d' />", *iter);
+
+       ui_info +=
+"              </menu>"
 "              <separator name='bleh08'/>"
 "              <menuitem action='play'/>"
-"              <menuitem action='pause'/>"
+//"            <menuitem action='pause'/>"
 "              <menuitem action='stop'/>"
 "              <menuitem action='dialog-flipbook'/>"
 "              <separator name='bleh09'/>"
@@ -904,8 +834,6 @@ init_ui_manager()
 "      </menu>"
 "      <menu action='menu-canvas'>"
 "              <menuitem action='canvas-new'/>"
-       "       <menuitem action='amount-inc'/>"
-       "       <menuitem action='amount-dec'/>"
 "      </menu>"
 "      <menu name='menu-state' action='menu-state'>"
 "      </menu>"
@@ -918,6 +846,8 @@ init_ui_manager()
 //"            <menuitem action='paste'/>"
 //"            <separator name='bleh06'/>"
 "              <menu action='menu-layer-new'></menu>"
+"              <menuitem action='amount-inc'/>"
+"              <menuitem action='amount-dec'/>"
 "      </menu>"
 "      <menu action='menu-keyframe'>"
 "              <menuitem action='keyframe-properties'/>"
@@ -962,8 +892,18 @@ init_ui_manager()
        }
 
        // Add default keyboard accelerators
-#define ACCEL(path,accel)      { Gtk::AccelKey accel_key(accel,path); Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(),accel_key.get_mod()); }
-#define ACCEL2(accel)  { Gtk::AccelKey accel_key(accel); Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(),accel_key.get_mod()); }
+#define ACCEL(path,accel)                                              \
+       {                                                                                       \
+               Gtk::AccelKey accel_key(accel,path);    \
+               Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod());       \
+       }
+
+#define ACCEL2(accel)                                                  \
+       {                                                                                       \
+               Gtk::AccelKey accel_key(accel);                 \
+               Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod());       \
+       }
+
        ACCEL("<Actions>//select-all-ducks","<Control>a");
        ACCEL("<Actions>//unselect-all-layers","<Control>d");
        ACCEL("<Actions>//render","F9");
@@ -982,7 +922,6 @@ init_ui_manager()
        ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
        ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
 
-
        ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
        ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
 
@@ -1007,6 +946,9 @@ init_ui_manager()
        ACCEL("<Actions>//time-zoom-in","+");
        ACCEL("<Actions>//time-zoom-out","_");
 */
+       ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
+       ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
+
        ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
        ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
 
@@ -1020,17 +962,31 @@ init_ui_manager()
        ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
        ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
        ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
-       ACCEL2(Gtk::AccelKey('o',Gdk::CONTROL_MASK,"<Actions>//toggle-onion-skin"));
+       ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
+       ACCEL("<Actions>//play",              "<Control>p");
        ACCEL("<Actions>//seek-begin","Home");
        ACCEL("<Actions>//seek-end","End");
-       ACCEL("<Actions>//state-normal","<Mod1>a");
-       ACCEL("<Actions>//state-rotate","<Mod1>s");
-       ACCEL("<Actions>//state-scale","<Mod1>d");
-       ACCEL("<Actions>//state-bline","<Mod1>b");
-       ACCEL("<Actions>//state-fill","<Mod1>f");
-       ACCEL("<Actions>//state-eyedrop","<Mod1>e");
-       ACCEL("<Actions>//state-gradient","<Mod1>g");
-       ACCEL("<Actions>//state-zoom","<Mod1>z");
+
+       ACCEL("<Actions>//state-normal",      "<Mod1>a");
+       ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
+       ACCEL("<Actions>//state-scale",       "<Mod1>d");
+       ACCEL("<Actions>//state-rotate",      "<Mod1>s");
+
+       ACCEL("<Actions>//state-bline",       "<Mod1>b");
+       ACCEL("<Actions>//state-circle",      "<Mod1>c");
+       ACCEL("<Actions>//state-rectangle",   "<Mod1>r");
+       ACCEL("<Actions>//state-gradient",    "<Mod1>g");
+
+       ACCEL("<Actions>//state-eyedrop",     "<Mod1>e");
+       ACCEL("<Actions>//state-fill",        "<Mod1>f");
+       ACCEL("<Actions>//state-zoom",        "<Mod1>z");
+       ACCEL("<Actions>//state-polygon",     "<Mod1>p");
+
+       ACCEL("<Actions>//state-draw",        "<Mod1>w");
+       ACCEL("<Actions>//state-sketch",      "<Mod1>k");
+       ACCEL("<Actions>//state-width",       "<Mod1>t");
+       ACCEL("<Actions>//state-mirror",      "<Mod1>m");
+
        ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
 
 #undef ACCEL
@@ -1044,19 +1000,19 @@ init_ui_manager()
 
 App::App(int *argc, char ***argv):
        Gtk::Main(argc,argv),
-       IconControler(etl::dirname((*argv)[0]))
+       IconController(etl::dirname((*argv)[0]))
 {
        app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
 
-       int serial_;
-       serial_=check_license(app_base_path_);
-
 
        ui_interface_=new GlobalUIInterface();
 
        gdk_rgb_init();
 
-       Glib::thread_init();
+       // don't call thread_init() if threads are already initialized
+       // on some machines bonobo_init() initialized threads before we get here
+       if (!g_thread_supported())
+               Glib::thread_init();
 
        distance_system=Distance::SYSTEM_UNITS;
 
@@ -1073,47 +1029,33 @@ App::App(int *argc, char ***argv):
 
        ipc=new IPC();
 
-       try
+       if(!SYNFIG_CHECK_VERSION())
        {
-               if(!SYNFIG_CHECK_VERSION())
-               {
                cerr<<"FATAL: Synfig Version Mismatch"<<endl;
                dialog_error_blocking("Synfig Studio",
                        "This copy of Synfig Studio was compiled against a\n"
                        "different version of libsynfig than what is currently\n"
                        "installed. Synfig Studio will now abort. Try downloading\n"
-                       "the latest version from the Synfig Development Website at\n"
-                       "http://dev.synfig.com/ "
+                       "the latest version from the Synfig website at\n"
+                       "http://synfig.org/Download"
                );
                throw 40;
-               }
-       }
-       catch(synfig::SoftwareExpired)
-       {
-               cerr<<"FATAL: Software Expired"<<endl;
-               dialog_error_blocking("Synfig Studio",
-                       "This copy of Synfig Studio has expired.\n"
-                       "Please erase this copy, or download and\n"
-                       "install the latest copy from the Synfig\n"
-                       "Development Website at http://dev.synfig.com/ ."
-               );
-               throw 39;
        }
        Glib::set_application_name(_("Synfig Studio"));
 
-       About about_window;
-       about_window.set_can_self_destruct(false);
-       about_window.show();
+       Splash splash_screen;
+       splash_screen.set_can_self_destruct(false);
+       splash_screen.show();
 
        shutdown_in_progress=false;
-       SuperCallback synfig_init_cb(about_window.get_callback(),0,9000,10000);
-       SuperCallback studio_init_cb(about_window.get_callback(),9000,10000,10000);
+       SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
+       SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
 
        // Initialize the Synfig library
        try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
        catch(...)
        {
-               get_ui_interface()->error("Failed to initialize synfig!");
+               get_ui_interface()->error(_("Failed to initialize synfig!"));
                throw;
        }
 
@@ -1122,159 +1064,159 @@ App::App(int *argc, char ***argv):
 
        try
        {
-               studio_init_cb.task("Init UI Manager...");
+               studio_init_cb.task(_("Init UI Manager..."));
                App::ui_manager_=studio::UIManager::create();
                init_ui_manager();
 
-               studio_init_cb.task("Init Dock Manager...");
+               studio_init_cb.task(_("Init Dock Manager..."));
                dock_manager=new studio::DockManager();
 
-               studio_init_cb.task("Init State Manager...");
+               studio_init_cb.task(_("Init State Manager..."));
                state_manager=new StateManager();
 
-               studio_init_cb.task("Init Toolbox...");
+               studio_init_cb.task(_("Init Toolbox..."));
                toolbox=new studio::Toolbox();
 
-               studio_init_cb.task("Init Tool Options...");
+               studio_init_cb.task(_("Init About Dialog..."));
+               about=new studio::About();
+
+               studio_init_cb.task(_("Init Tool Options..."));
                dialog_tool_options=new studio::Dialog_ToolOptions();
                dock_manager->register_dockable(*dialog_tool_options);
 
-               studio_init_cb.task("Init History...");
+               studio_init_cb.task(_("Init History..."));
                dock_history=new studio::Dock_History();
                dock_manager->register_dockable(*dock_history);
 
-               studio_init_cb.task("Init Canvases...");
+               studio_init_cb.task(_("Init Canvases..."));
                dock_canvases=new studio::Dock_Canvases();
                dock_manager->register_dockable(*dock_canvases);
 
-               studio_init_cb.task("Init Keyframes...");
+               studio_init_cb.task(_("Init Keyframes..."));
                dock_keyframes=new studio::Dock_Keyframes();
                dock_manager->register_dockable(*dock_keyframes);
 
-               studio_init_cb.task("Init Layers...");
+               studio_init_cb.task(_("Init Layers..."));
                dock_layers=new studio::Dock_Layers();
                dock_manager->register_dockable(*dock_layers);
 
-               studio_init_cb.task("Init Params...");
+               studio_init_cb.task(_("Init Params..."));
                dock_params=new studio::Dock_Params();
                dock_manager->register_dockable(*dock_params);
 
-               studio_init_cb.task("Init MetaData...");
+               studio_init_cb.task(_("Init MetaData..."));
                dock_meta_data=new studio::Dock_MetaData();
                dock_manager->register_dockable(*dock_meta_data);
 
-               studio_init_cb.task("Init Children...");
+               studio_init_cb.task(_("Init Children..."));
                dock_children=new studio::Dock_Children();
                dock_manager->register_dockable(*dock_children);
 
-               studio_init_cb.task("Init Info...");
+               studio_init_cb.task(_("Init Info..."));
                dock_info = new studio::Dock_Info();
                dock_manager->register_dockable(*dock_info);
 
-               studio_init_cb.task("Init Navigator...");
+               studio_init_cb.task(_("Init Navigator..."));
                dock_navigator = new studio::Dock_Navigator();
                dock_manager->register_dockable(*dock_navigator);
 
-               studio_init_cb.task("Init Timetrack...");
+               studio_init_cb.task(_("Init Timetrack..."));
                dock_timetrack = new studio::Dock_Timetrack();
                dock_manager->register_dockable(*dock_timetrack);
 
-               studio_init_cb.task("Init Curve Editor...");
+               studio_init_cb.task(_("Init Curve Editor..."));
                dock_curves = new studio::Dock_Curves();
                dock_manager->register_dockable(*dock_curves);
 
-               studio_init_cb.task("Init Layer Groups...");
+               studio_init_cb.task(_("Init Layer Groups..."));
                dock_layer_groups = new studio::Dock_LayerGroups();
                dock_manager->register_dockable(*dock_layer_groups);
 
 
-               studio_init_cb.task("Init Color Dialog...");
+               studio_init_cb.task(_("Init Color Dialog..."));
                dialog_color=new studio::Dialog_Color();
 
-               studio_init_cb.task("Init Gradient Dialog...");
+               studio_init_cb.task(_("Init Gradient Dialog..."));
                dialog_gradient=new studio::Dialog_Gradient();
 
-               studio_init_cb.task("Init DeviceTracker...");
+               studio_init_cb.task(_("Init DeviceTracker..."));
                device_tracker=new studio::DeviceTracker();
 
-               studio_init_cb.task("Init Tools...");
+               studio_init_cb.task(_("Init Tools..."));
+
+               /* row 1 */
                state_manager->add_state(&state_normal);
                state_manager->add_state(&state_smooth_move);
                state_manager->add_state(&state_scale);
                state_manager->add_state(&state_rotate);
+               studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
 
+               /* row 2 */
                state_manager->add_state(&state_bline);
-
-
                state_manager->add_state(&state_circle);
                state_manager->add_state(&state_rectangle);
-
                state_manager->add_state(&state_gradient);
-               state_manager->add_state(&state_eyedrop);
-               state_manager->add_state(&state_fill);
+               if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
 
+               /* row 3 */
+               if(!getenv("SYNFIG_DISABLE_DRAW"   )) state_manager->add_state(&state_draw); // Enabled for now.  Let's see whether they're good enough yet.
+               if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
+               state_manager->add_state(&state_fill);
+               state_manager->add_state(&state_eyedrop);
                state_manager->add_state(&state_zoom);
 
-               // Disabled this tool because it should be
-               // considered deprecated. Use the bline tool instead.
-               if(getenv("SYNFIG_ENABLE_POLYGON")) state_manager->add_state(&state_polygon);
-
-               // These tools are disabled by default for now,
-               // because they tend to confuse users.
-               if(getenv("SYNFIG_ENABLE_DRAW"  )) state_manager->add_state(&state_draw);
-               if(getenv("SYNFIG_ENABLE_SKETCH")) state_manager->add_state(&state_sketch);
-               if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
+               // Disabled by default - it doesn't work properly?
+               if(getenv("SYNFIG_ENABLE_WIDTH"    )) state_manager->add_state(&state_width);
 
-               studio_init_cb.task("Init ModPalette...");
+               studio_init_cb.task(_("Init ModPalette..."));
                module_list_.push_back(new ModPalette()); module_list_.back()->start();
 
-               studio_init_cb.task("Init ModMirror...");
-               module_list_.push_back(new ModMirror()); module_list_.back()->start();
-
-
-               studio_init_cb.task("Init Setup Dialog...");
+               studio_init_cb.task(_("Init Setup Dialog..."));
                dialog_setup=new studio::Dialog_Setup();
 
-               studio_init_cb.task("Init Input Dialog...");
+               studio_init_cb.task(_("Init Input Dialog..."));
                dialog_input=new Gtk::InputDialog();
                dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
+               dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
 
-               studio_init_cb.task("Init auto recovery...");
+               studio_init_cb.task(_("Init auto recovery..."));
                auto_recover=new AutoRecover();
 
                studio_init_cb.amount_complete(9250,10000);
-               studio_init_cb.task("Loading Settings...");
+               studio_init_cb.task(_("Loading Settings..."));
                load_settings();
-               studio_init_cb.task("Checking auto-recover...");
+               studio_init_cb.task(_("Checking auto-recover..."));
 
                studio_init_cb.amount_complete(9900,10000);
 
+               bool opened_any = false;
                if(auto_recover->recovery_needed())
                {
-                       about_window.hide();
-                       if(
-                               get_ui_interface()->yes_no(
-                                       "Auto Recovery",
-                                       "Synfig Studio seems to have crashed\n"
-                                       "before you could save all your files.\n"
-                                       "Would you like to re-open those files\n"
-                                       "and recover your unsaved changes?"
-                               )==synfigapp::UIInterface::RESPONSE_YES
-                       )
+                       splash_screen.hide();
+                       if (get_ui_interface()->yes_no(_("Auto Recovery"),
+                                                                                  _("Synfig Studio seems to have crashed\n"
+                                                                                        "before you could save all your files.\n"
+                                                                                        "Would you like to re-open those files\n"
+                                                                                        "and recover your unsaved changes?")) ==
+                               synfigapp::UIInterface::RESPONSE_YES)
                        {
-                               if(!auto_recover->recover())
-                               {
-                                       get_ui_interface()->error(_("Unable to fully recover from previous crash"));
-                               }
+                               int number_recovered;
+                               if(!auto_recover->recover(number_recovered))
+                                       if (number_recovered)
+                                               get_ui_interface()->error(_("Unable to fully recover from previous crash"));
+                                       else
+                                               get_ui_interface()->error(_("Unable to recover from previous crash"));
                                else
-                               get_ui_interface()->error(
-                                       _("Synfig Studio has attempted to recover\n"
-                                       "from a previous crash. The files that it has\n"
-                                       "recovered are NOT YET SAVED. It would be a good\n"
-                                       "idea to review them and save them now.")
-                               );
+                                       get_ui_interface()->error(
+                                               _("Synfig Studio has attempted to recover\n"
+                                                 "from a previous crash. The files that it has\n"
+                                                 "recovered are NOT YET SAVED. It would be a good\n"
+                                                 "idea to review them and save them now."));
+
+                               if (number_recovered)
+                                       opened_any = true;
                        }
-                       about_window.show();
+                       splash_screen.show();
                }
 
                // Look for any files given on the command line,
@@ -1282,17 +1224,26 @@ App::App(int *argc, char ***argv):
                for(;*argc>=1;(*argc)--)
                        if((*argv)[*argc] && (*argv)[*argc][0]!='-')
                        {
-                               studio_init_cb.task("Loading files...");
-                               about_window.hide();
+                               studio_init_cb.task(_("Loading files..."));
+                               splash_screen.hide();
                                open((*argv)[*argc]);
-                               about_window.show();
+                               opened_any = true;
+                               splash_screen.show();
                        }
 
-               studio_init_cb.task("Done.");
+               // if no file was specified to be opened, create a new document to help new users get started more easily
+               if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
+                       new_instance();
+
+               studio_init_cb.task(_("Done."));
                studio_init_cb.amount_complete(10000,10000);
 
                toolbox->present();
        }
+       catch(String x)
+       {
+               get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
+       }
        catch(...)
        {
                get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
@@ -1312,7 +1263,8 @@ App::~App()
        selected_instance=0;
 
        // Unload all of the modules
-       for(;!module_list_.empty();module_list_.pop_back());
+       for(;!module_list_.empty();module_list_.pop_back())
+               ;
 
        delete state_manager;
 
@@ -1320,6 +1272,8 @@ App::~App()
 
        delete auto_recover;
 
+       delete about;
+       
        toolbox->hide();
 
 //     studio::App::iteration(false);
@@ -1371,7 +1325,7 @@ App::add_recent_file(const std::string &file_name)
        if(basename(filename)[0]=='.')
                return;
 
-       // If we aren't an absolute path, turn outselves into one
+       // If we aren't an absolute path, turn ourselves into one
        if(!is_absolute_path(filename))
                filename=absolute_path(filename);
 
@@ -1484,19 +1438,7 @@ App::load_settings()
                        //if(!synfigapp::Main::settings().load_from_file(filename))
                        {
                                gamma.set_gamma(1.0/2.2);
-                               synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
-                               synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
-                               synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
-                               synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
-                               synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
-                               synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
-                               synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
-                               synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
-                               synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
-                               synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
-                               synfigapp::Main::settings().set_value("pref.distance_system","pt");
-                               synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
-                               synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
+                               reset_initial_window_configuration();
                        }
                }
        setlocale(LC_NUMERIC,old_locale);
@@ -1507,6 +1449,26 @@ App::load_settings()
        }
 }
 
+void
+App::reset_initial_window_configuration()
+{
+       synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
+       synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
+       synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
+       synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
+       synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
+       synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
+       synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
+       synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
+       synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
+       synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
+       synfigapp::Main::settings().set_value("pref.distance_system","pt");
+       synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
+       synfigapp::Main::settings().set_value("pref.single_threaded","0");
+       synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
+       synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
+}
+
 bool
 App::shutdown_request(GdkEventAny*)
 {
@@ -1521,10 +1483,10 @@ App::quit()
        if(shutdown_in_progress)return;
 
 
-       get_ui_interface()->task("Quit Request");
+       get_ui_interface()->task(_("Quit Request"));
        if(Busy::count)
        {
-               dialog_error_blocking("Cannot quit!","Tasks are currently running.\nPlease cancel the current tasks and try again");
+               dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
                return;
        }
 
@@ -1592,7 +1554,7 @@ App::quit()
        Gtk::Main::quit();
        auto_recover->normal_shutdown();
 
-       get_ui_interface()->task("Quit Request sent");
+       get_ui_interface()->task(_("Quit Request sent"));
 }
 
 void
@@ -1602,8 +1564,8 @@ App::show_setup()
        dialog_setup->show();
 }
 
-gint Signal_Open_Ok(GtkWidget *widget, int *val){*val=1;return 0;}
-gint Signal_Open_Cancel(GtkWidget *widget, int *val){*val=2;return 0;}
+gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
+gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
 
 //#ifdef WIN32
 //#define USE_WIN32_FILE_DIALOGS 1
@@ -1618,8 +1580,10 @@ static OPENFILENAME ofn={};
 #endif
 
 bool
-App::dialog_open_file(const std::string &title, std::string &filename)
+App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
 {
+       info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
+
 #ifdef USE_WIN32_FILE_DIALOGS
        static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
 
@@ -1664,22 +1628,36 @@ App::dialog_open_file(const std::string &title, std::string &filename)
 
 #else
        synfig::String prev_path;
-       if(!_preferences.get_value("curr_path",prev_path))
-               prev_path=".";
 
-    Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_OPEN);
+       if(!_preferences.get_value(preference, prev_path))
+               prev_path = ".";
+
+       prev_path = absolute_path(prev_path);
+
+    Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
+
     dialog->set_current_folder(prev_path);
-    dialog->add_button(Gtk::StockID("gtk-ok"),GTK_RESPONSE_ACCEPT);
-    dialog->add_button(Gtk::StockID("gtk-cancel"),GTK_RESPONSE_CANCEL);
-    if(!filename.empty())
-        dialog->set_filename(filename);
-    if(dialog->run()==GTK_RESPONSE_ACCEPT) {
-        filename=dialog->get_filename();
+    dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+    dialog->add_button(Gtk::Stock::OPEN,   Gtk::RESPONSE_ACCEPT);
+
+    if (filename.empty())
+               dialog->set_filename(prev_path);
+       else if (is_absolute_path(filename))
+               dialog->set_filename(filename);
+       else
+               dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
+
+    if(dialog->run() == GTK_RESPONSE_ACCEPT) {
+        filename = dialog->get_filename();
+               info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
+               _preferences.set_value(preference, dirname(filename));
         delete dialog;
         return true;
     }
+
     delete dialog;
     return false;
+
     /*
 
        GtkWidget *ok;
@@ -1692,7 +1670,7 @@ App::dialog_open_file(const std::string &title, std::string &filename)
 
        if(basename(filename)==filename)
        {
-               gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPERATOR).c_str());
+               gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
        }
        else
                gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
@@ -1714,7 +1692,7 @@ App::dialog_open_file(const std::string &title, std::string &filename)
        if(val==1)
        {
                filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
-               _preferences.set_value("curr_path",dirname(filename));
+               _preferences.set_value(preference,dirname(filename));
        }
        else
        {
@@ -1728,9 +1706,11 @@ App::dialog_open_file(const std::string &title, std::string &filename)
 }
 
 bool
-App::dialog_save_file(const std::string &title, std::string &filename)
+App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
 {
-#ifdef USE_WIN32_FILE_DIALOGS
+       info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
+
+#if USE_WIN32_FILE_DIALOGS
        static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
 
        GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
@@ -1768,94 +1748,73 @@ App::dialog_save_file(const std::string &title, std::string &filename)
        if(GetSaveFileName(&ofn))
        {
                filename=szFilename;
+               _preferences.set_value(preference,dirname(filename));
                return true;
        }
        return false;
 #else
        synfig::String prev_path;
-       if(!_preferences.get_value("curr_path",prev_path))
+
+       if(!_preferences.get_value(preference, prev_path))
                prev_path=".";
 
-    Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
-    dialog->set_current_folder(prev_path);
-    dialog->add_button(Gtk::StockID("gtk-ok"),GTK_RESPONSE_ACCEPT);
-    dialog->add_button(Gtk::StockID("gtk-cancel"),GTK_RESPONSE_CANCEL);
-    if(!filename.empty())
-        dialog->set_filename(filename);
-    if(dialog->run()==GTK_RESPONSE_ACCEPT) {
-        filename=dialog->get_filename();
-        delete dialog;
-        return true;
-    }
-    delete dialog;
-    return false;
-//     return dialog_open_file(title, filename);
-#endif
-}
+       prev_path = absolute_path(prev_path);
 
-bool
-App::dialog_saveas_file(const std::string &title, std::string &filename)
-{
-#if USE_WIN32_FILE_DIALOGS
-       static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
+    Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
 
-       GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
-       HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
-       HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
+    dialog->set_current_folder(prev_path);
+    dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+    dialog->add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_ACCEPT);
 
-       ofn.lStructSize=sizeof(OPENFILENAME);
-       ofn.hwndOwner = hWnd;
-       ofn.hInstance = hInstance;
-       ofn.lpstrFilter = szFilter;
-//     ofn.lpstrCustomFilter=NULL;
-//     ofn.nMaxCustFilter=0;
-//     ofn.nFilterIndex=0;
-//     ofn.lpstrFile=NULL;
-       ofn.nMaxFile=MAX_PATH;
-//     ofn.lpstrFileTitle=NULL;
-//     ofn.lpstrInitialDir=NULL;
-//     ofn.lpstrTitle=NULL;
-       ofn.Flags=OFN_OVERWRITEPROMPT;
-//     ofn.nFileOffset=0;
-//     ofn.nFileExtension=0;
-       ofn.lpstrDefExt=TEXT("sif");
-//     ofn.lCustData = 0l;
-       ofn.lpfnHook=NULL;
-//     ofn.lpTemplateName=NULL;
+       Widget_Enum *file_type_enum = 0;
+       if (preference == ANIMATION_DIR_PREFERENCE)
+       {
+               file_type_enum = manage(new Widget_Enum());
+               file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
+                                                                          .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", strprintf("0.61.08 (%s)", _("current")))
+                                                                          .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
+                                                                          .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
+               file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
+
+               Gtk::HBox *hbox = manage(new Gtk::HBox);
+               hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
+               hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
+               hbox->show_all();
+
+               dialog->set_extra_widget(*hbox);
+       }
 
-       CHAR szFilename[MAX_PATH];
-       CHAR szTitle[500];
-       strcpy(szFilename,filename.c_str());
-       strcpy(szTitle,title.c_str());
+    if (filename.empty())
+               dialog->set_filename(prev_path);
+    else
+       {
+               std::string full_path;
+               if (is_absolute_path(filename))
+                       full_path = filename;
+               else
+                       full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
 
-       ofn.lpstrFile=szFilename;
-       ofn.lpstrFileTitle=szTitle;
+               // select the file if it exists
+               dialog->set_filename(full_path);
 
-       if(GetSaveFileName(&ofn))
-       {
-               filename=szFilename;
-               return true;
+               // if the file doesn't exist, put its name into the filename box
+               struct stat s;
+               if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
+                       dialog->set_current_name(basename(filename));
        }
-       return false;
-#else
-       synfig::String prev_path;
-       if(!_preferences.get_value("curr_path",prev_path))
-               prev_path=".";
 
-    Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
-    dialog->set_current_folder(prev_path);
-    dialog->add_button(Gtk::StockID("gtk-ok"),GTK_RESPONSE_ACCEPT);
-    dialog->add_button(Gtk::StockID("gtk-cancel"),GTK_RESPONSE_CANCEL);
-    if(!filename.empty())
-        dialog->set_filename(filename);
-    if(dialog->run()==GTK_RESPONSE_ACCEPT) {
-        filename=dialog->get_filename();
+    if(dialog->run() == GTK_RESPONSE_ACCEPT) {
+               if (preference == ANIMATION_DIR_PREFERENCE)
+                       set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
+        filename = dialog->get_filename();
+               info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
+               _preferences.set_value(preference, dirname(filename));
         delete dialog;
         return true;
     }
+
     delete dialog;
     return false;
-//     return dialog_open_file(title, filename);
 #endif
 }
 
@@ -1917,8 +1876,8 @@ App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
 void
 App::dialog_not_implemented()
 {
-       Gtk::MessageDialog dialog("Feature not available", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
-       dialog.set_secondary_text("Sorry, this feature has not yet been implemented.");
+       Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
+       dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
        dialog.run();
 }
 
@@ -1963,6 +1922,9 @@ App::open(std::string filename)
        return open_as(filename,filename);
 }
 
+// this is called from autorecover.cpp:
+//   App::open_as(get_shadow_file_name(filename),filename)
+// other than that, 'filename' and 'as' are the same
 bool
 App::open_as(std::string filename,std::string as)
 {
@@ -1980,22 +1942,26 @@ App::open_as(std::string filename,std::string as)
                if(canvas && get_instance(canvas))
                {
                        get_instance(canvas)->find_canvas_view(canvas)->present();
-                       throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
+                       info("%s is already open", filename.c_str());
+                       // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
                }
-               if(!canvas)
-                       throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
+               else
+               {
+                       if(!canvas)
+                               throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
 
-               add_recent_file(as);
+                       add_recent_file(as);
 
-               handle<Instance> instance(Instance::create(canvas));
+                       handle<Instance> instance(Instance::create(canvas));
 
-               if(!instance)
-                       throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
+                       if(!instance)
+                               throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
 
-               one_moment.hide();
+                       one_moment.hide();
 
-               if(instance->is_updated() && App::dialog_yes_no(_("CVS Update"), _("There appears to be a newer version of this file available on the CVS repository.\nWould you like to update now? (It would probably be a good idea)")))
-                       instance->dialog_cvs_update();
+                       if(instance->is_updated() && App::dialog_yes_no(_("CVS Update"), _("There appears to be a newer version of this file available on the CVS repository.\nWould you like to update now? (It would probably be a good idea)")))
+                               instance->dialog_cvs_update();
+               }
        }
        catch(String x)
        {
@@ -2008,8 +1974,6 @@ App::open_as(std::string filename,std::string as)
                return false;
        }
 
-       _preferences.set_value("curr_path",dirname(as));
-
        return true;
 }
 
@@ -2018,13 +1982,13 @@ void
 App::new_instance()
 {
        handle<synfig::Canvas> canvas=synfig::Canvas::create();
-       canvas->set_name(strprintf("Untitled%d",Instance::get_count()));
+       canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
 
-       String file_name(strprintf("untitled%d.sif",Instance::get_count()));
+       String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
 
        canvas->rend_desc().set_frame_rate(24.0);
        canvas->rend_desc().set_time_start(0.0);
-       canvas->rend_desc().set_time_end(00.0);
+       canvas->rend_desc().set_time_end(5.0);
        canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
        canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
        canvas->rend_desc().set_tl(Vector(-4,2.25));
@@ -2035,7 +1999,10 @@ App::new_instance()
        canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
        canvas->set_file_name(file_name);
 
-       Instance::create(canvas)->find_canvas_view(canvas)->canvas_properties.present();
+       handle<Instance> instance = Instance::create(canvas);
+
+       if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
+               instance->find_canvas_view(canvas)->canvas_properties.present();
 }
 
 void
@@ -2043,7 +2010,7 @@ App::dialog_open()
 {
        string filename="*.sif";
 
-       while(dialog_open_file("Open", filename))
+       while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
        {
                // If the filename still has wildcards, then we should
                // continue looking for the file we want
@@ -2107,7 +2074,7 @@ App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
 }
 
 etl::loose_handle<Instance>
-App::get_instance(Canvas::Handle canvas)
+App::get_instance(etl::handle<synfig::Canvas> canvas)
 {
        if(!canvas) return 0;
        canvas=canvas->get_root();
@@ -2124,7 +2091,8 @@ App::get_instance(Canvas::Handle canvas)
 void
 App::dialog_about()
 {
-       (new class About())->show();
+       if(about)
+               about->show();
 }
 
 void