Remove spaces and tabs at end of lines.
[synfig.git] / synfig-studio / trunk / src / gtkmm / app.cpp
index 8195891..ee4459b 100644 (file)
@@ -6,7 +6,9 @@
 **
 **     \legal
 **     Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
-**     Copyright (c) 2007 Chris Moore
+**     Copyright (c) 2007, 2008 Chris Moore
+**     Copyright (c) 2008 Gerald Young
+**  Copyright (c) 2008 Carlos López
 **
 **     This package is free software; you can redistribute it and/or
 **     modify it under the terms of the GNU General Public License as
 #      include <config.h>
 #endif
 
+#ifdef WIN32
+#define WINVER 0x0500
+#include <windows.h>
+#endif
+
 #include <fstream>
 #include <iostream>
 #include <locale>
 #include <gtkmm/inputdialog.h>
 #include <gtkmm/accelmap.h>
 #include <gtkmm/uimanager.h>
+#include <gtkmm/textview.h>
 
 #include <gtk/gtk.h>
 
+#include <gdkmm/general.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"
 #include "state_rectangle.h"
 #include "state_smoothmove.h"
 #include "state_scale.h"
+#include "state_star.h"
+#include "state_text.h"
 #include "state_width.h"
 #include "state_rotate.h"
 #include "state_zoom.h"
 
 #include "devicetracker.h"
 #include "dialog_tooloptions.h"
+#include "widget_enum.h"
 
 #include "autorecover.h"
 
 #include <fmod.h>
 #endif
 
-#ifdef WIN32
-#define _WIN32_WINNT 0x0500
-#include <windows.h>
-#endif
 #include <gtkmm/accelmap.h>
 #include <gtkmm/filechooser.h>
 #include <gtkmm/filechooserdialog.h>
@@ -200,6 +211,8 @@ App::signal_instance_deleted() { return signal_instance_deleted_; }
 static std::list<std::string> recent_files;
 const std::list<std::string>& App::get_recent_files() { return recent_files; }
 
+static std::list<std::string> recent_files_window_size;
+
 int    App::Busy::count;
 bool App::shutdown_in_progress;
 
@@ -222,6 +235,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;
@@ -256,7 +271,20 @@ studio::Dock_Curves* dock_curves;
 std::list< etl::handle< studio::Module > > module_list_;
 
 bool studio::App::use_colorspace_gamma=true;
+#ifdef SINGLE_THREADED
 bool studio::App::single_threaded=false;
+#endif
+bool studio::App::restrict_radius_ducks=false;
+bool studio::App::resize_imported_images=false;
+String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
+int studio::App::preferred_x_size=480;
+int studio::App::preferred_y_size=270;
+String studio::App::predefined_size(DEFAULT_PREDEFINED_SIZE);
+#ifdef USE_OPEN_FOR_URLS
+String studio::App::browser_command("open"); // MacOS only
+#else
+String studio::App::browser_command("xdg-open"); // Linux XDG standard
+#endif
 
 static int max_recent_files_=25;
 int studio::App::get_max_recent_files() { return max_recent_files_; }
@@ -467,16 +495,53 @@ public:
                        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;
                }
+#endif
                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=="resize_imported_images")
+               {
+                       value=strprintf("%i",(int)App::resize_imported_images);
+                       return true;
+               }
+               if(key=="browser_command")
+               {
+                       value=App::browser_command;
+                       return true;
+               }
+               if(key=="custom_filename_prefix")
+               {
+                       value=App::custom_filename_prefix;
+                       return true;
+               }
+               if(key=="preferred_x_size")
+               {
+                       value=strprintf("%i",App::preferred_x_size);
+                       return true;
+               }
+               if(key=="preferred_y_size")
+               {
+                       value=strprintf("%i",App::preferred_y_size);
+                       return true;
+               }
+               if(key=="predefined_size")
+               {
+                       value=strprintf("%s",App::predefined_size.c_str());
+                       return true;
+               }
 
                return synfigapp::Settings::get_value(key,value);
        }
@@ -527,13 +592,53 @@ public:
                        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;
                }
-
+#endif
+               if(key=="restrict_radius_ducks")
+               {
+                       int i(atoi(value.c_str()));
+                       App::restrict_radius_ducks=i;
+                       return true;
+               }
+               if(key=="resize_imported_images")
+               {
+                       int i(atoi(value.c_str()));
+                       App::resize_imported_images=i;
+                       return true;
+               }
+               if(key=="browser_command")
+               {
+                       App::browser_command=value;
+                       return true;
+               }
+               if(key=="custom_filename_prefix")
+               {
+                       App::custom_filename_prefix=value;
+                       return true;
+               }
+               if(key=="preferred_x_size")
+               {
+                       int i(atoi(value.c_str()));
+                       App::preferred_x_size=i;
+                       return true;
+               }
+               if(key=="preferred_y_size")
+               {
+                       int i(atoi(value.c_str()));
+                       App::preferred_y_size=i;
+                       return true;
+               }
+               if(key=="predefined_size")
+               {
+                       App::predefined_size=value;
+                       return true;
+               }
                return synfigapp::Settings::set_value(key,value);
        }
 
@@ -545,8 +650,17 @@ public:
                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");
+#endif
                ret.push_back("auto_recover_backup_interval");
+               ret.push_back("restrict_radius_ducks");
+               ret.push_back("resize_imported_images");
+               ret.push_back("browser_command");
+               ret.push_back("custom_filename_prefix");
+               ret.push_back("preferred_x_size");
+               ret.push_back("preferred_y_size");
+               ret.push_back("predefined_size");
                return ret;
        }
 };
@@ -619,6 +733,8 @@ init_ui_manager()
        DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
        DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
        DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
+       DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
+       DEFINE_ACTION("select-all-layers", _("Select All Layers"));
        DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
        DEFINE_ACTION("properties", _("Properties"));
 
@@ -639,12 +755,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("lowres-pixel-01", _("Set Low-Res pixel size to 2^1"));
-       DEFINE_ACTION("lowres-pixel-02", _("Set Low-Res pixel size to 2^2"));
-       DEFINE_ACTION("lowres-pixel-03", _("Set Low-Res pixel size to 2^3"));
-       DEFINE_ACTION("lowres-pixel-04", _("Set Low-Res pixel size to 2^4"));
-       DEFINE_ACTION("lowres-pixel-05", _("Set Low-Res pixel size to 2^5"));
-       DEFINE_ACTION("lowres-pixel-06", _("Set Low-Res pixel size to 2^6"));
+       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"));
@@ -652,6 +764,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("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"));
@@ -749,8 +863,10 @@ init_ui_manager()
 "              <menuitem action='copy'/>"
 "              <menuitem action='paste'/>"
 "              <separator name='bleh06'/>"
-"              <menuitem action='select-all-ducks'/>"
+"              <menuitem action='select-all-layers'/>"
 "              <menuitem action='unselect-all-layers'/>"
+"              <menuitem action='select-all-ducks'/>"
+"              <menuitem action='unselect-all-ducks'/>"
 "              <separator name='bleh07'/>"
 "              <menuitem action='properties'/>"
 "      </menu>"
@@ -777,12 +893,15 @@ init_ui_manager()
 "                      <menuitem action='quality-10' />"
 "              </menu>"
 "              <menu action='menu-lowres-pixel'>"
-"                      <menuitem action='lowres-pixel-01' />"
-"                      <menuitem action='lowres-pixel-02' />"
-"                      <menuitem action='lowres-pixel-03' />"
-"                      <menuitem action='lowres-pixel-04' />"
-"                      <menuitem action='lowres-pixel-05' />"
-"                      <menuitem action='lowres-pixel-06' />"
+"              <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'/>"
@@ -873,7 +992,7 @@ init_ui_manager()
        }
 
        // Add default keyboard accelerators
-#define ACCEL(path,accel)                                              \
+#define ACCEL(accel,path)                                              \
        {                                                                                       \
                Gtk::AccelKey accel_key(accel,path);    \
                Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod());       \
@@ -885,87 +1004,80 @@ init_ui_manager()
                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");
-       ACCEL("<Actions>//preview","F11");
-       ACCEL("<Actions>//properties","F8");
-       ACCEL("<Actions>//options","F12");
-       ACCEL("<Actions>//import","<control>i");
-       ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
-       ACCEL("<Actions>//toggle-grid-show","<Control>g");
-       ACCEL("<Actions>//toggle-grid-snap","<Control>l");
-       ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
-       ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
-       ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
-       ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
-       ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
-       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"));
-
-       ACCEL("<Actions>//quality-01","<Control>1");
-       ACCEL("<Actions>//quality-02","<Control>2");
-       ACCEL("<Actions>//quality-03","<Control>3");
-       ACCEL("<Actions>//quality-04","<Control>4");
-       ACCEL("<Actions>//quality-05","<Control>5");
-       ACCEL("<Actions>//quality-06","<Control>6");
-       ACCEL("<Actions>//quality-07","<Control>7");
-       ACCEL("<Actions>//quality-08","<Control>8");
-       ACCEL("<Actions>//quality-09","<Control>9");
-       ACCEL("<Actions>//quality-10","<Control>0");
-       ACCEL("<Actions>//undo","<Control>z");
-       ACCEL("<Actions>//redo","<Control>r");
-       ACCEL("<Actions>//action-layer_remove","Delete");
-
-/*     ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
-       ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
-       ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
-       ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
-       ACCEL("<Actions>//time-zoom-in","+");
-       ACCEL("<Actions>//time-zoom-out","_");
-*/
-       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::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
-       ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
-       ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
-       ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
-       ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
-       ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
-       ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
-       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::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-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");
+       // the toolbox
+       ACCEL("<Mod1>a",                                                                                                        "<Actions>//state-normal"                                       );
+       ACCEL("<Mod1>v",                                                                                                        "<Actions>//state-smooth_move"                          );
+       ACCEL("<Mod1>s",                                                                                                        "<Actions>//state-scale"                                        );
+       ACCEL("<Mod1>t",                                                                                                        "<Actions>//state-rotate"                                       );
+       ACCEL("<Mod1>m",                                                                                                        "<Actions>//state-mirror"                                       );
+       ACCEL("<Mod1>c",                                                                                                        "<Actions>//state-circle"                                       );
+       ACCEL("<Mod1>r",                                                                                                        "<Actions>//state-rectangle"                            );
+       ACCEL("<Mod1>q",                                                                                                        "<Actions>//state-star"                                         );
+       ACCEL("<Mod1>g",                                                                                                        "<Actions>//state-gradient"                                     );
+       ACCEL("<Mod1>p",                                                                                                        "<Actions>//state-polygon"                                      );
+       ACCEL("<Mod1>b",                                                                                                        "<Actions>//state-bline"                                        );
+       ACCEL("<Mod1>x",                                                                                                        "<Actions>//state-text"                                         );
+       ACCEL("<Mod1>f",                                                                                                        "<Actions>//state-fill"                                         );
+       ACCEL("<Mod1>e",                                                                                                        "<Actions>//state-eyedrop"                                      );
+       ACCEL("<Mod1>z",                                                                                                        "<Actions>//state-zoom"                                         );
+       ACCEL("<Mod1>d",                                                                                                        "<Actions>//state-draw"                                         );
+       ACCEL("<Mod1>k",                                                                                                        "<Actions>//state-sketch"                                       );
+       ACCEL("<Mod1>w",                                                                                                        "<Actions>//state-width"                                        );
+
+       // everything else
+       ACCEL("<Control>a",                                                                                                     "<Actions>//select-all-ducks"                           );
+       ACCEL("<Control>d",                                                                                                     "<Actions>//unselect-all-ducks"                         );
+       ACCEL("<Control><Shift>a",                                                                                      "<Actions>//select-all-layers"                          );
+       ACCEL("<Control><Shift>d",                                                                                      "<Actions>//unselect-all-layers"                        );
+       ACCEL("F9",                                                                                                                     "<Actions>//render"                                                     );
+       ACCEL("F11",                                                                                                            "<Actions>//preview"                                            );
+       ACCEL("F8",                                                                                                                     "<Actions>//properties"                                         );
+       ACCEL("F12",                                                                                                            "<Actions>//options"                                            );
+       ACCEL("<control>i",                                                                                                     "<Actions>//import"                                                     );
+       ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),      "<Actions>//stop"                                                       ));
+       ACCEL("<Control>g",                                                                                                     "<Actions>//toggle-grid-show"                           );
+       ACCEL("<Control>l",                                                                                                     "<Actions>//toggle-grid-snap"                           );
+       ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,                                                     "<Actions>//toggle-low-res"                                     ));
+       ACCEL("<Mod1>1",                                                                                                        "<Actions>//mask-position-ducks"                        );
+       ACCEL("<Mod1>2",                                                                                                        "<Actions>//mask-vertex-ducks"                          );
+       ACCEL("<Mod1>3",                                                                                                        "<Actions>//mask-tangent-ducks"                         );
+       ACCEL("<Mod1>4",                                                                                                        "<Actions>//mask-radius-ducks"                          );
+       ACCEL("<Mod1>5",                                                                                                        "<Actions>//mask-width-ducks"                           );
+       ACCEL("<Mod1>6",                                                                                                        "<Actions>//mask-angle-ducks"                           );
+       ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,                                       "<Actions>//action-LayerRaise"                          ));
+       ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,                                     "<Actions>//action-LayerLower"                          ));
+       ACCEL("<Control>1",                                                                                                     "<Actions>//quality-01"                                         );
+       ACCEL("<Control>2",                                                                                                     "<Actions>//quality-02"                                         );
+       ACCEL("<Control>3",                                                                                                     "<Actions>//quality-03"                                         );
+       ACCEL("<Control>4",                                                                                                     "<Actions>//quality-04"                                         );
+       ACCEL("<Control>5",                                                                                                     "<Actions>//quality-05"                                         );
+       ACCEL("<Control>6",                                                                                                     "<Actions>//quality-06"                                         );
+       ACCEL("<Control>7",                                                                                                     "<Actions>//quality-07"                                         );
+       ACCEL("<Control>8",                                                                                                     "<Actions>//quality-08"                                         );
+       ACCEL("<Control>9",                                                                                                     "<Actions>//quality-09"                                         );
+       ACCEL("<Control>0",                                                                                                     "<Actions>//quality-10"                                         );
+       ACCEL("<Control>z",                                                                                                     "<Actions>//undo"                                                       );
+       ACCEL("<Control>r",                                                                                                     "<Actions>//redo"                                                       );
+       ACCEL2(Gtk::AccelKey(GDK_Delete,Gdk::CONTROL_MASK,                                      "<Actions>//action-LayerRemove"                         ));
+       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::CONTROL_MASK,                                                     "<Actions>//jump-next-keyframe"                         ));
+       ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,                                                     "<Actions>//jump-prev-keyframe"                         ));
+       ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,                                                     "<Actions>//canvas-zoom-in"                                     ));
+       ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,                                                     "<Actions>//canvas-zoom-out"                            ));
+       ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,                                                     "<Actions>//time-zoom-in"                                       ));
+       ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,                                                     "<Actions>//time-zoom-out"                                      ));
+       ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,                                                     "<Actions>//seek-next-frame"                            ));
+       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"                           ));
+       ACCEL("<Mod1>o",                                                                                                        "<Actions>//toggle-onion-skin"                          );
+       ACCEL("<Control><Shift>z",                                                                                      "<Actions>//canvas-zoom-fit"                            );
+       ACCEL("<Control>p",                                                                                                     "<Actions>//play"                                                       );
+       ACCEL("Home",                                                                                                           "<Actions>//seek-begin"                                         );
+       ACCEL("End",                                                                                                            "<Actions>//seek-end"                                           );
 
 #undef ACCEL
 }
@@ -1021,16 +1133,20 @@ App::App(int *argc, char ***argv):
        }
        Glib::set_application_name(_("Synfig Studio"));
 
-       About about_window;
-       about_window.set_can_self_destruct(false);
-       about_window.show();
+       Splash splash_screen;
+       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(std::runtime_error x)
+       {
+               get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
+               throw;
+       }
        catch(...)
        {
                get_ui_interface()->error(_("Failed to initialize synfig!"));
@@ -1055,6 +1171,9 @@ App::App(int *argc, char ***argv):
                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);
@@ -1118,41 +1237,35 @@ App::App(int *argc, char ***argv):
                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);
+               studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
 
-               state_manager->add_state(&state_bline);
-
-
+               /* row 2 */
                state_manager->add_state(&state_circle);
                state_manager->add_state(&state_rectangle);
-
+               state_manager->add_state(&state_star);
                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 */
+               state_manager->add_state(&state_bline);
+               state_manager->add_state(&state_text);
+               state_manager->add_state(&state_fill);
+               state_manager->add_state(&state_eyedrop);
                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);
-
-               // Enabled for now.  Let's see whether they're good enough yet.
-               if(!getenv("SYNFIG_DISABLE_DRAW"   )) state_manager->add_state(&state_draw);
+               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);
-
-               // Disabled by default - it doesn't work properly?
-               if(getenv("SYNFIG_ENABLE_WIDTH"    )) state_manager->add_state(&state_width);
+               if(!getenv("SYNFIG_DISABLE_WIDTH"  )) state_manager->add_state(&state_width); // Enabled since 0.61.09
 
                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();
 
@@ -1171,45 +1284,46 @@ App::App(int *argc, char ***argv):
 
                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,
                // and load them if found.
-               bool opened_any = false;
                for(;*argc>=1;(*argc)--)
                        if((*argv)[*argc] && (*argv)[*argc][0]!='-')
                        {
                                studio_init_cb.task(_("Loading files..."));
-                               about_window.hide();
+                               splash_screen.hide();
                                open((*argv)[*argc]);
                                opened_any = true;
-                               about_window.show();
+                               splash_screen.show();
                        }
 
                // if no file was specified to be opened, create a new document to help new users get started more easily
@@ -1253,6 +1367,8 @@ App::~App()
 
        delete auto_recover;
 
+       delete about;
+
        toolbox->hide();
 
 //     studio::App::iteration(false);
@@ -1281,7 +1397,12 @@ App::~App()
 String
 App::get_user_app_directory()
 {
+//! \todo do we need locale_from_utf8() on non-Windows boxes too?  (bug #1837445)
+#ifdef WIN32
+       return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
+#else
        return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
+#endif
 }
 
 synfig::String
@@ -1290,8 +1411,116 @@ App::get_config_file(const synfig::String& file)
        return Glib::build_filename(get_user_app_directory(),file);
 }
 
+#define SCALE_FACTOR   (1280)
+//! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
+void
+App::set_recent_file_window_size(etl::handle<Instance> instance)
+{
+       int screen_w(Gdk::screen_width());
+       int screen_h(Gdk::screen_height());
+
+       const std::string &canvas_window_size = *recent_files_window_size.begin();
+
+       if(canvas_window_size.empty())
+               return;
+
+       synfig::String::size_type current=0;
+       bool seen_root(false), shown_non_root(false);
+
+       while(current != synfig::String::npos)
+       {
+               // find end of first field (canvas) or return
+               synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
+               if(separator == synfig::String::npos) break;
+
+               // find the canvas
+               synfig::Canvas::Handle canvas;
+               try {
+                       String warnings;
+                       canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
+               }
+               catch(Exception::IDNotFound) {
+                       // can't find the canvas; skip to the next canvas or return
+                       separator = canvas_window_size.find_first_of('\t', current);
+                       if(separator == synfig::String::npos) return;
+                       current = separator+1;
+                       continue;
+               }
+
+               if (canvas->is_root())
+                       seen_root = true;
+               else
+                       shown_non_root = true;
+
+               // check that we have the tab character the ends this canvas' data or return
+               current = separator+1;
+               separator = canvas_window_size.find_first_of('\t', current);
+               if(separator == synfig::String::npos) return;
+
+               int x,y,w,h;
+               if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
+               {
+                       current = separator+1;
+                       continue;
+               }
+
+               if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
+               if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
+               x=x*screen_w/SCALE_FACTOR;
+               y=y*screen_h/SCALE_FACTOR;
+               if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
+                       x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
+               if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
+                       y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
+
+               if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
+               if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
+
+               CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
+               canvasview->move(x,y);
+               canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
+               canvasview->present();
+
+               current = separator+1;
+       }
+
+       if (shown_non_root && !seen_root)
+               instance->find_canvas_view(instance->get_canvas())->hide();
+}
+
+void
+App::add_recent_file(const etl::handle<Instance> instance)
+{
+       int screen_w(Gdk::screen_width());
+       int screen_h(Gdk::screen_height());
+
+       std::string canvas_window_size;
+
+       const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
+       Instance::CanvasViewList::const_iterator iter;
+
+       for(iter=cview_list.begin();iter!=cview_list.end();iter++)
+       {
+               if( !((*iter)->is_visible()) )
+                       continue;
+
+               etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
+               int x_pos, y_pos, x_size, y_size;
+               (*iter)->get_position(x_pos,y_pos);
+               (*iter)->get_size(x_size,y_size);
+
+               canvas_window_size += strprintf("%s %d %d %d %d\t",
+                                                                               canvas->get_relative_id(canvas->get_root()).c_str(),
+                                                                               x_pos*SCALE_FACTOR/screen_w,  y_pos*SCALE_FACTOR/screen_h,
+                                                                               x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
+       }
+
+       add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
+}
+#undef SCALE_FACTOR
+
 void
-App::add_recent_file(const std::string &file_name)
+App::add_recent_file(const std::string &file_name, const std::string &window_size)
 {
        std::string filename(file_name);
 
@@ -1308,23 +1537,35 @@ App::add_recent_file(const std::string &file_name)
        if(!is_absolute_path(filename))
                filename=absolute_path(filename);
 
+       std::string old_window_size;
+
        list<string>::iterator iter;
+       list<string>::iterator iter_wsize;
        // Check to see if the file is already on the list.
        // If it is, then remove it from the list
-       for(iter=recent_files.begin();iter!=recent_files.end();iter++)
+       for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
                if(*iter==filename)
                {
                        recent_files.erase(iter);
+                       old_window_size = *iter_wsize;
+                       recent_files_window_size.erase(iter_wsize);
                        break;
                }
 
 
        // Push the filename to the front of the list
        recent_files.push_front(filename);
+       if(window_size.empty())
+               recent_files_window_size.push_front(old_window_size);
+       else
+               recent_files_window_size.push_front(window_size);
 
        // Clean out the files at the end of the list.
        while(recent_files.size()>(unsigned)get_max_recent_files())
+       {
                recent_files.pop_back();
+               recent_files_window_size.pop_back();
+       }
 
        signal_recent_files_changed_();
 
@@ -1374,7 +1615,23 @@ App::save_settings()
                        for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
                                file<<*iter<<endl;
                }while(0);
+               do{
+                       std::string filename=get_config_file("recentfiles")+std::string("_window_size");
 
+                       std::ofstream file(filename.c_str());
+
+                       if(!file)
+                       {
+                               synfig::warning("Unable to save %s",filename.c_str());
+                               break;
+                       }
+
+                       list<string>::reverse_iterator iter;
+
+                       for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
+                               file<<*iter<<endl;
+
+               }while(0);
                std::string filename=get_config_file("settings");
                synfigapp::Main::settings().save_to_file(filename);
        setlocale(LC_NUMERIC,old_locale);
@@ -1398,22 +1655,50 @@ App::load_settings()
                        Gtk::AccelMap::load(filename);
                }
                {
+                       bool window_size_broken = false;
+
                        std::string filename=get_config_file("recentfiles");
+                       std::string filename_window_size=filename+std::string("_window_size");
 
                        std::ifstream file(filename.c_str());
+                       std::ifstream file_window_size(filename_window_size.c_str());
+
+                       if(!file_window_size)
+                               window_size_broken = true;
 
                        while(file)
                        {
                                std::string recent_file;
+                               std::string recent_file_window_size;
                                getline(file,recent_file);
+                               if(!window_size_broken)
+                                       getline(file_window_size,recent_file_window_size);
                                if(!recent_file.empty())
-                                       add_recent_file(recent_file);
+                               {
+                                       if(!window_size_broken && !file_window_size)
+                                               window_size_broken = true;
+                                       if (std::ifstream(recent_file.c_str()))
+                                       {
+                                               if(!window_size_broken)
+                                                       add_recent_file(recent_file,recent_file_window_size);
+                                               else
+                                                       add_recent_file(recent_file);
+                                       }
+                               }
+                       }
+                       if(!window_size_broken && file_window_size)
+                               window_size_broken = true;
+
+                       if(window_size_broken)
+                       {
+                               recent_files_window_size.clear();
+                               recent_files_window_size.resize(recent_files.size());
                        }
                }
                std::string filename=get_config_file("settings");
                if(!synfigapp::Main::settings().load_from_file(filename))
                {
-                       //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
+                       //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
                        //if(!synfigapp::Main::settings().load_from_file(filename))
                        {
                                gamma.set_gamma(1.0/2.2);
@@ -1443,7 +1728,15 @@ 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");
+#ifdef SINGLE_THREADED
        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("pref.resize_imported_images","0");
+       synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
+       synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
+       synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
+       synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
        synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
 }
 
@@ -1560,7 +1853,7 @@ static OPENFILENAME ofn={};
 bool
 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());
+       // 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") ;
@@ -1627,7 +1920,7 @@ App::dialog_open_file(const std::string &title, std::string &filename, std::stri
 
     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());
+               // 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;
@@ -1686,7 +1979,7 @@ App::dialog_open_file(const std::string &title, std::string &filename, std::stri
 bool
 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());
+       // 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") ;
@@ -1744,6 +2037,25 @@ App::dialog_save_file(const std::string &title, std::string &filename, std::stri
     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
     dialog->add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_ACCEPT);
 
+       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_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
+                                                                          .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
+                                                                          .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
@@ -1764,8 +2076,10 @@ App::dialog_save_file(const std::string &title, std::string &filename, std::stri
        }
 
     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());
+               // 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;
@@ -1839,14 +2153,114 @@ App::dialog_not_implemented()
        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
+       std::vector<std::string> command_line;
+       std::vector<std::string> browsers;
+       browsers.reserve(23);
+
+       // Browser wrapper scripts
+#ifdef USE_OPEN_FOR_URLS
+       browsers.push_back("open");              // Apple MacOS X wrapper, on Linux it opens a virtual console
+#endif
+       browsers.push_back("xdg-open");          // XDG wrapper
+       browsers.push_back("sensible-browser");  // Debian wrapper
+       browsers.push_back("gnome-open");        // GNOME wrapper
+       browsers.push_back("kfmclient");         // KDE wrapper
+       browsers.push_back("exo-open");          // XFCE wrapper
+
+       // Alternatives system
+       browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
+       browsers.push_back("x-www-browser");     // Debian GUI alternative
+
+       // Individual browsers
+       browsers.push_back("firefox");
+       browsers.push_back("epiphany-browser");
+       browsers.push_back("epiphany");
+       browsers.push_back("konqueror");
+       browsers.push_back("iceweasel");
+       browsers.push_back("mozilla");
+       browsers.push_back("netscape");
+       browsers.push_back("icecat");
+       browsers.push_back("galeon");
+       browsers.push_back("midori");
+       browsers.push_back("safari");
+       browsers.push_back("opera");
+       browsers.push_back("amaya");
+       browsers.push_back("netsurf");
+       browsers.push_back("dillo");
+
+       // Try the user-specified browser first
+       command_line.push_back(App::browser_command);
+       if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
+       command_line.push_back(url);
+
+       try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
+       catch( Glib::SpawnError& exception ){
+
+               while ( !browsers.empty() )
+               {
+                       // Skip the browser if we already tried it
+                       if( browsers[0] == App::browser_command )
+                               continue;
+
+                       // Construct the command line
+                       command_line.clear();
+                       command_line.push_back(browsers[0]);
+                       if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
+                       command_line.push_back(url);
+
+                       // Remove the browser from the list
+                       browsers.erase(browsers.begin());
+
+                       // Try to spawn the browser
+                       try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
+                       // Failed, move on to the next one
+                       catch(Glib::SpawnError& exception){ continue; }
+                       return true; // No exception means we succeeded!
+               }
+       }
+
+       return false;
+#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)
+{
+       if(!try_open_url(url))
+       {
+               Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
+               dialog.set_secondary_text(url);
+               dialog.set_title(_("No browser found"));
+               dialog.run();
+       }
+}
+
 bool
 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
 {
        Gtk::Dialog dialog(
                title,          // Title
                true,           // Modal
-               true            // use_separator
-       );
+               true);          // use_separator
+
        Gtk::Label label(message);
        label.show();
        dialog.get_vbox()->pack_start(label);
@@ -1855,11 +2269,13 @@ App::dialog_entry(const std::string &title, const std::string &message,std::stri
        entry.set_text(text);
        entry.show();
        entry.set_activates_default(true);
+
        dialog.get_vbox()->pack_start(entry);
 
        dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
        dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
        dialog.set_default_response(Gtk::RESPONSE_OK);
+
        entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
        dialog.show();
 
@@ -1871,8 +2287,39 @@ App::dialog_entry(const std::string &title, const std::string &message,std::stri
        return true;
 }
 
+bool
+App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
+{
+       Gtk::Dialog dialog(
+               title,          // Title
+               true,           // Modal
+               true);          // use_separator
+
+       Gtk::Label label(message);
+       label.show();
+       dialog.get_vbox()->pack_start(label);
+
+       Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
+       text_buffer->set_text(text);
+       Gtk::TextView text_view(text_buffer);
+       text_view.show();
 
+       dialog.get_vbox()->pack_start(text_view);
 
+       dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
+       dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
+       dialog.set_default_response(Gtk::RESPONSE_OK);
+
+       //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
+       dialog.show();
+
+       if(dialog.run()!=Gtk::RESPONSE_OK)
+               return false;
+
+       text=text_buffer->get_text();
+
+       return true;
+}
 
 bool
 App::open(std::string filename)
@@ -1889,39 +2336,58 @@ App::open_as(std::string filename,std::string as)
 #ifdef WIN32
     char long_name[1024];
     if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
-    as=long_name;
+       // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
+       // don't use it if that's the case
+       if (long_name[0] != '\0')
+               as=long_name;
 #endif
 
        try
        {
                OneMoment one_moment;
+               String errors, warnings;
 
-               etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
+               etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
                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 load \"%s\":\n\n"),filename.c_str()) + errors;
 
-               add_recent_file(as);
+                       if (warnings != "")
+                               dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
 
-               handle<Instance> instance(Instance::create(canvas));
+                       if (as.find(custom_filename_prefix.c_str()) != 0)
+                               add_recent_file(as);
 
-               if(!instance)
-                       throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
+                       handle<Instance> instance(Instance::create(canvas));
 
-               one_moment.hide();
+                       if(!instance)
+                               throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
 
-               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();
+                       set_recent_file_window_size(instance);
+
+                       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();
+               }
        }
        catch(String x)
        {
                dialog_error_blocking(_("Error"), x);
                return false;
        }
+       catch(runtime_error x)
+       {
+               dialog_error_blocking(_("Error"), x.what());
+               return false;
+       }
        catch(...)
        {
                dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
@@ -1936,19 +2402,22 @@ void
 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", App::custom_filename_prefix.c_str(), 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_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_br(Vector(4,-2.25));
-       canvas->rend_desc().set_w(480);
-       canvas->rend_desc().set_h(270);
+       // The top left and botton right positions are expressed in units
+       // Original convention is that 1 unit = 60 pixels
+       canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
+       canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
+       canvas->rend_desc().set_w(preferred_x_size);
+       canvas->rend_desc().set_h(preferred_y_size);
        canvas->rend_desc().set_antialias(1);
        canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
        canvas->set_file_name(file_name);
@@ -1960,9 +2429,10 @@ App::new_instance()
 }
 
 void
-App::dialog_open()
+App::dialog_open(string filename)
 {
-       string filename="*.sif";
+       if (filename.empty())
+               filename="*.sif";
 
        while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
        {
@@ -2045,7 +2515,8 @@ App::get_instance(etl::handle<synfig::Canvas> canvas)
 void
 App::dialog_about()
 {
-       (new class About())->show();
+       if(about)
+               about->show();
 }
 
 void