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