Conditionally compile out the 'single threaded' stuff. It doesn't work very well...
[synfig.git] / synfig-studio / trunk / src / gtkmm / app.cpp
index b9b0f86..762e46a 100644 (file)
@@ -6,7 +6,7 @@
 **
 **     \legal
 **     Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
 **
 **     \legal
 **     Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
-**     Copyright (c) 2007 Chris Moore
+**     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
 **
 **     This package is free software; you can redistribute it and/or
 **     modify it under the terms of the GNU General Public License as
@@ -33,6 +33,7 @@
 #include <fstream>
 #include <iostream>
 #include <locale>
 #include <fstream>
 #include <iostream>
 #include <locale>
+#include <cstring>
 
 #ifdef HAVE_SYS_ERRNO_H
 #include <sys/errno.h>
 
 #ifdef HAVE_SYS_ERRNO_H
 #include <sys/errno.h>
 #include <gtk/gtk.h>
 
 #include <synfig/loadcanvas.h>
 #include <gtk/gtk.h>
 
 #include <synfig/loadcanvas.h>
+#include <synfig/savecanvas.h>
 
 #include "app.h"
 #include "about.h"
 
 #include "app.h"
 #include "about.h"
+#include "splash.h"
 #include "instance.h"
 #include "canvasview.h"
 #include "dialog_setup.h"
 #include "instance.h"
 #include "canvasview.h"
 #include "dialog_setup.h"
@@ -83,6 +86,7 @@
 
 #include "devicetracker.h"
 #include "dialog_tooloptions.h"
 
 #include "devicetracker.h"
 #include "dialog_tooloptions.h"
+#include "widget_enum.h"
 
 #include "autorecover.h"
 
 
 #include "autorecover.h"
 
@@ -221,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;
 
 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;
 studio::Toolbox *studio::App::toolbox=NULL;
 
 studio::AutoRecover *studio::App::auto_recover=NULL;
@@ -255,7 +261,11 @@ studio::Dock_Curves* dock_curves;
 std::list< etl::handle< studio::Module > > module_list_;
 
 bool studio::App::use_colorspace_gamma=true;
 std::list< etl::handle< studio::Module > > module_list_;
 
 bool studio::App::use_colorspace_gamma=true;
+#ifdef SINGLE_THREADED
 bool studio::App::single_threaded=false;
 bool studio::App::single_threaded=false;
+#endif
+bool studio::App::restrict_radius_ducks=false;
+String studio::App::browser_command("firefox");
 
 static int max_recent_files_=25;
 int studio::App::get_max_recent_files() { return max_recent_files_; }
 
 static int max_recent_files_=25;
 int studio::App::get_max_recent_files() { return max_recent_files_; }
@@ -268,7 +278,7 @@ namespace studio {
 bool
 really_delete_widget(Gtk::Widget *widget)
 {
 bool
 really_delete_widget(Gtk::Widget *widget)
 {
-       synfig::info("really delete %p", (void*)widget);
+       // synfig::info("really delete %p", (void*)widget);
        delete widget;
        return false;
 }
        delete widget;
        return false;
 }
@@ -279,7 +289,7 @@ really_delete_widget(Gtk::Widget *widget)
 void
 delete_widget(Gtk::Widget *widget)
 {
 void
 delete_widget(Gtk::Widget *widget)
 {
-       synfig::info("delete %p", (void*)widget);
+       // synfig::info("delete %p", (void*)widget);
        Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
 }
 
        Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
 }
 
@@ -411,30 +421,24 @@ studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib
 {
        ui_manager->insert_action_group(group,0);
        return;
 {
        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;
 
        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)
        {
        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);
                }
        }
                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);
 
        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);
        }
        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
 }
 */
 class Preferences : public synfigapp::Settings
@@ -472,16 +476,28 @@ public:
                        value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
                        return true;
                }
                        value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
                        return true;
                }
+#ifdef SINGLE_THREADED
                if(key=="single_threaded")
                {
                        value=strprintf("%i",(int)App::single_threaded);
                        return true;
                }
                if(key=="single_threaded")
                {
                        value=strprintf("%i",(int)App::single_threaded);
                        return true;
                }
+#endif
                if(key=="auto_recover_backup_interval")
                {
                        value=strprintf("%i",App::auto_recover->get_timeout());
                        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;
+               }
+               if(key=="browser_command")
+               {
+                       value=App::browser_command;
+                       return true;
+               }
 
                return synfigapp::Settings::get_value(key,value);
        }
 
                return synfigapp::Settings::get_value(key,value);
        }
@@ -532,12 +548,25 @@ public:
                        App::distance_system=Distance::ident_system(value);;
                        return true;
                }
                        App::distance_system=Distance::ident_system(value);;
                        return true;
                }
+#ifdef SINGLE_THREADED
                if(key=="single_threaded")
                {
                        int i(atoi(value.c_str()));
                        App::single_threaded=i;
                        return true;
                }
                if(key=="single_threaded")
                {
                        int i(atoi(value.c_str()));
                        App::single_threaded=i;
                        return true;
                }
+#endif
+               if(key=="restrict_radius_ducks")
+               {
+                       int i(atoi(value.c_str()));
+                       App::restrict_radius_ducks=i;
+                       return true;
+               }
+               if(key=="browser_command")
+               {
+                       App::browser_command=value;
+                       return true;
+               }
 
                return synfigapp::Settings::set_value(key,value);
        }
 
                return synfigapp::Settings::set_value(key,value);
        }
@@ -550,8 +579,12 @@ public:
                ret.push_back("distance_system");
                ret.push_back("file_history.size");
                ret.push_back("use_colorspace_gamma");
                ret.push_back("distance_system");
                ret.push_back("file_history.size");
                ret.push_back("use_colorspace_gamma");
+#ifdef SINGLE_THREADED
                ret.push_back("single_threaded");
                ret.push_back("single_threaded");
+#endif
                ret.push_back("auto_recover_backup_interval");
                ret.push_back("auto_recover_backup_interval");
+               ret.push_back("restrict_radius_ducks");
+               ret.push_back("browser_command");
                return ret;
        }
 };
                return ret;
        }
 };
@@ -574,6 +607,7 @@ init_ui_manager()
        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", _("_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-layer-new", _("New Layer")) );
        menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
        menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
@@ -597,6 +631,7 @@ init_ui_manager()
 
        DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
        DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
 
        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);
        DEFINE_ACTION("open", Gtk::Stock::OPEN);
        DEFINE_ACTION("save", Gtk::Stock::SAVE);
        DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
@@ -613,6 +648,7 @@ init_ui_manager()
        DEFINE_ACTION("options", _("Options"));
        DEFINE_ACTION("close", _("Close View"));
        DEFINE_ACTION("close-document", _("Close Document"));
        DEFINE_ACTION("options", _("Options"));
        DEFINE_ACTION("close", _("Close View"));
        DEFINE_ACTION("close-document", _("Close Document"));
+       DEFINE_ACTION("quit", Gtk::Stock::QUIT);
 
 
        DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
 
 
        DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
@@ -641,6 +677,8 @@ 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"));
        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("stop", _("Stop"));
        DEFINE_ACTION("play", _("Play"));
        // DEFINE_ACTION("pause", _("Pause"));
        DEFINE_ACTION("stop", _("Stop"));
@@ -648,6 +686,8 @@ init_ui_manager()
        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("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"));
        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"));
@@ -715,6 +755,8 @@ init_ui_manager()
 "      </popup>"
 "      <popup name='menu-main' action='menu-main'>"
 "      <menu action='menu-file'>"
 "      </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' />"
 "              <menuitem action='save' />"
 "              <menuitem action='save-as' />"
 "              <menuitem action='revert' />"
@@ -733,6 +775,7 @@ init_ui_manager()
 "              <menuitem action='options' />"
 "              <menuitem action='close' />"
 "              <menuitem action='close-document' />"
 "              <menuitem action='options' />"
 "              <menuitem action='close' />"
 "              <menuitem action='close-document' />"
+"              <menuitem action='quit' />"
 "      </menu>"
 "      <menu action='menu-edit'>"
 "              <menuitem action='undo'/>"
 "      </menu>"
 "      <menu action='menu-edit'>"
 "              <menuitem action='undo'/>"
@@ -769,6 +812,17 @@ init_ui_manager()
 "                      <menuitem action='quality-09' />"
 "                      <menuitem action='quality-10' />"
 "              </menu>"
 "                      <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'/>"
 "              <separator name='bleh08'/>"
 "              <menuitem action='play'/>"
 //"            <menuitem action='pause'/>"
@@ -912,6 +966,9 @@ init_ui_manager()
        ACCEL("<Actions>//time-zoom-in","+");
        ACCEL("<Actions>//time-zoom-out","_");
 */
        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"));
 
        ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
        ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
 
@@ -925,7 +982,7 @@ 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(',',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>//play",              "<Control>p");
        ACCEL("<Actions>//seek-begin","Home");
        ACCEL("<Actions>//seek-end","End");
@@ -1000,19 +1057,19 @@ App::App(int *argc, char ***argv):
                        "different version of libsynfig than what is currently\n"
                        "installed. Synfig Studio will now abort. Try downloading\n"
                        "the latest version from the Synfig website at\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 website at\n"
-                       "http://www.synfig.com/ "
+                       "http://synfig.org/Download"
                );
                throw 40;
        }
        Glib::set_application_name(_("Synfig Studio"));
 
                );
                throw 40;
        }
        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;
 
        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)); }
 
        // Initialize the Synfig library
        try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
@@ -1040,6 +1097,9 @@ App::App(int *argc, char ***argv):
                studio_init_cb.task(_("Init Toolbox..."));
                toolbox=new studio::Toolbox();
 
                studio_init_cb.task(_("Init Toolbox..."));
                toolbox=new studio::Toolbox();
 
+               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 Tool Options..."));
                dialog_tool_options=new studio::Dialog_ToolOptions();
                dock_manager->register_dockable(*dialog_tool_options);
@@ -1103,30 +1163,27 @@ App::App(int *argc, char ***argv):
                device_tracker=new studio::DeviceTracker();
 
                studio_init_cb.task(_("Init Tools..."));
                device_tracker=new studio::DeviceTracker();
 
                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);
                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_bline);
-
-
                state_manager->add_state(&state_circle);
                state_manager->add_state(&state_rectangle);
                state_manager->add_state(&state_circle);
                state_manager->add_state(&state_rectangle);
-
                state_manager->add_state(&state_gradient);
                state_manager->add_state(&state_gradient);
-               state_manager->add_state(&state_eyedrop);
-               state_manager->add_state(&state_fill);
-
-               state_manager->add_state(&state_zoom);
-
-               // Enabled - it's useful to be able to work with polygons without tangent ducks getting in the way.
-               // I know we can switch tangent ducks off, but why not allow this kind of layer as well?
-               if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon);
+               if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
 
 
-               // Enabled for now.  Let's see whether they're good enough yet.
-               if(!getenv("SYNFIG_DISABLE_DRAW"   )) state_manager->add_state(&state_draw);
+               /* 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);
                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 by default - it doesn't work properly?
                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);
@@ -1134,10 +1191,6 @@ App::App(int *argc, char ***argv):
                studio_init_cb.task(_("Init ModPalette..."));
                module_list_.push_back(new ModPalette()); module_list_.back()->start();
 
                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..."));
                dialog_setup=new studio::Dialog_Setup();
 
                studio_init_cb.task(_("Init Setup Dialog..."));
                dialog_setup=new studio::Dialog_Setup();
 
@@ -1156,32 +1209,34 @@ App::App(int *argc, char ***argv):
 
                studio_init_cb.amount_complete(9900,10000);
 
 
                studio_init_cb.amount_complete(9900,10000);
 
+               bool opened_any = false;
                if(auto_recover->recovery_needed())
                {
                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
                                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,
                }
 
                // Look for any files given on the command line,
@@ -1190,11 +1245,16 @@ App::App(int *argc, char ***argv):
                        if((*argv)[*argc] && (*argv)[*argc][0]!='-')
                        {
                                studio_init_cb.task(_("Loading files..."));
                        if((*argv)[*argc] && (*argv)[*argc][0]!='-')
                        {
                                studio_init_cb.task(_("Loading files..."));
-                               about_window.hide();
+                               splash_screen.hide();
                                open((*argv)[*argc]);
                                open((*argv)[*argc]);
-                               about_window.show();
+                               opened_any = true;
+                               splash_screen.show();
                        }
 
                        }
 
+               // 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);
 
                studio_init_cb.task(_("Done."));
                studio_init_cb.amount_complete(10000,10000);
 
@@ -1223,7 +1283,8 @@ App::~App()
        selected_instance=0;
 
        // Unload all of the modules
        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;
 
 
        delete state_manager;
 
@@ -1231,6 +1292,8 @@ App::~App()
 
        delete auto_recover;
 
 
        delete auto_recover;
 
+       delete about;
+       
        toolbox->hide();
 
 //     studio::App::iteration(false);
        toolbox->hide();
 
 //     studio::App::iteration(false);
@@ -1421,7 +1484,10 @@ App::reset_initial_window_configuration()
        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("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");
+#ifdef SINGLE_THREADED
        synfigapp::Main::settings().set_value("pref.single_threaded","0");
        synfigapp::Main::settings().set_value("pref.single_threaded","0");
+#endif
+       synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
        synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
 }
 
        synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
 }
 
@@ -1536,8 +1602,10 @@ static OPENFILENAME ofn={};
 #endif
 
 bool
 #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") ;
 
 #ifdef USE_WIN32_FILE_DIALOGS
        static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
 
@@ -1582,26 +1650,36 @@ App::dialog_open_file(const std::string &title, std::string &filename)
 
 #else
        synfig::String prev_path;
 
 #else
        synfig::String prev_path;
-       if(!_preferences.get_value("curr_path",prev_path))
-               prev_path=".";
+
+       if(!_preferences.get_value(preference, prev_path))
+               prev_path = ".";
+
        prev_path = absolute_path(prev_path);
 
        prev_path = absolute_path(prev_path);
 
-    Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_OPEN);
+    Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
+
     dialog->set_current_folder(prev_path);
     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
     dialog->add_button(Gtk::Stock::OPEN,   Gtk::RESPONSE_ACCEPT);
     dialog->set_current_folder(prev_path);
     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
     dialog->add_button(Gtk::Stock::OPEN,   Gtk::RESPONSE_ACCEPT);
-    if(!filename.empty())
-               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();
+
+    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 true;
     }
+
     delete dialog;
     return false;
     delete dialog;
     return false;
+
     /*
 
        GtkWidget *ok;
     /*
 
        GtkWidget *ok;
@@ -1636,7 +1714,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));
        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
        {
        }
        else
        {
@@ -1650,8 +1728,10 @@ App::dialog_open_file(const std::string &title, std::string &filename)
 }
 
 bool
 }
 
 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)
 {
 {
+       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") ;
 
 #if USE_WIN32_FILE_DIALOGS
        static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
 
@@ -1690,27 +1770,52 @@ App::dialog_save_file(const std::string &title, std::string &filename)
        if(GetSaveFileName(&ofn))
        {
                filename=szFilename;
        if(GetSaveFileName(&ofn))
        {
                filename=szFilename;
-               _preferences.set_value("curr_path",dirname(filename));
+               _preferences.set_value(preference,dirname(filename));
                return true;
        }
        return false;
 #else
        synfig::String prev_path;
                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=".";
                prev_path=".";
+
        prev_path = absolute_path(prev_path);
 
        prev_path = absolute_path(prev_path);
 
-    Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
+    Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
+
     dialog->set_current_folder(prev_path);
     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
     dialog->add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_ACCEPT);
     dialog->set_current_folder(prev_path);
     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
     dialog->add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_ACCEPT);
-    if(!filename.empty())
+
+       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);
+       }
+
+    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;
        {
                std::string full_path;
                if (is_absolute_path(filename))
                        full_path = filename;
                else
                        full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
+
                // select the file if it exists
                dialog->set_filename(full_path);
 
                // select the file if it exists
                dialog->set_filename(full_path);
 
@@ -1719,15 +1824,19 @@ App::dialog_save_file(const std::string &title, std::string &filename)
                if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
                        dialog->set_current_name(basename(filename));
        }
                if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
                        dialog->set_current_name(basename(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;
         delete dialog;
-               _preferences.set_value("curr_path",dirname(filename));
         return true;
     }
         return true;
     }
+
     delete dialog;
     return false;
     delete dialog;
     return false;
-//     return dialog_open_file(title, filename);
 #endif
 }
 
 #endif
 }
 
@@ -1794,6 +1903,49 @@ App::dialog_not_implemented()
        dialog.run();
 }
 
        dialog.run();
 }
 
+static bool
+try_open_url(const std::string &url)
+{
+#ifdef WIN32
+       return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
+#else  // WIN32
+       gchar* argv[3] = {strdup(App::browser_command.c_str()), strdup(url.c_str()), NULL};
+
+       GError* gerror = NULL;
+       gboolean retval;
+       retval = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &gerror);
+       free(argv[0]);
+       free(argv[1]);
+
+       if (!retval)
+    {
+               error(_("Could not execute specified web browser: %s"), gerror->message);
+               g_error_free(gerror);
+               return false;
+    }
+
+       return true;
+#endif  // WIN32
+}
+
+void
+App::dialog_help()
+{
+       if (!try_open_url("http://synfig.org/Documentation"))
+       {
+               Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
+               dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
+               dialog.set_title(_("Help"));
+               dialog.run();
+       }
+}
+
+void
+App::open_url(const std::string &url)
+{
+       try_open_url(url);
+}
+
 bool
 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
 {
 bool
 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
 {
@@ -1855,22 +2007,26 @@ App::open_as(std::string filename,std::string as)
                if(canvas && get_instance(canvas))
                {
                        get_instance(canvas)->find_canvas_view(canvas)->present();
                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)
        {
        }
        catch(String x)
        {
@@ -1883,8 +2039,6 @@ App::open_as(std::string filename,std::string as)
                return false;
        }
 
                return false;
        }
 
-       _preferences.set_value("curr_path",dirname(as));
-
        return true;
 }
 
        return true;
 }
 
@@ -1893,13 +2047,14 @@ void
 App::new_instance()
 {
        handle<synfig::Canvas> canvas=synfig::Canvas::create();
 App::new_instance()
 {
        handle<synfig::Canvas> canvas=synfig::Canvas::create();
-       canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
 
 
-       String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
+       String file_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
+       canvas->set_name(file_name);
+       file_name += ".sifz";
 
        canvas->rend_desc().set_frame_rate(24.0);
        canvas->rend_desc().set_time_start(0.0);
 
        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));
        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));
@@ -1912,16 +2067,17 @@ App::new_instance()
 
        handle<Instance> instance = Instance::create(canvas);
 
 
        handle<Instance> instance = Instance::create(canvas);
 
-       if (!getenv("SYNFIG_DISABLE_NEW_CANVAS_EDIT_PROPERTIES"))
+       if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
                instance->find_canvas_view(canvas)->canvas_properties.present();
 }
 
 void
                instance->find_canvas_view(canvas)->canvas_properties.present();
 }
 
 void
-App::dialog_open()
+App::dialog_open(string filename)
 {
 {
-       string filename="*.sif";
+       if (filename.empty())
+               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
        {
                // If the filename still has wildcards, then we should
                // continue looking for the file we want
@@ -2002,7 +2158,8 @@ App::get_instance(etl::handle<synfig::Canvas> canvas)
 void
 App::dialog_about()
 {
 void
 App::dialog_about()
 {
-       (new class About())->show();
+       if(about)
+               about->show();
 }
 
 void
 }
 
 void