When studio fails to start up, show a more specific error message stating why.
[synfig.git] / synfig-studio / trunk / src / gtkmm / app.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file app.cpp
3 **      \brief writeme
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **      Copyright (c) 2007, 2008 Chris Moore
10 **      Copyright (c) 2008 Gerald Young
11 **  Copyright (c) 2008 Carlos López
12 **
13 **      This package is free software; you can redistribute it and/or
14 **      modify it under the terms of the GNU General Public License as
15 **      published by the Free Software Foundation; either version 2 of
16 **      the License, or (at your option) any later version.
17 **
18 **      This package is distributed in the hope that it will be useful,
19 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
20 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 **      General Public License for more details.
22 **      \endlegal
23 */
24 /* ========================================================================= */
25
26 /* === H E A D E R S ======================================================= */
27
28 #ifdef USING_PCH
29 #       include "pch.h"
30 #else
31 #ifdef HAVE_CONFIG_H
32 #       include <config.h>
33 #endif
34
35 #ifdef WIN32
36 #define WINVER 0x0500
37 #include <windows.h>
38 #endif
39
40 #include <fstream>
41 #include <iostream>
42 #include <locale>
43 #include <cstring>
44
45 #ifdef HAVE_SYS_ERRNO_H
46 #include <sys/errno.h>
47 #endif
48 #include <gtkmm/fileselection.h>
49 #include <gtkmm/dialog.h>
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/label.h>
52 #include <gtkmm/stock.h>
53 #include <gtkmm/stockitem.h>
54 #include <gtkmm/iconsource.h>
55 #include <gtkmm/inputdialog.h>
56 #include <gtkmm/accelmap.h>
57 #include <gtkmm/uimanager.h>
58 #include <gtkmm/textview.h>
59
60 #include <gtk/gtk.h>
61
62 #include <gdkmm/general.h>
63
64 #include <synfig/loadcanvas.h>
65 #include <synfig/savecanvas.h>
66
67 #include "app.h"
68 #include "about.h"
69 #include "splash.h"
70 #include "instance.h"
71 #include "canvasview.h"
72 #include "dialog_setup.h"
73 #include "dialog_gradient.h"
74 #include "dialog_color.h"
75 #include "toolbox.h"
76 #include "compview.h"
77 #include "onemoment.h"
78
79 #include "dockmanager.h"
80
81 #include "state_eyedrop.h"
82 #include "state_normal.h"
83 #include "state_draw.h"
84 #include "state_fill.h"
85 #include "state_bline.h"
86 #include "state_polygon.h"
87 #include "state_sketch.h"
88 #include "state_gradient.h"
89 #include "state_circle.h"
90 #include "state_rectangle.h"
91 #include "state_smoothmove.h"
92 #include "state_scale.h"
93 #include "state_star.h"
94 #include "state_text.h"
95 #include "state_width.h"
96 #include "state_rotate.h"
97 #include "state_zoom.h"
98
99 #include "devicetracker.h"
100 #include "dialog_tooloptions.h"
101 #include "widget_enum.h"
102
103 #include "autorecover.h"
104
105 #include <synfigapp/settings.h>
106 #include "dock_history.h"
107 #include "dock_canvases.h"
108 #include "dock_keyframes.h"
109 #include "dock_layers.h"
110 #include "dock_params.h"
111 #include "dock_metadata.h"
112 #include "dock_children.h"
113 #include "dock_info.h"
114 #include "dock_navigator.h"
115 #include "dock_layergroups.h"
116 #include "dock_timetrack.h"
117 #include "dock_curves.h"
118
119 #include "mod_palette/mod_palette.h"
120 #include "mod_mirror/mod_mirror.h"
121
122 #include <sys/stat.h>
123
124 #include "ipc.h"
125
126 #include "module.h"
127
128 #include "statemanager.h"
129
130 #ifdef WITH_FMOD
131 #include <fmod.h>
132 #endif
133
134 #include <gtkmm/accelmap.h>
135 #include <gtkmm/filechooser.h>
136 #include <gtkmm/filechooserdialog.h>
137
138 #include "general.h"
139
140 #endif
141
142 /* === U S I N G =========================================================== */
143
144 using namespace std;
145 using namespace etl;
146 using namespace synfig;
147 using namespace studio;
148
149 /* === M A C R O S ========================================================= */
150
151 #ifndef SYNFIG_USER_APP_DIR
152 #ifdef __APPLE__
153 #define SYNFIG_USER_APP_DIR     "Library/Synfig"
154 #elif defined(_WIN32)
155 #define SYNFIG_USER_APP_DIR     "Synfig"
156 #else
157 #define SYNFIG_USER_APP_DIR     ".synfig"
158 #endif
159 #endif
160
161 #ifndef DPM2DPI
162 #define DPM2DPI(x)      (float(x)/39.3700787402f)
163 #define DPI2DPM(x)      (float(x)*39.3700787402f)
164 #endif
165
166 #ifdef WIN32
167 #       ifdef IMAGE_DIR
168 #               undef IMAGE_DIR
169 #               define IMAGE_DIR "share\\pixmaps"
170 #       endif
171 #endif
172
173 #ifndef IMAGE_DIR
174 #       define IMAGE_DIR "/usr/local/share/pixmaps"
175 #endif
176
177 #ifndef IMAGE_EXT
178 #       define IMAGE_EXT        "tif"
179 #endif
180
181 #include <synfigapp/main.h>
182
183 /* === S I G N A L S ======================================================= */
184
185 static sigc::signal<void> signal_present_all_;
186 sigc::signal<void>&
187 App::signal_present_all() { return signal_present_all_; }
188
189 static sigc::signal<void> signal_recent_files_changed_;
190 sigc::signal<void>&
191 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
192
193 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
194 sigc::signal<void,etl::loose_handle<CanvasView> >&
195 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
196
197 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
198 sigc::signal<void,etl::handle<Instance> >&
199 App::signal_instance_selected() { return signal_instance_selected_; }
200
201 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
202 sigc::signal<void,etl::handle<Instance> >&
203 App::signal_instance_created() { return signal_instance_created_; }
204
205 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
206 sigc::signal<void,etl::handle<Instance> >&
207 App::signal_instance_deleted() { return signal_instance_deleted_; }
208
209 /* === G L O B A L S ======================================================= */
210
211 static std::list<std::string> recent_files;
212 const std::list<std::string>& App::get_recent_files() { return recent_files; }
213
214 static std::list<std::string> recent_files_window_size;
215
216 int     App::Busy::count;
217 bool App::shutdown_in_progress;
218
219 synfig::Gamma App::gamma;
220
221 Glib::RefPtr<studio::UIManager> App::ui_manager_;
222
223 synfig::Distance::System App::distance_system;
224
225 studio::Dialog_Setup* App::dialog_setup;
226
227 etl::handle< studio::ModPalette > mod_palette_;
228 //studio::Dialog_Palette* App::dialog_palette;
229
230 std::list<etl::handle<Instance> > App::instance_list;
231
232 static etl::handle<synfigapp::UIInterface> ui_interface_;
233 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
234
235 etl::handle<Instance> App::selected_instance;
236 etl::handle<CanvasView> App::selected_canvas_view;
237
238 studio::About *studio::App::about=NULL;
239
240 studio::Toolbox *studio::App::toolbox=NULL;
241
242 studio::AutoRecover *studio::App::auto_recover=NULL;
243
244 studio::IPC *ipc=NULL;
245
246 studio::DockManager* studio::App::dock_manager=0;
247
248 studio::DeviceTracker* studio::App::device_tracker=0;
249
250 studio::Dialog_Gradient* studio::App::dialog_gradient;
251
252 studio::Dialog_Color* studio::App::dialog_color;
253
254 Gtk::InputDialog* studio::App::dialog_input;
255
256 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
257
258 studio::Dock_History* dock_history;
259 studio::Dock_Canvases* dock_canvases;
260 studio::Dock_Keyframes* dock_keyframes;
261 studio::Dock_Layers* dock_layers;
262 studio::Dock_Params* dock_params;
263 studio::Dock_MetaData* dock_meta_data;
264 studio::Dock_Children* dock_children;
265 studio::Dock_Info* dock_info;
266 studio::Dock_LayerGroups* dock_layer_groups;
267 studio::Dock_Navigator* dock_navigator;
268 studio::Dock_Timetrack* dock_timetrack;
269 studio::Dock_Curves* dock_curves;
270
271 std::list< etl::handle< studio::Module > > module_list_;
272
273 bool studio::App::use_colorspace_gamma=true;
274 #ifdef SINGLE_THREADED
275 bool studio::App::single_threaded=false;
276 #endif
277 bool studio::App::restrict_radius_ducks=false;
278 String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
279 int studio::App::preferred_x_size=480;
280 int studio::App::preferred_y_size=270;
281 String studio::App::predefined_size(DEFAULT_PREDEFINED_SIZE);
282 #ifdef USE_OPEN_FOR_URLS
283 String studio::App::browser_command("open"); // MacOS only
284 #else
285 String studio::App::browser_command("xdg-open"); // Linux XDG standard
286 #endif
287
288 static int max_recent_files_=25;
289 int studio::App::get_max_recent_files() { return max_recent_files_; }
290 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
291
292 static synfig::String app_base_path_;
293
294 namespace studio {
295
296 bool
297 really_delete_widget(Gtk::Widget *widget)
298 {
299         // synfig::info("really delete %p", (void*)widget);
300         delete widget;
301         return false;
302 }
303
304 // nasty workaround - when we've finished with a popup menu, we want to delete it
305 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
306 // so schedule the real delete to happen in 50ms, giving the action a chance to run
307 void
308 delete_widget(Gtk::Widget *widget)
309 {
310         // synfig::info("delete %p", (void*)widget);
311         Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
312 }
313
314 }; // END of namespace studio
315 studio::StateManager* state_manager;
316
317
318
319
320 class GlobalUIInterface : public synfigapp::UIInterface
321 {
322 public:
323
324         virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
325         {
326                 Gtk::Dialog dialog(
327                         title,          // Title
328                         true,           // Modal
329                         true            // use_separator
330                 );
331                 Gtk::Label label(message);
332                 label.show();
333
334                 dialog.get_vbox()->pack_start(label);
335                 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
336                 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
337
338                 dialog.set_default_response(dflt);
339                 dialog.show();
340                 return (Response)dialog.run();
341         }
342         virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
343         {
344                 Gtk::Dialog dialog(
345                         title,          // Title
346                         true,           // Modal
347                         true            // use_separator
348                 );
349                 Gtk::Label label(message);
350                 label.show();
351
352                 dialog.get_vbox()->pack_start(label);
353                 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
354                 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
355                 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
356
357                 dialog.set_default_response(dflt);
358                 dialog.show();
359                 return (Response)dialog.run();
360         }
361         virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
362         {
363                 Gtk::Dialog dialog(
364                         title,          // Title
365                         true,           // Modal
366                         true            // use_separator
367                 );
368                 Gtk::Label label(message);
369                 label.show();
370
371                 dialog.get_vbox()->pack_start(label);
372                 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
373                 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
374
375                 dialog.set_default_response(dflt);
376                 dialog.show();
377                 return (Response)dialog.run();
378         }
379
380         virtual bool
381         task(const std::string &task)
382         {
383                 std::cerr<<task<<std::endl;
384                 while(studio::App::events_pending())studio::App::iteration(false);
385                 return true;
386         }
387
388         virtual bool
389         error(const std::string &err)
390         {
391                 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
392                 dialog.show();
393                 dialog.run();
394                 return true;
395         }
396
397         virtual bool
398         warning(const std::string &err)
399         {
400                 std::cerr<<"warning: "<<err<<std::endl;
401                 while(studio::App::events_pending())studio::App::iteration(false);
402                 return true;
403         }
404
405         virtual bool
406         amount_complete(int /*current*/, int /*total*/)
407         {
408                 while(studio::App::events_pending())studio::App::iteration(false);
409                 return true;
410         }
411 };
412
413 /* === P R O C E D U R E S ================================================= */
414
415 /*
416 void
417 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
418 {
419         action_group_list.push_back(action_group);
420         Gtk::UIManager::insert_action_group(action_group, pos);
421 }
422
423 void
424 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
425 {
426         std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
427         for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
428                 if(*iter==action_group)
429                 {
430                         action_group_list.erase(iter);
431                         Gtk::UIManager::remove_action_group(action_group);
432                         return;
433                 }
434         synfig::error("Unable to find action group");
435 }
436
437 void
438 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
439 {
440         ui_manager->insert_action_group(group,0);
441         return;
442         std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
443         std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
444
445         for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
446         {
447                 if(*iter && (*iter)->get_name()!="menus")
448                 {
449                         synfig::info("Removing action group "+(*iter)->get_name());
450                         ui_manager->remove_action_group(*iter);
451                 }
452         }
453         ui_manager->insert_action_group(group,0);
454
455         for(;!prev_groups.empty();prev_groups.pop_front())
456         {
457                 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
458                         ui_manager->insert_action_group(prev_groups.front(),1);
459         }
460 }
461 */
462 class Preferences : public synfigapp::Settings
463 {
464 public:
465         virtual bool get_value(const synfig::String& key, synfig::String& value)const
466         {
467                 if(key=="gamma")
468                 {
469                         value=strprintf("%f %f %f %f",
470                                 App::gamma.get_gamma_r(),
471                                 App::gamma.get_gamma_g(),
472                                 App::gamma.get_gamma_b(),
473                                 App::gamma.get_black_level()
474                         );
475                         return true;
476                 }
477                 if(key=="time_format")
478                 {
479                         value=strprintf("%i",App::get_time_format());
480                         return true;
481                 }
482                 if(key=="file_history.size")
483                 {
484                         value=strprintf("%i",App::get_max_recent_files());
485                         return true;
486                 }
487                 if(key=="use_colorspace_gamma")
488                 {
489                         value=strprintf("%i",(int)App::use_colorspace_gamma);
490                         return true;
491                 }
492                 if(key=="distance_system")
493                 {
494                         value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
495                         return true;
496                 }
497 #ifdef SINGLE_THREADED
498                 if(key=="single_threaded")
499                 {
500                         value=strprintf("%i",(int)App::single_threaded);
501                         return true;
502                 }
503 #endif
504                 if(key=="auto_recover_backup_interval")
505                 {
506                         value=strprintf("%i",App::auto_recover->get_timeout());
507                         return true;
508                 }
509                 if(key=="restrict_radius_ducks")
510                 {
511                         value=strprintf("%i",(int)App::restrict_radius_ducks);
512                         return true;
513                 }
514                 if(key=="browser_command")
515                 {
516                         value=App::browser_command;
517                         return true;
518                 }
519                 if(key=="custom_filename_prefix")
520                 {
521                         value=App::custom_filename_prefix;
522                         return true;
523                 }
524                 if(key=="preferred_x_size")
525                 {
526                         value=strprintf("%i",App::preferred_x_size);
527                         return true;
528                 }
529                 if(key=="preferred_y_size")
530                 {
531                         value=strprintf("%i",App::preferred_y_size);
532                         return true;
533                 }
534                 if(key=="predefined_size")
535                 {
536                         value=strprintf("%s",App::predefined_size.c_str());
537                         return true;
538                 }
539                 
540                 return synfigapp::Settings::get_value(key,value);
541         }
542
543         virtual bool set_value(const synfig::String& key,const synfig::String& value)
544         {
545                 if(key=="gamma")
546                 {
547                         float r,g,b,blk;
548
549                         strscanf(value,"%f %f %f %f",
550                                 &r,
551                                 &g,
552                                 &b,
553                                 &blk
554                         );
555
556                         App::gamma.set_all(r,g,b,blk);
557
558                         return true;
559                 }
560                 if(key=="time_format")
561                 {
562                         int i(atoi(value.c_str()));
563                         App::set_time_format(static_cast<synfig::Time::Format>(i));
564                         return true;
565                 }
566                 if(key=="auto_recover_backup_interval")
567                 {
568                         int i(atoi(value.c_str()));
569                         App::auto_recover->set_timeout(i);
570                         return true;
571                 }
572                 if(key=="file_history.size")
573                 {
574                         int i(atoi(value.c_str()));
575                         App::set_max_recent_files(i);
576                         return true;
577                 }
578                 if(key=="use_colorspace_gamma")
579                 {
580                         int i(atoi(value.c_str()));
581                         App::use_colorspace_gamma=i;
582                         return true;
583                 }
584                 if(key=="distance_system")
585                 {
586                         App::distance_system=Distance::ident_system(value);;
587                         return true;
588                 }
589 #ifdef SINGLE_THREADED
590                 if(key=="single_threaded")
591                 {
592                         int i(atoi(value.c_str()));
593                         App::single_threaded=i;
594                         return true;
595                 }
596 #endif
597                 if(key=="restrict_radius_ducks")
598                 {
599                         int i(atoi(value.c_str()));
600                         App::restrict_radius_ducks=i;
601                         return true;
602                 }
603                 if(key=="browser_command")
604                 {
605                         App::browser_command=value;
606                         return true;
607                 }
608                 if(key=="custom_filename_prefix")
609                 {
610                         App::custom_filename_prefix=value;
611                         return true;
612                 }
613                 if(key=="preferred_x_size")
614                 {
615                         int i(atoi(value.c_str()));
616                         App::preferred_x_size=i;
617                         return true;
618                 }
619                 if(key=="preferred_y_size")
620                 {
621                         int i(atoi(value.c_str()));
622                         App::preferred_y_size=i;
623                         return true;
624                 }
625                 if(key=="predefined_size")
626                 {
627                         App::predefined_size=value;
628                         return true;
629                 }
630                 return synfigapp::Settings::set_value(key,value);
631         }
632
633         virtual KeyList get_key_list()const
634         {
635                 KeyList ret(synfigapp::Settings::get_key_list());
636                 ret.push_back("gamma");
637                 ret.push_back("time_format");
638                 ret.push_back("distance_system");
639                 ret.push_back("file_history.size");
640                 ret.push_back("use_colorspace_gamma");
641 #ifdef SINGLE_THREADED
642                 ret.push_back("single_threaded");
643 #endif
644                 ret.push_back("auto_recover_backup_interval");
645                 ret.push_back("restrict_radius_ducks");
646                 ret.push_back("browser_command");
647                 ret.push_back("custom_filename_prefix");
648                 ret.push_back("preferred_x_size");
649                 ret.push_back("preferred_y_size");
650                 ret.push_back("predefined_size");               
651                 return ret;
652         }
653 };
654
655 static ::Preferences _preferences;
656
657 void
658 init_ui_manager()
659 {
660         Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
661
662         Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
663
664         Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
665
666         menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
667         menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
668         menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
669         menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
670         menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
671         menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
672         menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
673         menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
674         menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
675         menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
676         menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
677         menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
678         menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
679
680         // Add the synfigapp actions...
681         synfigapp::Action::Book::iterator iter;
682         for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
683         {
684                 actions_action_group->add(Gtk::Action::create(
685                         "action-"+iter->second.name,
686                         get_action_stock_id(iter->second),
687                         iter->second.local_name,iter->second.local_name
688                 ));
689         }
690
691 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
692 #define DEFINE_ACTION2(x,stock,label) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock,label,label) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
693 #define DEFINE_ACTION_SIG(group,x,stock,sig) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ group->add(action,sig); }
694
695         DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
696         DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
697         DEFINE_ACTION("new", Gtk::Stock::NEW);
698         DEFINE_ACTION("open", Gtk::Stock::OPEN);
699         DEFINE_ACTION("save", Gtk::Stock::SAVE);
700         DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
701         DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
702         DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
703         DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
704         DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
705         DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
706         DEFINE_ACTION("import", _("Import"));
707         DEFINE_ACTION("render", _("Render"));
708         DEFINE_ACTION("preview", _("Preview"));
709         DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
710         DEFINE_ACTION("sound", _("Sound File"));
711         DEFINE_ACTION("options", _("Options"));
712         DEFINE_ACTION("close", _("Close View"));
713         DEFINE_ACTION("close-document", _("Close Document"));
714         DEFINE_ACTION("quit", Gtk::Stock::QUIT);
715
716
717         DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
718         DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
719         DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
720         DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
721         DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
722         DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
723         DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
724         DEFINE_ACTION("select-all-layers", _("Select All Layers"));
725         DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
726         DEFINE_ACTION("properties", _("Properties"));
727
728         DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
729         DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
730         DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
731         DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
732         DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
733         DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
734         DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
735         DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
736         DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
737         DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
738         DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
739         DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
740         DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
741         DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
742         DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
743         DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
744         DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
745         for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
746                 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
747         DEFINE_ACTION("play", _("Play"));
748         // DEFINE_ACTION("pause", _("Pause"));
749         DEFINE_ACTION("stop", _("Stop"));
750         DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
751         DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
752         DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
753         DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
754         DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
755         DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
756         DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
757         DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
758         DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
759         DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
760         DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
761         DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
762         DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
763         DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
764         DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
765         DEFINE_ACTION("seek-next-frame", _("Next Frame"));
766         DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
767         DEFINE_ACTION("seek-next-second", _("Seek Forward"));
768         DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
769         DEFINE_ACTION("seek-begin", _("Seek to Begin"));
770         DEFINE_ACTION("seek-end", _("Seek to End"));
771
772         DEFINE_ACTION("action-group_add", _("Add group"));
773
774         DEFINE_ACTION("canvas-new", _("New Canvas"));
775
776         DEFINE_ACTION("amount-inc", _("Increase Amount"));
777         DEFINE_ACTION("amount-dec", _("Decrease Amount"));
778
779 #undef DEFINE_ACTION
780
781
782 // Set up synfigapp actions
783         /*{
784                 synfigapp::Action::Book::iterator iter;
785
786                 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
787                 {
788                         Gtk::StockID stock_id;
789
790                         if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
791                         {
792                                 //Gtk::Image* image(manage(new Gtk::Image()));
793                                 if(iter->second.task=="raise")                  stock_id=Gtk::Stock::GO_UP;
794                                 else if(iter->second.task=="lower")             stock_id=Gtk::Stock::GO_DOWN;
795                                 else if(iter->second.task=="move_top")  stock_id=Gtk::Stock::GOTO_TOP;
796                                 else if(iter->second.task=="move_bottom")       stock_id=Gtk::Stock::GOTO_BOTTOM;
797                                 else if(iter->second.task=="remove")    stock_id=Gtk::Stock::DELETE;
798                                 else if(iter->second.task=="set_on")    stock_id=Gtk::Stock::YES;
799                                 else if(iter->second.task=="set_off")   stock_id=Gtk::Stock::NO;
800                                 //else if(iter->second.task=="duplicate")       stock_id=Gtk::Stock::COPY;
801                                 else if(iter->second.task=="remove")    stock_id=Gtk::Stock::DELETE;
802                                 else                                                                    stock_id=Gtk::StockID("synfig-"+iter->second.task);
803
804                                 actions_action_group->add(Gtk::Action::create(
805                                         "action-"+iter->second.name,
806                                         stock_id,
807                                         iter->second.local_name,iter->second.local_name
808                                 ));
809                         }
810                 }
811         }
812 */
813
814
815     Glib::ustring ui_info =
816 "<ui>"
817 "       <popup name='menu-toolbox' action='menu-toolbox'>"
818 "       <menu action='menu-file'>"
819 "       </menu>"
820 "       </popup>"
821 "       <popup name='menu-main' action='menu-main'>"
822 "       <menu action='menu-file'>"
823 "               <menuitem action='new' />"
824 "               <menuitem action='open' />"
825 "               <menuitem action='save' />"
826 "               <menuitem action='save-as' />"
827 "               <menuitem action='revert' />"
828 "               <separator name='bleh01'/>"
829 "               <menuitem action='cvs-add' />"
830 "               <menuitem action='cvs-update' />"
831 "               <menuitem action='cvs-commit' />"
832 "               <menuitem action='cvs-revert' />"
833 "               <separator name='bleh02'/>"
834 "               <menuitem action='import' />"
835 "               <separator name='bleh03'/>"
836 "               <menuitem action='render' />"
837 "               <menuitem action='preview' />"
838 "               <menuitem action='sound' />"
839 "               <separator name='bleh04'/>"
840 "               <menuitem action='options' />"
841 "               <menuitem action='close' />"
842 "               <menuitem action='close-document' />"
843 "               <menuitem action='quit' />"
844 "       </menu>"
845 "       <menu action='menu-edit'>"
846 "               <menuitem action='undo'/>"
847 "               <menuitem action='redo'/>"
848 "               <separator name='bleh05'/>"
849 "               <menuitem action='cut'/>"
850 "               <menuitem action='copy'/>"
851 "               <menuitem action='paste'/>"
852 "               <separator name='bleh06'/>"
853 "               <menuitem action='select-all-layers'/>"
854 "               <menuitem action='unselect-all-layers'/>"
855 "               <menuitem action='select-all-ducks'/>"
856 "               <menuitem action='unselect-all-ducks'/>"
857 "               <separator name='bleh07'/>"
858 "               <menuitem action='properties'/>"
859 "       </menu>"
860 "       <menu action='menu-view'>"
861 "               <menu action='menu-duck-mask'>"
862 "                       <menuitem action='mask-position-ducks' />"
863 "                       <menuitem action='mask-vertex-ducks' />"
864 "                       <menuitem action='mask-tangent-ducks' />"
865 "                       <menuitem action='mask-radius-ducks' />"
866 "                       <menuitem action='mask-width-ducks' />"
867 "                       <menuitem action='mask-angle-ducks' />"
868 "               </menu>"
869 "               <menu action='menu-preview-quality'>"
870 "                       <menuitem action='quality-00' />"
871 "                       <menuitem action='quality-01' />"
872 "                       <menuitem action='quality-02' />"
873 "                       <menuitem action='quality-03' />"
874 "                       <menuitem action='quality-04' />"
875 "                       <menuitem action='quality-05' />"
876 "                       <menuitem action='quality-06' />"
877 "                       <menuitem action='quality-07' />"
878 "                       <menuitem action='quality-08' />"
879 "                       <menuitem action='quality-09' />"
880 "                       <menuitem action='quality-10' />"
881 "               </menu>"
882 "               <menu action='menu-lowres-pixel'>"
883 "               <menuitem action='decrease-low-res-pixel-size'/>"
884 "               <menuitem action='increase-low-res-pixel-size'/>"
885 "               <separator name='pixel-size-separator'/>"
886 ;
887
888         for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
889                 ui_info += strprintf("                  <menuitem action='lowres-pixel-%d' />", *iter);
890
891         ui_info +=
892 "               </menu>"
893 "               <separator name='bleh08'/>"
894 "               <menuitem action='play'/>"
895 //"             <menuitem action='pause'/>"
896 "               <menuitem action='stop'/>"
897 "               <menuitem action='dialog-flipbook'/>"
898 "               <separator name='bleh09'/>"
899 "               <menuitem action='toggle-grid-show'/>"
900 "               <menuitem action='toggle-grid-snap'/>"
901 "               <menuitem action='toggle-guide-show'/>"
902 "               <menuitem action='toggle-low-res'/>"
903 "               <menuitem action='toggle-onion-skin'/>"
904 "               <separator name='bleh10'/>"
905 "               <menuitem action='canvas-zoom-in'/>"
906 "               <menuitem action='canvas-zoom-out'/>"
907 "               <menuitem action='canvas-zoom-fit'/>"
908 "               <menuitem action='canvas-zoom-100'/>"
909 "               <separator name='bleh11'/>"
910 "               <menuitem action='time-zoom-in'/>"
911 "               <menuitem action='time-zoom-out'/>"
912 "               <separator name='bleh12'/>"
913 "               <menuitem action='jump-next-keyframe'/>"
914 "               <menuitem action='jump-prev-keyframe'/>"
915 "               <menuitem action='seek-next-frame'/>"
916 "               <menuitem action='seek-prev-frame'/>"
917 "               <menuitem action='seek-next-second'/>"
918 "               <menuitem action='seek-prev-second'/>"
919 "               <menuitem action='seek-begin'/>"
920 "               <menuitem action='seek-end'/>"
921 "       </menu>"
922 "       <menu action='menu-canvas'>"
923 "               <menuitem action='canvas-new'/>"
924 "       </menu>"
925 "       <menu name='menu-state' action='menu-state'>"
926 "       </menu>"
927 "       <menu action='menu-group'>"
928 "               <menuitem action='action-group_add'/>"
929 "       </menu>"
930 "       <menu action='menu-layer'>"
931 //"             <menuitem action='cut'/>"
932 //"             <menuitem action='copy'/>"
933 //"             <menuitem action='paste'/>"
934 //"             <separator name='bleh06'/>"
935 "               <menu action='menu-layer-new'></menu>"
936 "               <menuitem action='amount-inc'/>"
937 "               <menuitem action='amount-dec'/>"
938 "       </menu>"
939 "       <menu action='menu-keyframe'>"
940 "               <menuitem action='keyframe-properties'/>"
941 "       </menu>"
942 "       </popup>"
943
944 "</ui>"
945 ;
946 /*              "<ui>"
947         "  <menubar name='MenuBar'>"
948         "    <menu action='MenuFile'>"
949         "      <menuitem action='New'/>"
950         "      <menuitem action='Open'/>"
951         "      <separator/>"
952         "      <menuitem action='Quit'/>"
953         "    </menu>"
954         "    <menu action='MenuEdit'>"
955         "      <menuitem action='Cut'/>"
956         "      <menuitem action='Copy'/>"
957         "      <menuitem action='Paste'/>"
958         "    </menu>"
959         "  </menubar>"
960         "  <toolbar  name='ToolBar'>"
961         "    <toolitem action='Open'/>"
962         "    <toolitem action='Quit'/>"
963         "  </toolbar>"
964         "</ui>";
965 */
966         try
967         {
968                 actions_action_group->set_sensitive(false);
969                 App::ui_manager()->set_add_tearoffs(true);
970                 App::ui_manager()->insert_action_group(menus_action_group,1);
971                 App::ui_manager()->insert_action_group(actions_action_group,1);
972                 App::ui_manager()->add_ui_from_string(ui_info);
973
974                 //App::ui_manager()->get_accel_group()->unlock();
975         }
976         catch(const Glib::Error& ex)
977         {
978                 synfig::error("building menus and toolbars failed: " + ex.what());
979         }
980
981         // Add default keyboard accelerators
982 #define ACCEL(path,accel)                                               \
983         {                                                                                       \
984                 Gtk::AccelKey accel_key(accel,path);    \
985                 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod());       \
986         }
987
988 #define ACCEL2(accel)                                                   \
989         {                                                                                       \
990                 Gtk::AccelKey accel_key(accel);                 \
991                 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod());       \
992         }
993
994         ACCEL("<Actions>//select-all-ducks","<Control>a");
995         ACCEL("<Actions>//unselect-all-ducks","<Control>d");
996         ACCEL("<Actions>//select-all-layers","<Control><Shift>a");
997         ACCEL("<Actions>//unselect-all-layers","<Control><Shift>d");
998         ACCEL("<Actions>//render","F9");
999         ACCEL("<Actions>//preview","F11");
1000         ACCEL("<Actions>//properties","F8");
1001         ACCEL("<Actions>//options","F12");
1002         ACCEL("<Actions>//import","<control>i");
1003         ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
1004         ACCEL("<Actions>//toggle-grid-show","<Control>g");
1005         ACCEL("<Actions>//toggle-grid-snap","<Control>l");
1006         ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
1007         ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
1008         ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
1009         ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
1010         ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
1011         ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
1012         ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
1013
1014         ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
1015         ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
1016
1017         ACCEL("<Actions>//quality-01","<Control>1");
1018         ACCEL("<Actions>//quality-02","<Control>2");
1019         ACCEL("<Actions>//quality-03","<Control>3");
1020         ACCEL("<Actions>//quality-04","<Control>4");
1021         ACCEL("<Actions>//quality-05","<Control>5");
1022         ACCEL("<Actions>//quality-06","<Control>6");
1023         ACCEL("<Actions>//quality-07","<Control>7");
1024         ACCEL("<Actions>//quality-08","<Control>8");
1025         ACCEL("<Actions>//quality-09","<Control>9");
1026         ACCEL("<Actions>//quality-10","<Control>0");
1027         ACCEL("<Actions>//undo","<Control>z");
1028         ACCEL("<Actions>//redo","<Control>r");
1029         ACCEL("<Actions>//action-layer_remove","Delete");
1030
1031 /*      ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
1032         ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
1033         ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
1034         ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
1035         ACCEL("<Actions>//time-zoom-in","+");
1036         ACCEL("<Actions>//time-zoom-out","_");
1037 */
1038         ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
1039         ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
1040
1041         ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
1042         ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
1043
1044         ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
1045         ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
1046         ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
1047         ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
1048         ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
1049         ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
1050         ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
1051         ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
1052         ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
1053         ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
1054         ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
1055         ACCEL("<Actions>//play",              "<Control>p");
1056         ACCEL("<Actions>//seek-begin","Home");
1057         ACCEL("<Actions>//seek-end","End");
1058
1059         ACCEL("<Actions>//state-normal",      "<Mod1>a");
1060         ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1061         ACCEL("<Actions>//state-scale",       "<Mod1>s");
1062         ACCEL("<Actions>//state-rotate",      "<Mod1>t");
1063         ACCEL("<Actions>//state-mirror",      "<Mod1>m");
1064
1065         ACCEL("<Actions>//state-circle",      "<Mod1>c");
1066         ACCEL("<Actions>//state-rectangle",   "<Mod1>r");
1067         ACCEL("<Actions>//state-star",        "<Mod1>q");
1068         ACCEL("<Actions>//state-gradient",    "<Mod1>g");
1069         ACCEL("<Actions>//state-polygon",     "<Mod1>p");
1070
1071         ACCEL("<Actions>//state-bline",       "<Mod1>b");
1072         ACCEL("<Actions>//state-text",        "<Mod1>x");
1073         ACCEL("<Actions>//state-fill",        "<Mod1>f");
1074         ACCEL("<Actions>//state-eyedrop",     "<Mod1>e");
1075         ACCEL("<Actions>//state-zoom",        "<Mod1>z");
1076
1077         ACCEL("<Actions>//state-draw",        "<Mod1>d");
1078         ACCEL("<Actions>//state-sketch",      "<Mod1>k");
1079         ACCEL("<Actions>//state-width",       "<Mod1>w");
1080
1081         ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1082
1083 #undef ACCEL
1084 }
1085
1086 #ifdef _WIN32
1087 #define mkdir(x,y) mkdir(x)
1088 #endif
1089
1090 /* === M E T H O D S ======================================================= */
1091
1092 App::App(int *argc, char ***argv):
1093         Gtk::Main(argc,argv),
1094         IconController(etl::dirname((*argv)[0]))
1095 {
1096         app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1097
1098
1099         ui_interface_=new GlobalUIInterface();
1100
1101         gdk_rgb_init();
1102
1103         // don't call thread_init() if threads are already initialized
1104         // on some machines bonobo_init() initialized threads before we get here
1105         if (!g_thread_supported())
1106                 Glib::thread_init();
1107
1108         distance_system=Distance::SYSTEM_UNITS;
1109
1110         if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1111         {
1112                 if(errno!=EEXIST)
1113                         synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1114         }
1115         else
1116         {
1117                 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1118         }
1119
1120
1121         ipc=new IPC();
1122
1123         if(!SYNFIG_CHECK_VERSION())
1124         {
1125                 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1126                 dialog_error_blocking("Synfig Studio",
1127                         "This copy of Synfig Studio was compiled against a\n"
1128                         "different version of libsynfig than what is currently\n"
1129                         "installed. Synfig Studio will now abort. Try downloading\n"
1130                         "the latest version from the Synfig website at\n"
1131                         "http://synfig.org/Download"
1132                 );
1133                 throw 40;
1134         }
1135         Glib::set_application_name(_("Synfig Studio"));
1136
1137         Splash splash_screen;
1138         splash_screen.show();
1139
1140         shutdown_in_progress=false;
1141         SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1142         SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1143
1144         // Initialize the Synfig library
1145         try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1146         catch(std::runtime_error x)
1147         {
1148                 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1149                 throw;
1150         }
1151         catch(...)
1152         {
1153                 get_ui_interface()->error(_("Failed to initialize synfig!"));
1154                 throw;
1155         }
1156
1157         // add the preferences to the settings
1158         synfigapp::Main::settings().add_domain(&_preferences,"pref");
1159
1160         try
1161         {
1162                 studio_init_cb.task(_("Init UI Manager..."));
1163                 App::ui_manager_=studio::UIManager::create();
1164                 init_ui_manager();
1165
1166                 studio_init_cb.task(_("Init Dock Manager..."));
1167                 dock_manager=new studio::DockManager();
1168
1169                 studio_init_cb.task(_("Init State Manager..."));
1170                 state_manager=new StateManager();
1171
1172                 studio_init_cb.task(_("Init Toolbox..."));
1173                 toolbox=new studio::Toolbox();
1174
1175                 studio_init_cb.task(_("Init About Dialog..."));
1176                 about=new studio::About();
1177
1178                 studio_init_cb.task(_("Init Tool Options..."));
1179                 dialog_tool_options=new studio::Dialog_ToolOptions();
1180                 dock_manager->register_dockable(*dialog_tool_options);
1181
1182                 studio_init_cb.task(_("Init History..."));
1183                 dock_history=new studio::Dock_History();
1184                 dock_manager->register_dockable(*dock_history);
1185
1186                 studio_init_cb.task(_("Init Canvases..."));
1187                 dock_canvases=new studio::Dock_Canvases();
1188                 dock_manager->register_dockable(*dock_canvases);
1189
1190                 studio_init_cb.task(_("Init Keyframes..."));
1191                 dock_keyframes=new studio::Dock_Keyframes();
1192                 dock_manager->register_dockable(*dock_keyframes);
1193
1194                 studio_init_cb.task(_("Init Layers..."));
1195                 dock_layers=new studio::Dock_Layers();
1196                 dock_manager->register_dockable(*dock_layers);
1197
1198                 studio_init_cb.task(_("Init Params..."));
1199                 dock_params=new studio::Dock_Params();
1200                 dock_manager->register_dockable(*dock_params);
1201
1202                 studio_init_cb.task(_("Init MetaData..."));
1203                 dock_meta_data=new studio::Dock_MetaData();
1204                 dock_manager->register_dockable(*dock_meta_data);
1205
1206                 studio_init_cb.task(_("Init Children..."));
1207                 dock_children=new studio::Dock_Children();
1208                 dock_manager->register_dockable(*dock_children);
1209
1210                 studio_init_cb.task(_("Init Info..."));
1211                 dock_info = new studio::Dock_Info();
1212                 dock_manager->register_dockable(*dock_info);
1213
1214                 studio_init_cb.task(_("Init Navigator..."));
1215                 dock_navigator = new studio::Dock_Navigator();
1216                 dock_manager->register_dockable(*dock_navigator);
1217
1218                 studio_init_cb.task(_("Init Timetrack..."));
1219                 dock_timetrack = new studio::Dock_Timetrack();
1220                 dock_manager->register_dockable(*dock_timetrack);
1221
1222                 studio_init_cb.task(_("Init Curve Editor..."));
1223                 dock_curves = new studio::Dock_Curves();
1224                 dock_manager->register_dockable(*dock_curves);
1225
1226                 studio_init_cb.task(_("Init Layer Groups..."));
1227                 dock_layer_groups = new studio::Dock_LayerGroups();
1228                 dock_manager->register_dockable(*dock_layer_groups);
1229
1230
1231                 studio_init_cb.task(_("Init Color Dialog..."));
1232                 dialog_color=new studio::Dialog_Color();
1233
1234                 studio_init_cb.task(_("Init Gradient Dialog..."));
1235                 dialog_gradient=new studio::Dialog_Gradient();
1236
1237                 studio_init_cb.task(_("Init DeviceTracker..."));
1238                 device_tracker=new studio::DeviceTracker();
1239
1240                 studio_init_cb.task(_("Init Tools..."));
1241
1242                 /* row 1 */
1243                 state_manager->add_state(&state_normal);
1244                 state_manager->add_state(&state_smooth_move);
1245                 state_manager->add_state(&state_scale);
1246                 state_manager->add_state(&state_rotate);
1247                 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1248
1249                 /* row 2 */
1250                 state_manager->add_state(&state_circle);
1251                 state_manager->add_state(&state_rectangle);
1252                 state_manager->add_state(&state_star);
1253                 state_manager->add_state(&state_gradient);
1254                 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1255
1256                 /* row 3 */
1257                 state_manager->add_state(&state_bline);
1258                 state_manager->add_state(&state_text);
1259                 state_manager->add_state(&state_fill);
1260                 state_manager->add_state(&state_eyedrop);
1261                 state_manager->add_state(&state_zoom);
1262
1263                 if(!getenv("SYNFIG_DISABLE_DRAW"   )) state_manager->add_state(&state_draw); // Enabled for now.  Let's see whether they're good enough yet.
1264                 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1265                 if(!getenv("SYNFIG_DISABLE_WIDTH"  )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1266
1267                 studio_init_cb.task(_("Init ModPalette..."));
1268                 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1269
1270                 studio_init_cb.task(_("Init Setup Dialog..."));
1271                 dialog_setup=new studio::Dialog_Setup();
1272
1273                 studio_init_cb.task(_("Init Input Dialog..."));
1274                 dialog_input=new Gtk::InputDialog();
1275                 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1276                 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1277
1278                 studio_init_cb.task(_("Init auto recovery..."));
1279                 auto_recover=new AutoRecover();
1280
1281                 studio_init_cb.amount_complete(9250,10000);
1282                 studio_init_cb.task(_("Loading Settings..."));
1283                 load_settings();
1284                 studio_init_cb.task(_("Checking auto-recover..."));
1285
1286                 studio_init_cb.amount_complete(9900,10000);
1287
1288                 bool opened_any = false;
1289                 if(auto_recover->recovery_needed())
1290                 {
1291                         splash_screen.hide();
1292                         if (get_ui_interface()->yes_no(_("Auto Recovery"),
1293                                                                                    _("Synfig Studio seems to have crashed\n"
1294                                                                                          "before you could save all your files.\n"
1295                                                                                          "Would you like to re-open those files\n"
1296                                                                                          "and recover your unsaved changes?")) ==
1297                                 synfigapp::UIInterface::RESPONSE_YES)
1298                         {
1299                                 int number_recovered;
1300                                 if(!auto_recover->recover(number_recovered))
1301                                         if (number_recovered)
1302                                                 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1303                                         else
1304                                                 get_ui_interface()->error(_("Unable to recover from previous crash"));
1305                                 else
1306                                         get_ui_interface()->error(
1307                                                 _("Synfig Studio has attempted to recover\n"
1308                                                   "from a previous crash. The files that it has\n"
1309                                                   "recovered are NOT YET SAVED. It would be a good\n"
1310                                                   "idea to review them and save them now."));
1311
1312                                 if (number_recovered)
1313                                         opened_any = true;
1314                         }
1315                         splash_screen.show();
1316                 }
1317
1318                 // Look for any files given on the command line,
1319                 // and load them if found.
1320                 for(;*argc>=1;(*argc)--)
1321                         if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1322                         {
1323                                 studio_init_cb.task(_("Loading files..."));
1324                                 splash_screen.hide();
1325                                 open((*argv)[*argc]);
1326                                 opened_any = true;
1327                                 splash_screen.show();
1328                         }
1329
1330                 // if no file was specified to be opened, create a new document to help new users get started more easily
1331                 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1332                         new_instance();
1333
1334                 studio_init_cb.task(_("Done."));
1335                 studio_init_cb.amount_complete(10000,10000);
1336
1337                 toolbox->present();
1338         }
1339         catch(String x)
1340         {
1341                 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1342         }
1343         catch(...)
1344         {
1345                 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1346         }
1347 }
1348
1349 StateManager* App::get_state_manager() { return state_manager; }
1350
1351 App::~App()
1352 {
1353         shutdown_in_progress=true;
1354
1355         save_settings();
1356
1357         synfigapp::Main::settings().remove_domain("pref");
1358
1359         selected_instance=0;
1360
1361         // Unload all of the modules
1362         for(;!module_list_.empty();module_list_.pop_back())
1363                 ;
1364
1365         delete state_manager;
1366
1367         delete ipc;
1368
1369         delete auto_recover;
1370
1371         delete about;
1372         
1373         toolbox->hide();
1374
1375 //      studio::App::iteration(false);
1376
1377         delete toolbox;
1378
1379 //      studio::App::iteration(false);
1380
1381 //      studio::App::iteration(false);
1382
1383         delete dialog_setup;
1384
1385         delete dialog_gradient;
1386
1387         delete dialog_color;
1388
1389         delete dialog_input;
1390
1391         delete dock_manager;
1392
1393         instance_list.clear();
1394
1395 //      studio::App::iteration(false);
1396 }
1397
1398 String
1399 App::get_user_app_directory()
1400 {
1401 //! \todo do we need locale_from_utf8() on non-Windows boxes too?  (bug #1837445)
1402 #ifdef WIN32
1403         return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1404 #else
1405         return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1406 #endif
1407 }
1408
1409 synfig::String
1410 App::get_config_file(const synfig::String& file)
1411 {
1412         return Glib::build_filename(get_user_app_directory(),file);
1413 }
1414
1415 #define SCALE_FACTOR    (1280)
1416 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1417 void
1418 App::set_recent_file_window_size(etl::handle<Instance> instance)
1419 {
1420         int screen_w(Gdk::screen_width());
1421         int screen_h(Gdk::screen_height());
1422
1423         const std::string &canvas_window_size = *recent_files_window_size.begin();
1424
1425         if(canvas_window_size.empty())
1426                 return;
1427
1428         synfig::String::size_type current=0;
1429         bool seen_root(false), shown_non_root(false);
1430
1431         while(current != synfig::String::npos)
1432         {
1433                 // find end of first field (canvas) or return
1434                 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1435                 if(separator == synfig::String::npos) break;
1436
1437                 // find the canvas
1438                 synfig::Canvas::Handle canvas;
1439                 try {
1440                         canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current));
1441                 }
1442                 catch(Exception::IDNotFound) {
1443                         // can't find the canvas; skip to the next canvas or return
1444                         separator = canvas_window_size.find_first_of('\t', current);
1445                         if(separator == synfig::String::npos) return;
1446                         current = separator+1;
1447                         continue;
1448                 }
1449
1450                 if (canvas->is_root())
1451                         seen_root = true;
1452                 else
1453                         shown_non_root = true;
1454
1455                 // check that we have the tab character the ends this canvas' data or return
1456                 current = separator+1;
1457                 separator = canvas_window_size.find_first_of('\t', current);
1458                 if(separator == synfig::String::npos) return;
1459
1460                 int x,y,w,h;
1461                 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1462                 {
1463                         current = separator+1;
1464                         continue;
1465                 }
1466
1467                 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1468                 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1469                 x=x*screen_w/SCALE_FACTOR;
1470                 y=y*screen_h/SCALE_FACTOR;
1471                 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1472                         x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1473                 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1474                         y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1475
1476                 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1477                 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1478
1479                 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1480                 canvasview->move(x,y);
1481                 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1482                 canvasview->present();
1483
1484                 current = separator+1;
1485         }
1486
1487         if (shown_non_root && !seen_root)
1488                 instance->find_canvas_view(instance->get_canvas())->hide();
1489 }
1490
1491 void
1492 App::add_recent_file(const etl::handle<Instance> instance)
1493 {
1494         int screen_w(Gdk::screen_width());
1495         int screen_h(Gdk::screen_height());
1496
1497         std::string canvas_window_size;
1498
1499         const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1500         Instance::CanvasViewList::const_iterator iter;
1501
1502         for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1503         {
1504                 if( !((*iter)->is_visible()) )
1505                         continue;
1506
1507                 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1508                 int x_pos, y_pos, x_size, y_size;
1509                 (*iter)->get_position(x_pos,y_pos);
1510                 (*iter)->get_size(x_size,y_size);
1511
1512                 canvas_window_size += strprintf("%s %d %d %d %d\t",
1513                                                                                 canvas->get_relative_id(canvas->get_root()).c_str(),
1514                                                                                 x_pos*SCALE_FACTOR/screen_w,  y_pos*SCALE_FACTOR/screen_h,
1515                                                                                 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1516         }
1517
1518         add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1519 }
1520 #undef SCALE_FACTOR
1521
1522 void
1523 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1524 {
1525         std::string filename(file_name);
1526
1527         assert(!filename.empty());
1528
1529         if(filename.empty())
1530                 return;
1531
1532         // Toss out any "hidden" files
1533         if(basename(filename)[0]=='.')
1534                 return;
1535
1536         // If we aren't an absolute path, turn ourselves into one
1537         if(!is_absolute_path(filename))
1538                 filename=absolute_path(filename);
1539
1540         std::string old_window_size;
1541
1542         list<string>::iterator iter;
1543         list<string>::iterator iter_wsize;
1544         // Check to see if the file is already on the list.
1545         // If it is, then remove it from the list
1546         for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1547                 if(*iter==filename)
1548                 {
1549                         recent_files.erase(iter);
1550                         old_window_size = *iter_wsize;
1551                         recent_files_window_size.erase(iter_wsize);
1552                         break;
1553                 }
1554
1555
1556         // Push the filename to the front of the list
1557         recent_files.push_front(filename);
1558         if(window_size.empty())
1559                 recent_files_window_size.push_front(old_window_size);
1560         else
1561                 recent_files_window_size.push_front(window_size);
1562
1563         // Clean out the files at the end of the list.
1564         while(recent_files.size()>(unsigned)get_max_recent_files())
1565         {
1566                 recent_files.pop_back();
1567                 recent_files_window_size.pop_back();
1568         }
1569
1570         signal_recent_files_changed_();
1571
1572         return;
1573 }
1574
1575 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1576
1577 Time::Format
1578 App::get_time_format()
1579 {
1580         return _App_time_format;
1581 }
1582
1583 void
1584 App::set_time_format(synfig::Time::Format x)
1585 {
1586         _App_time_format=x;
1587 }
1588
1589
1590 void
1591 App::save_settings()
1592 {
1593         char * old_locale;
1594         try
1595         {
1596         old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1597         setlocale(LC_NUMERIC, "C");
1598                 {
1599                         std::string filename=get_config_file("accelrc");
1600                         Gtk::AccelMap::save(filename);
1601                 }
1602                 do{
1603                         std::string filename=get_config_file("recentfiles");
1604
1605                         std::ofstream file(filename.c_str());
1606
1607                         if(!file)
1608                         {
1609                                 synfig::warning("Unable to save %s",filename.c_str());
1610                                 break;
1611                         }
1612
1613                         list<string>::reverse_iterator iter;
1614
1615                         for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1616                                 file<<*iter<<endl;
1617                 }while(0);
1618                 do{
1619                         std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1620
1621                         std::ofstream file(filename.c_str());
1622
1623                         if(!file)
1624                         {
1625                                 synfig::warning("Unable to save %s",filename.c_str());
1626                                 break;
1627                         }
1628
1629                         list<string>::reverse_iterator iter;
1630
1631                         for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1632                                 file<<*iter<<endl;
1633
1634                 }while(0);
1635                 std::string filename=get_config_file("settings");
1636                 synfigapp::Main::settings().save_to_file(filename);
1637         setlocale(LC_NUMERIC,old_locale);
1638         }
1639         catch(...)
1640         {
1641                 synfig::warning("Caught exception when attempting to save settings.");
1642         }
1643 }
1644
1645 void
1646 App::load_settings()
1647 {
1648         char  * old_locale;
1649         try
1650         {
1651         old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1652         setlocale(LC_NUMERIC, "C");
1653                 {
1654                         std::string filename=get_config_file("accelrc");
1655                         Gtk::AccelMap::load(filename);
1656                 }
1657                 {
1658                         bool window_size_broken = false;
1659
1660                         std::string filename=get_config_file("recentfiles");
1661                         std::string filename_window_size=filename+std::string("_window_size");
1662
1663                         std::ifstream file(filename.c_str());
1664                         std::ifstream file_window_size(filename_window_size.c_str());
1665
1666                         if(!file_window_size)
1667                                 window_size_broken = true;
1668
1669                         while(file)
1670                         {
1671                                 std::string recent_file;
1672                                 std::string recent_file_window_size;
1673                                 getline(file,recent_file);
1674                                 if(!window_size_broken)
1675                                         getline(file_window_size,recent_file_window_size);
1676                                 if(!recent_file.empty())
1677                                 {
1678                                         if(!window_size_broken && !file_window_size)
1679                                                 window_size_broken = true;
1680                                         if (std::ifstream(recent_file.c_str()))
1681                                         {
1682                                                 if(!window_size_broken)
1683                                                         add_recent_file(recent_file,recent_file_window_size);
1684                                                 else
1685                                                         add_recent_file(recent_file);
1686                                         }
1687                                 }
1688                         }
1689                         if(!window_size_broken && file_window_size)
1690                                 window_size_broken = true;
1691
1692                         if(window_size_broken)
1693                         {
1694                                 recent_files_window_size.clear();
1695                                 recent_files_window_size.resize(recent_files.size());
1696                         }
1697                 }
1698                 std::string filename=get_config_file("settings");
1699                 if(!synfigapp::Main::settings().load_from_file(filename))
1700                 {
1701                         //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1702                         //if(!synfigapp::Main::settings().load_from_file(filename))
1703                         {
1704                                 gamma.set_gamma(1.0/2.2);
1705                                 reset_initial_window_configuration();
1706                         }
1707                 }
1708         setlocale(LC_NUMERIC,old_locale);
1709         }
1710         catch(...)
1711         {
1712                 synfig::warning("Caught exception when attempting to load settings.");
1713         }
1714 }
1715
1716 void
1717 App::reset_initial_window_configuration()
1718 {
1719         synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1720         synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1721         synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1722         synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1723         synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1724         synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1725         synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1726         synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1727         synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1728         synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1729         synfigapp::Main::settings().set_value("pref.distance_system","pt");
1730         synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1731 #ifdef SINGLE_THREADED
1732         synfigapp::Main::settings().set_value("pref.single_threaded","0");
1733 #endif
1734         synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1735         synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1736         synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1737         synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1738         synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1739         synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1740 }
1741
1742 bool
1743 App::shutdown_request(GdkEventAny*)
1744 {
1745         quit();
1746         return true;
1747         //return !shutdown_in_progress;
1748 }
1749
1750 void
1751 App::quit()
1752 {
1753         if(shutdown_in_progress)return;
1754
1755
1756         get_ui_interface()->task(_("Quit Request"));
1757         if(Busy::count)
1758         {
1759                 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1760                 return;
1761         }
1762
1763         std::list<etl::handle<Instance> >::iterator iter;
1764         for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1765         {
1766                 if(!(*iter)->safe_close())
1767                         return;
1768
1769 /*
1770                 if((*iter)->synfigapp::Instance::get_action_count())
1771                 {
1772                         handle<synfigapp::UIInterface> uim;
1773                         uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1774                         assert(uim);
1775                         string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1776                         switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1777                         {
1778                                 case synfigapp::UIInterface::RESPONSE_NO:
1779                                         break;
1780                                 case synfigapp::UIInterface::RESPONSE_YES:
1781                                         (*iter)->save();
1782                                         break;
1783                                 case synfigapp::UIInterface::RESPONSE_CANCEL:
1784                                         return;
1785                                 default:
1786                                         assert(0);
1787                                         return;
1788                         }
1789                 }
1790
1791
1792                 if((*iter)->synfigapp::Instance::is_modified())
1793                 {
1794                         handle<synfigapp::UIInterface> uim;
1795                         uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1796                         assert(uim);
1797                         string str=strprintf(_("%s has changes not yet on the CVS repository.\nWould you like to commit these changes?"),(*iter)->get_file_name().c_str() );
1798                         switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1799                         {
1800                                 case synfigapp::UIInterface::RESPONSE_NO:
1801                                         break;
1802                                 case synfigapp::UIInterface::RESPONSE_YES:
1803                                         (*iter)->dialog_cvs_commit();
1804                                         break;
1805                                 case synfigapp::UIInterface::RESPONSE_CANCEL:
1806                                         return;
1807                                 default:
1808                                         assert(0);
1809                                         return;
1810                         }
1811                 }
1812 */
1813
1814                 // This next line causes things to crash for some reason
1815                 //(*iter)->close();
1816         }
1817
1818         shutdown_in_progress=true;
1819
1820         instance_list.clear();
1821
1822         while(studio::App::events_pending())studio::App::iteration(false);
1823
1824         Gtk::Main::quit();
1825         auto_recover->normal_shutdown();
1826
1827         get_ui_interface()->task(_("Quit Request sent"));
1828 }
1829
1830 void
1831 App::show_setup()
1832 {
1833         dialog_setup->refresh();
1834         dialog_setup->show();
1835 }
1836
1837 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1838 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1839
1840 //#ifdef WIN32
1841 //#define USE_WIN32_FILE_DIALOGS 1
1842 //#endif
1843
1844 #ifdef USE_WIN32_FILE_DIALOGS
1845 static OPENFILENAME ofn={};
1846 #endif
1847
1848 #ifdef WIN32
1849 #include <gdk/gdkwin32.h>
1850 #endif
1851
1852 bool
1853 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1854 {
1855         // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1856
1857 #ifdef USE_WIN32_FILE_DIALOGS
1858         static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1859
1860         GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1861         HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1862         HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1863
1864         ofn.lStructSize=sizeof(OPENFILENAME);
1865         ofn.hwndOwner = hWnd;
1866         ofn.hInstance = hInstance;
1867         ofn.lpstrFilter = szFilter;
1868 //      ofn.lpstrCustomFilter=NULL;
1869 //      ofn.nMaxCustFilter=0;
1870 //      ofn.nFilterIndex=0;
1871 //      ofn.lpstrFile=NULL;
1872         ofn.nMaxFile=MAX_PATH;
1873 //      ofn.lpstrFileTitle=NULL;
1874 //      ofn.lpstrInitialDir=NULL;
1875 //      ofn.lpstrTitle=NULL;
1876         ofn.Flags=OFN_HIDEREADONLY;
1877 //      ofn.nFileOffset=0;
1878 //      ofn.nFileExtension=0;
1879         ofn.lpstrDefExt=TEXT("sif");
1880 //      ofn.lCustData = 0l;
1881         ofn.lpfnHook=NULL;
1882 //      ofn.lpTemplateName=NULL;
1883
1884         CHAR szFilename[MAX_PATH];
1885         CHAR szTitle[500];
1886         strcpy(szFilename,filename.c_str());
1887         strcpy(szTitle,title.c_str());
1888
1889         ofn.lpstrFile=szFilename;
1890         ofn.lpstrFileTitle=szTitle;
1891
1892         if(GetOpenFileName(&ofn))
1893         {
1894                 filename=szFilename;
1895                 return true;
1896         }
1897         return false;
1898
1899 #else
1900         synfig::String prev_path;
1901
1902         if(!_preferences.get_value(preference, prev_path))
1903                 prev_path = ".";
1904
1905         prev_path = absolute_path(prev_path);
1906
1907     Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1908
1909     dialog->set_current_folder(prev_path);
1910     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1911     dialog->add_button(Gtk::Stock::OPEN,   Gtk::RESPONSE_ACCEPT);
1912
1913     if (filename.empty())
1914                 dialog->set_filename(prev_path);
1915         else if (is_absolute_path(filename))
1916                 dialog->set_filename(filename);
1917         else
1918                 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1919
1920     if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1921         filename = dialog->get_filename();
1922                 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1923                 _preferences.set_value(preference, dirname(filename));
1924         delete dialog;
1925         return true;
1926     }
1927
1928     delete dialog;
1929     return false;
1930
1931     /*
1932
1933         GtkWidget *ok;
1934         GtkWidget *cancel;
1935         int val=0;
1936
1937         GtkWidget *fileselection;
1938         fileselection = gtk_file_selection_new(title.c_str());
1939
1940
1941         if(basename(filename)==filename)
1942         {
1943                 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1944         }
1945         else
1946                 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1947
1948         gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1949
1950         ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1951         cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1952
1953         gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1954         gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1955
1956         gtk_widget_show(fileselection);
1957
1958         while(!val)
1959                 iteration();
1960
1961
1962         if(val==1)
1963         {
1964                 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1965                 _preferences.set_value(preference,dirname(filename));
1966         }
1967         else
1968         {
1969                 gtk_widget_destroy(fileselection);
1970                 return false;
1971         }
1972         gtk_widget_destroy(fileselection);
1973         return true;
1974     */
1975 #endif
1976 }
1977
1978 bool
1979 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1980 {
1981         // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1982
1983 #if USE_WIN32_FILE_DIALOGS
1984         static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1985
1986         GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1987         HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1988         HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1989
1990         ofn.lStructSize=sizeof(OPENFILENAME);
1991         ofn.hwndOwner = hWnd;
1992         ofn.hInstance = hInstance;
1993         ofn.lpstrFilter = szFilter;
1994 //      ofn.lpstrCustomFilter=NULL;
1995 //      ofn.nMaxCustFilter=0;
1996 //      ofn.nFilterIndex=0;
1997 //      ofn.lpstrFile=NULL;
1998         ofn.nMaxFile=MAX_PATH;
1999 //      ofn.lpstrFileTitle=NULL;
2000 //      ofn.lpstrInitialDir=NULL;
2001 //      ofn.lpstrTitle=NULL;
2002         ofn.Flags=OFN_OVERWRITEPROMPT;
2003 //      ofn.nFileOffset=0;
2004 //      ofn.nFileExtension=0;
2005         ofn.lpstrDefExt=TEXT("sif");
2006 //      ofn.lCustData = 0l;
2007         ofn.lpfnHook=NULL;
2008 //      ofn.lpTemplateName=NULL;
2009
2010         CHAR szFilename[MAX_PATH];
2011         CHAR szTitle[500];
2012         strcpy(szFilename,filename.c_str());
2013         strcpy(szTitle,title.c_str());
2014
2015         ofn.lpstrFile=szFilename;
2016         ofn.lpstrFileTitle=szTitle;
2017
2018         if(GetSaveFileName(&ofn))
2019         {
2020                 filename=szFilename;
2021                 _preferences.set_value(preference,dirname(filename));
2022                 return true;
2023         }
2024         return false;
2025 #else
2026         synfig::String prev_path;
2027
2028         if(!_preferences.get_value(preference, prev_path))
2029                 prev_path=".";
2030
2031         prev_path = absolute_path(prev_path);
2032
2033     Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2034
2035     dialog->set_current_folder(prev_path);
2036     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2037     dialog->add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_ACCEPT);
2038
2039         Widget_Enum *file_type_enum = 0;
2040         if (preference == ANIMATION_DIR_PREFERENCE)
2041         {
2042                 file_type_enum = manage(new Widget_Enum());
2043                 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2044                                                                            .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2045                                                                            .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2046                                                                            .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2047                                                                            .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2048                 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2049
2050                 Gtk::HBox *hbox = manage(new Gtk::HBox);
2051                 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2052                 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2053                 hbox->show_all();
2054
2055                 dialog->set_extra_widget(*hbox);
2056         }
2057
2058     if (filename.empty())
2059                 dialog->set_filename(prev_path);
2060     else
2061         {
2062                 std::string full_path;
2063                 if (is_absolute_path(filename))
2064                         full_path = filename;
2065                 else
2066                         full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2067
2068                 // select the file if it exists
2069                 dialog->set_filename(full_path);
2070
2071                 // if the file doesn't exist, put its name into the filename box
2072                 struct stat s;
2073                 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2074                         dialog->set_current_name(basename(filename));
2075         }
2076
2077     if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2078                 if (preference == ANIMATION_DIR_PREFERENCE)
2079                         set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2080         filename = dialog->get_filename();
2081                 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2082                 _preferences.set_value(preference, dirname(filename));
2083         delete dialog;
2084         return true;
2085     }
2086
2087     delete dialog;
2088     return false;
2089 #endif
2090 }
2091
2092 void
2093 App::dialog_error_blocking(const std::string &title, const std::string &message)
2094 {
2095         Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2096         dialog.set_title(title);
2097         dialog.show();
2098         dialog.run();
2099 }
2100
2101 void
2102 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2103 {
2104         Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2105         dialog.set_title(title);
2106         dialog.show();
2107         dialog.run();
2108 }
2109
2110 bool
2111 App::dialog_yes_no(const std::string &title, const std::string &message)
2112 {
2113         Gtk::Dialog dialog(
2114                 title,          // Title
2115                 true,           // Modal
2116                 true            // use_separator
2117         );
2118         Gtk::Label label(message);
2119         label.show();
2120
2121         dialog.get_vbox()->pack_start(label);
2122         dialog.add_button(Gtk::StockID("gtk-yes"),1);
2123         dialog.add_button(Gtk::StockID("gtk-no"),0);
2124         dialog.show();
2125         return dialog.run();
2126 }
2127
2128 int
2129 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2130 {
2131         Gtk::Dialog dialog(
2132                 title,          // Title
2133                 true,           // Modal
2134                 true            // use_separator
2135         );
2136         Gtk::Label label(message);
2137         label.show();
2138
2139         dialog.get_vbox()->pack_start(label);
2140         dialog.add_button(Gtk::StockID("gtk-yes"),1);
2141         dialog.add_button(Gtk::StockID("gtk-no"),0);
2142         dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2143         dialog.show();
2144         return dialog.run();
2145 }
2146
2147 void
2148 App::dialog_not_implemented()
2149 {
2150         Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2151         dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2152         dialog.run();
2153 }
2154
2155 static bool
2156 try_open_url(const std::string &url)
2157 {
2158 #ifdef WIN32
2159         return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2160 #else // !WIN32
2161         std::vector<std::string> command_line;
2162         std::vector<std::string> browsers;
2163         browsers.reserve(23);
2164
2165         // Browser wrapper scripts
2166 #ifdef USE_OPEN_FOR_URLS
2167         browsers.push_back("open");              // Apple MacOS X wrapper, on Linux it opens a virtual console
2168 #endif
2169         browsers.push_back("xdg-open");          // XDG wrapper
2170         browsers.push_back("sensible-browser");  // Debian wrapper
2171         browsers.push_back("gnome-open");        // GNOME wrapper
2172         browsers.push_back("kfmclient");         // KDE wrapper
2173         browsers.push_back("exo-open");          // XFCE wrapper
2174
2175         // Alternatives system
2176         browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2177         browsers.push_back("x-www-browser");     // Debian GUI alternative
2178
2179         // Individual browsers
2180         browsers.push_back("firefox");
2181         browsers.push_back("epiphany-browser");
2182         browsers.push_back("epiphany");
2183         browsers.push_back("konqueror");
2184         browsers.push_back("iceweasel");
2185         browsers.push_back("mozilla");
2186         browsers.push_back("netscape");
2187         browsers.push_back("icecat");
2188         browsers.push_back("galeon");
2189         browsers.push_back("midori");
2190         browsers.push_back("safari");
2191         browsers.push_back("opera");
2192         browsers.push_back("amaya");
2193         browsers.push_back("netsurf");
2194         browsers.push_back("dillo");
2195
2196         // Try the user-specified browser first
2197         command_line.push_back(App::browser_command);
2198         if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2199         command_line.push_back(url);
2200
2201         try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2202         catch( Glib::SpawnError& exception ){
2203
2204                 while ( !browsers.empty() )
2205                 {
2206                         // Skip the browser if we already tried it
2207                         if( browsers[0] == App::browser_command )
2208                                 continue;
2209
2210                         // Construct the command line
2211                         command_line.clear();
2212                         command_line.push_back(browsers[0]);
2213                         if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2214                         command_line.push_back(url);
2215
2216                         // Remove the browser from the list
2217                         browsers.erase(browsers.begin());
2218
2219                         // Try to spawn the browser
2220                         try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2221                         // Failed, move on to the next one
2222                         catch(Glib::SpawnError& exception){ continue; }
2223                         return true; // No exception means we succeeded!                        
2224                 }
2225         }
2226
2227         return false;
2228 #endif // !WIN32
2229 }
2230
2231 void
2232 App::dialog_help()
2233 {
2234         if (!try_open_url("http://synfig.org/Documentation"))
2235         {
2236                 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2237                 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2238                 dialog.set_title(_("Help"));
2239                 dialog.run();
2240         }
2241 }
2242
2243 void
2244 App::open_url(const std::string &url)
2245 {
2246         if(!try_open_url(url))
2247         {
2248                 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2249                 dialog.set_secondary_text(url);
2250                 dialog.set_title(_("No browser found"));
2251                 dialog.run();
2252         }
2253 }
2254
2255 bool
2256 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2257 {
2258         Gtk::Dialog dialog(
2259                 title,          // Title
2260                 true,           // Modal
2261                 true);          // use_separator
2262
2263         Gtk::Label label(message);
2264         label.show();
2265         dialog.get_vbox()->pack_start(label);
2266
2267         Gtk::Entry entry;
2268         entry.set_text(text);
2269         entry.show();
2270         entry.set_activates_default(true);
2271
2272         dialog.get_vbox()->pack_start(entry);
2273
2274         dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2275         dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2276         dialog.set_default_response(Gtk::RESPONSE_OK);
2277
2278         entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2279         dialog.show();
2280
2281         if(dialog.run()!=Gtk::RESPONSE_OK)
2282                 return false;
2283
2284         text=entry.get_text();
2285
2286         return true;
2287 }
2288
2289 bool
2290 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2291 {
2292         Gtk::Dialog dialog(
2293                 title,          // Title
2294                 true,           // Modal
2295                 true);          // use_separator
2296
2297         Gtk::Label label(message);
2298         label.show();
2299         dialog.get_vbox()->pack_start(label);
2300
2301         Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2302         text_buffer->set_text(text);
2303         Gtk::TextView text_view(text_buffer);
2304         text_view.show();
2305
2306         dialog.get_vbox()->pack_start(text_view);
2307
2308         dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2309         dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2310         dialog.set_default_response(Gtk::RESPONSE_OK);
2311
2312         //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2313         dialog.show();
2314
2315         if(dialog.run()!=Gtk::RESPONSE_OK)
2316                 return false;
2317
2318         text=text_buffer->get_text();
2319
2320         return true;
2321 }
2322
2323 bool
2324 App::open(std::string filename)
2325 {
2326         return open_as(filename,filename);
2327 }
2328
2329 // this is called from autorecover.cpp:
2330 //   App::open_as(get_shadow_file_name(filename),filename)
2331 // other than that, 'filename' and 'as' are the same
2332 bool
2333 App::open_as(std::string filename,std::string as)
2334 {
2335 #ifdef WIN32
2336     char long_name[1024];
2337     if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2338         // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2339         // don't use it if that's the case
2340         if (long_name[0] != '\0')
2341                 as=long_name;
2342 #endif
2343
2344         try
2345         {
2346                 OneMoment one_moment;
2347                 String errors;
2348
2349                 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors));
2350                 if(canvas && get_instance(canvas))
2351                 {
2352                         get_instance(canvas)->find_canvas_view(canvas)->present();
2353                         info("%s is already open", filename.c_str());
2354                         // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2355                 }
2356                 else
2357                 {
2358                         if(!canvas)
2359                                 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2360
2361                         if (as.find(custom_filename_prefix.c_str()) != 0)
2362                                 add_recent_file(as);
2363
2364                         handle<Instance> instance(Instance::create(canvas));
2365
2366                         if(!instance)
2367                                 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2368
2369                         set_recent_file_window_size(instance);
2370
2371                         one_moment.hide();
2372
2373                         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)")))
2374                                 instance->dialog_cvs_update();
2375                 }
2376         }
2377         catch(String x)
2378         {
2379                 dialog_error_blocking(_("Error"), x);
2380                 return false;
2381         }
2382         catch(...)
2383         {
2384                 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2385                 return false;
2386         }
2387
2388         return true;
2389 }
2390
2391
2392 void
2393 App::new_instance()
2394 {
2395         handle<synfig::Canvas> canvas=synfig::Canvas::create();
2396
2397         String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2398         canvas->set_name(file_name);
2399         file_name += ".sifz";
2400
2401         canvas->rend_desc().set_frame_rate(24.0);
2402         canvas->rend_desc().set_time_start(0.0);
2403         canvas->rend_desc().set_time_end(5.0);
2404         canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2405         canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2406         // The top left and botton right positions are expressed in units
2407         // Original convention is that 1 unit = 60 pixels
2408         canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2409         canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2410         canvas->rend_desc().set_w(preferred_x_size);
2411         canvas->rend_desc().set_h(preferred_y_size);
2412         canvas->rend_desc().set_antialias(1);
2413         canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2414         canvas->set_file_name(file_name);
2415
2416         handle<Instance> instance = Instance::create(canvas);
2417
2418         if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2419                 instance->find_canvas_view(canvas)->canvas_properties.present();
2420 }
2421
2422 void
2423 App::dialog_open(string filename)
2424 {
2425         if (filename.empty())
2426                 filename="*.sif";
2427
2428         while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2429         {
2430                 // If the filename still has wildcards, then we should
2431                 // continue looking for the file we want
2432                 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2433                         continue;
2434
2435                 if(open(filename))
2436                         break;
2437
2438                 get_ui_interface()->error(_("Unable to open file"));
2439         }
2440 }
2441
2442 void
2443 App::set_selected_instance(etl::loose_handle<Instance> instance)
2444 {
2445 /*      if(get_selected_instance()==instance)
2446         {
2447                 selected_instance=instance;
2448                 signal_instance_selected()(instance);
2449                 return;
2450         }
2451         else
2452         {
2453 */
2454                 selected_instance=instance;
2455                 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2456                 {
2457                         if(instance)
2458                         {
2459                                 instance->focus(instance->get_canvas());
2460                         }
2461                         else
2462                                 set_selected_canvas_view(0);
2463                 }
2464                 signal_instance_selected()(instance);
2465 }
2466
2467 void
2468 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2469 {
2470         selected_canvas_view=canvas_view;
2471         signal_canvas_view_focus()(selected_canvas_view);
2472         if(canvas_view)
2473         {
2474                 selected_instance=canvas_view->get_instance();
2475                 signal_instance_selected()(canvas_view->get_instance());
2476         }
2477 /*
2478         if(get_selected_canvas_view()==canvas_view)
2479         {
2480                 signal_canvas_view_focus()(selected_canvas_view);
2481                 signal_instance_selected()(canvas_view->get_instance());
2482                 return;
2483         }
2484         selected_canvas_view=canvas_view;
2485         if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2486                 set_selected_instance(canvas_view->get_instance());
2487         signal_canvas_view_focus()(selected_canvas_view);
2488 */
2489 }
2490
2491 etl::loose_handle<Instance>
2492 App::get_instance(etl::handle<synfig::Canvas> canvas)
2493 {
2494         if(!canvas) return 0;
2495         canvas=canvas->get_root();
2496
2497         std::list<etl::handle<Instance> >::iterator iter;
2498         for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2499         {
2500                 if((*iter)->get_canvas()==canvas)
2501                         return *iter;
2502         }
2503         return 0;
2504 }
2505
2506 void
2507 App::dialog_about()
2508 {
2509         if(about)
2510                 about->show();
2511 }
2512
2513 void
2514 studio::App::undo()
2515 {
2516         if(selected_instance)
2517                 selected_instance->undo();
2518 }
2519
2520 void
2521 studio::App::redo()
2522 {
2523         if(selected_instance)
2524                 selected_instance->redo();
2525 }
2526
2527 synfig::String
2528 studio::App::get_base_path()
2529 {
2530         return app_base_path_;
2531 }