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