d94d3fdb5d333d7c1700af3ec6c326f07beef104
[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
37 #ifdef HAVE_SYS_ERRNO_H
38 #include <sys/errno.h>
39 #endif
40 #include <gtkmm/fileselection.h>
41 #include <gtkmm/dialog.h>
42 #include <gtkmm/messagedialog.h>
43 #include <gtkmm/label.h>
44 #include <gtkmm/stock.h>
45 #include <gtkmm/stockitem.h>
46 #include <gtkmm/iconsource.h>
47 #include <gtkmm/inputdialog.h>
48 #include <gtkmm/accelmap.h>
49 #include <gtkmm/uimanager.h>
50
51 #include <gtk/gtk.h>
52
53 #include <synfig/loadcanvas.h>
54
55 #include "app.h"
56 #include "about.h"
57 #include "instance.h"
58 #include "canvasview.h"
59 #include "dialog_setup.h"
60 #include "dialog_gradient.h"
61 #include "dialog_color.h"
62 #include "toolbox.h"
63 #include "compview.h"
64 #include "onemoment.h"
65
66 #include "dockmanager.h"
67
68 #include "state_eyedrop.h"
69 #include "state_normal.h"
70 #include "state_draw.h"
71 #include "state_fill.h"
72 #include "state_bline.h"
73 #include "state_polygon.h"
74 #include "state_sketch.h"
75 #include "state_gradient.h"
76 #include "state_circle.h"
77 #include "state_rectangle.h"
78 #include "state_smoothmove.h"
79 #include "state_scale.h"
80 #include "state_width.h"
81 #include "state_rotate.h"
82 #include "state_zoom.h"
83
84 #include "devicetracker.h"
85 #include "dialog_tooloptions.h"
86
87 #include "autorecover.h"
88
89 #include <synfigapp/settings.h>
90 #include "dock_history.h"
91 #include "dock_canvases.h"
92 #include "dock_keyframes.h"
93 #include "dock_layers.h"
94 #include "dock_params.h"
95 #include "dock_metadata.h"
96 #include "dock_children.h"
97 #include "dock_info.h"
98 #include "dock_navigator.h"
99 #include "dock_layergroups.h"
100 #include "dock_timetrack.h"
101 #include "dock_curves.h"
102
103 #include "mod_palette/mod_palette.h"
104 #include "mod_mirror/mod_mirror.h"
105
106 #include <sys/stat.h>
107
108 #include "ipc.h"
109
110 #include "module.h"
111
112 #include "statemanager.h"
113
114 #ifdef WITH_FMOD
115 #include <fmod.h>
116 #endif
117
118 #ifdef WIN32
119 #define _WIN32_WINNT 0x0500
120 #include <windows.h>
121 #endif
122 #include <gtkmm/accelmap.h>
123 #include <gtkmm/filechooser.h>
124 #include <gtkmm/filechooserdialog.h>
125
126 #include "general.h"
127
128 #endif
129
130 /* === U S I N G =========================================================== */
131
132 using namespace std;
133 using namespace etl;
134 using namespace synfig;
135 using namespace studio;
136
137 /* === M A C R O S ========================================================= */
138
139 #ifndef SYNFIG_USER_APP_DIR
140 #ifdef __APPLE__
141 #define SYNFIG_USER_APP_DIR     "Library/Synfig"
142 #elif defined(_WIN32)
143 #define SYNFIG_USER_APP_DIR     "Synfig"
144 #else
145 #define SYNFIG_USER_APP_DIR     ".synfig"
146 #endif
147 #endif
148
149 #ifndef DPM2DPI
150 #define DPM2DPI(x)      (float(x)/39.3700787402f)
151 #define DPI2DPM(x)      (float(x)*39.3700787402f)
152 #endif
153
154 #ifdef WIN32
155 #       ifdef IMAGE_DIR
156 #               undef IMAGE_DIR
157 #               define IMAGE_DIR "share\\pixmaps"
158 #       endif
159 #endif
160
161 #ifndef IMAGE_DIR
162 #       define IMAGE_DIR "/usr/local/share/pixmaps"
163 #endif
164
165 #ifndef IMAGE_EXT
166 #       define IMAGE_EXT        "tif"
167 #endif
168
169 #include <synfigapp/main.h>
170
171 /* === S I G N A L S ======================================================= */
172
173 static sigc::signal<void> signal_present_all_;
174 sigc::signal<void>&
175 App::signal_present_all() { return signal_present_all_; }
176
177 static sigc::signal<void> signal_recent_files_changed_;
178 sigc::signal<void>&
179 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
180
181 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
182 sigc::signal<void,etl::loose_handle<CanvasView> >&
183 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
184
185 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
186 sigc::signal<void,etl::handle<Instance> >&
187 App::signal_instance_selected() { return signal_instance_selected_; }
188
189 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
190 sigc::signal<void,etl::handle<Instance> >&
191 App::signal_instance_created() { return signal_instance_created_; }
192
193 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
194 sigc::signal<void,etl::handle<Instance> >&
195 App::signal_instance_deleted() { return signal_instance_deleted_; }
196
197 /* === G L O B A L S ======================================================= */
198
199 static std::list<std::string> recent_files;
200 const std::list<std::string>& App::get_recent_files() { return recent_files; }
201
202 int     App::Busy::count;
203 bool App::shutdown_in_progress;
204
205 synfig::Gamma App::gamma;
206
207 Glib::RefPtr<studio::UIManager> App::ui_manager_;
208
209 synfig::Distance::System App::distance_system;
210
211 studio::Dialog_Setup* App::dialog_setup;
212
213 etl::handle< studio::ModPalette > mod_palette_;
214 //studio::Dialog_Palette* App::dialog_palette;
215
216 std::list<etl::handle<Instance> > App::instance_list;
217
218 static etl::handle<synfigapp::UIInterface> ui_interface_;
219 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
220
221 etl::handle<Instance> App::selected_instance;
222 etl::handle<CanvasView> App::selected_canvas_view;
223
224 studio::Toolbox *studio::App::toolbox=NULL;
225
226 studio::AutoRecover *studio::App::auto_recover=NULL;
227
228 studio::IPC *ipc=NULL;
229
230 studio::DockManager* studio::App::dock_manager=0;
231
232 studio::DeviceTracker* studio::App::device_tracker=0;
233
234 studio::Dialog_Gradient* studio::App::dialog_gradient;
235
236 studio::Dialog_Color* studio::App::dialog_color;
237
238 Gtk::InputDialog* studio::App::dialog_input;
239
240 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
241
242 studio::Dock_History* dock_history;
243 studio::Dock_Canvases* dock_canvases;
244 studio::Dock_Keyframes* dock_keyframes;
245 studio::Dock_Layers* dock_layers;
246 studio::Dock_Params* dock_params;
247 studio::Dock_MetaData* dock_meta_data;
248 studio::Dock_Children* dock_children;
249 studio::Dock_Info* dock_info;
250 studio::Dock_LayerGroups* dock_layer_groups;
251 studio::Dock_Navigator* dock_navigator;
252 studio::Dock_Timetrack* dock_timetrack;
253 studio::Dock_Curves* dock_curves;
254
255 std::list< etl::handle< studio::Module > > module_list_;
256
257 bool studio::App::use_colorspace_gamma=true;
258 bool studio::App::single_threaded=false;
259
260 static int max_recent_files_=25;
261 int studio::App::get_max_recent_files() { return max_recent_files_; }
262 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
263
264 static synfig::String app_base_path_;
265
266 namespace studio {
267
268 bool
269 really_delete_widget(Gtk::Widget *widget)
270 {
271         synfig::info("really delete %p", (void*)widget);
272         delete widget;
273         return false;
274 }
275
276 // nasty workaround - when we've finished with a popup menu, we want to delete it
277 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
278 // so schedule the real delete to happen in 50ms, giving the action a chance to run
279 void
280 delete_widget(Gtk::Widget *widget)
281 {
282         synfig::info("delete %p", (void*)widget);
283         Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
284 }
285
286 }; // END of namespace studio
287 studio::StateManager* state_manager;
288
289
290
291
292 class GlobalUIInterface : public synfigapp::UIInterface
293 {
294 public:
295
296         virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
297         {
298                 Gtk::Dialog dialog(
299                         title,          // Title
300                         true,           // Modal
301                         true            // use_separator
302                 );
303                 Gtk::Label label(message);
304                 label.show();
305
306                 dialog.get_vbox()->pack_start(label);
307                 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
308                 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
309
310                 dialog.set_default_response(dflt);
311                 dialog.show();
312                 return (Response)dialog.run();
313         }
314         virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
315         {
316                 Gtk::Dialog dialog(
317                         title,          // Title
318                         true,           // Modal
319                         true            // use_separator
320                 );
321                 Gtk::Label label(message);
322                 label.show();
323
324                 dialog.get_vbox()->pack_start(label);
325                 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
326                 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
327                 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
328
329                 dialog.set_default_response(dflt);
330                 dialog.show();
331                 return (Response)dialog.run();
332         }
333         virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
334         {
335                 Gtk::Dialog dialog(
336                         title,          // Title
337                         true,           // Modal
338                         true            // use_separator
339                 );
340                 Gtk::Label label(message);
341                 label.show();
342
343                 dialog.get_vbox()->pack_start(label);
344                 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
345                 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
346
347                 dialog.set_default_response(dflt);
348                 dialog.show();
349                 return (Response)dialog.run();
350         }
351
352         virtual bool
353         task(const std::string &task)
354         {
355                 std::cerr<<task<<std::endl;
356                 while(studio::App::events_pending())studio::App::iteration(false);
357                 return true;
358         }
359
360         virtual bool
361         error(const std::string &err)
362         {
363                 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
364                 dialog.show();
365                 dialog.run();
366                 return true;
367         }
368
369         virtual bool
370         warning(const std::string &err)
371         {
372                 std::cerr<<"warning: "<<err<<std::endl;
373                 while(studio::App::events_pending())studio::App::iteration(false);
374                 return true;
375         }
376
377         virtual bool
378         amount_complete(int /*current*/, int /*total*/)
379         {
380                 while(studio::App::events_pending())studio::App::iteration(false);
381                 return true;
382         }
383 };
384
385 /* === P R O C E D U R E S ================================================= */
386
387 /*
388 void
389 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
390 {
391         action_group_list.push_back(action_group);
392         Gtk::UIManager::insert_action_group(action_group, pos);
393 }
394
395 void
396 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
397 {
398         std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
399         for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
400                 if(*iter==action_group)
401                 {
402                         action_group_list.erase(iter);
403                         Gtk::UIManager::remove_action_group(action_group);
404                         return;
405                 }
406         synfig::error("Unable to find action group");
407 }
408
409 void
410 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
411 {
412         ui_manager->insert_action_group(group,0);
413         return;
414         DEBUGPOINT();
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         DEBUGPOINT();
419         for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
420         {
421                 DEBUGPOINT();
422                 if(*iter && (*iter)->get_name()!="menus")
423                 {
424                         synfig::info("Removing action group "+(*iter)->get_name());
425                         ui_manager->remove_action_group(*iter);
426                 }
427         }
428         DEBUGPOINT();
429         ui_manager->insert_action_group(group,0);
430
431         DEBUGPOINT();
432         for(;!prev_groups.empty();prev_groups.pop_front())
433         {
434                 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
435                         ui_manager->insert_action_group(prev_groups.front(),1);
436         }
437         DEBUGPOINT();
438 }
439 */
440 class Preferences : public synfigapp::Settings
441 {
442 public:
443         virtual bool get_value(const synfig::String& key, synfig::String& value)const
444         {
445                 if(key=="gamma")
446                 {
447                         value=strprintf("%f %f %f %f",
448                                 App::gamma.get_gamma_r(),
449                                 App::gamma.get_gamma_g(),
450                                 App::gamma.get_gamma_b(),
451                                 App::gamma.get_black_level()
452                         );
453                         return true;
454                 }
455                 if(key=="time_format")
456                 {
457                         value=strprintf("%i",App::get_time_format());
458                         return true;
459                 }
460                 if(key=="file_history.size")
461                 {
462                         value=strprintf("%i",App::get_max_recent_files());
463                         return true;
464                 }
465                 if(key=="use_colorspace_gamma")
466                 {
467                         value=strprintf("%i",(int)App::use_colorspace_gamma);
468                         return true;
469                 }
470                 if(key=="distance_system")
471                 {
472                         value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
473                         return true;
474                 }
475                 if(key=="single_threaded")
476                 {
477                         value=strprintf("%i",(int)App::single_threaded);
478                         return true;
479                 }
480                 if(key=="auto_recover_backup_interval")
481                 {
482                         value=strprintf("%i",App::auto_recover->get_timeout());
483                         return true;
484                 }
485
486                 return synfigapp::Settings::get_value(key,value);
487         }
488
489         virtual bool set_value(const synfig::String& key,const synfig::String& value)
490         {
491                 if(key=="gamma")
492                 {
493                         float r,g,b,blk;
494
495                         strscanf(value,"%f %f %f %f",
496                                 &r,
497                                 &g,
498                                 &b,
499                                 &blk
500                         );
501
502                         App::gamma.set_all(r,g,b,blk);
503
504                         return true;
505                 }
506                 if(key=="time_format")
507                 {
508                         int i(atoi(value.c_str()));
509                         App::set_time_format(static_cast<synfig::Time::Format>(i));
510                         return true;
511                 }
512                 if(key=="auto_recover_backup_interval")
513                 {
514                         int i(atoi(value.c_str()));
515                         App::auto_recover->set_timeout(i);
516                         return true;
517                 }
518                 if(key=="file_history.size")
519                 {
520                         int i(atoi(value.c_str()));
521                         App::set_max_recent_files(i);
522                         return true;
523                 }
524                 if(key=="use_colorspace_gamma")
525                 {
526                         int i(atoi(value.c_str()));
527                         App::use_colorspace_gamma=i;
528                         return true;
529                 }
530                 if(key=="distance_system")
531                 {
532                         App::distance_system=Distance::ident_system(value);;
533                         return true;
534                 }
535                 if(key=="single_threaded")
536                 {
537                         int i(atoi(value.c_str()));
538                         App::single_threaded=i;
539                         return true;
540                 }
541
542                 return synfigapp::Settings::set_value(key,value);
543         }
544
545         virtual KeyList get_key_list()const
546         {
547                 KeyList ret(synfigapp::Settings::get_key_list());
548                 ret.push_back("gamma");
549                 ret.push_back("time_format");
550                 ret.push_back("distance_system");
551                 ret.push_back("file_history.size");
552                 ret.push_back("use_colorspace_gamma");
553                 ret.push_back("single_threaded");
554                 ret.push_back("auto_recover_backup_interval");
555                 return ret;
556         }
557 };
558
559 static ::Preferences _preferences;
560
561 void
562 init_ui_manager()
563 {
564         Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
565
566         Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
567
568         Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
569
570         menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
571         menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
572         menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
573         menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
574         menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
575         menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
576         menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
577         menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
578         menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
579         menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
580         menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
581         menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
582
583         // Add the synfigapp actions...
584         synfigapp::Action::Book::iterator iter;
585         for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
586         {
587                 actions_action_group->add(Gtk::Action::create(
588                         "action-"+iter->second.name,
589                         get_action_stock_id(iter->second),
590                         iter->second.local_name,iter->second.local_name
591                 ));
592         }
593
594 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
595 #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); }
596 #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); }
597
598         DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
599         DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
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
617
618         DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
619         DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
620         DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
621         DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
622         DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
623         DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
624         DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
625         DEFINE_ACTION("properties", _("Properties"));
626
627         DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
628         DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
629         DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
630         DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
631         DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
632         DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
633         DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
634         DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
635         DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
636         DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
637         DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
638         DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
639         DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
640         DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
641         DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
642         DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
643         DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
644         DEFINE_ACTION("play", _("Play"));
645         // DEFINE_ACTION("pause", _("Pause"));
646         DEFINE_ACTION("stop", _("Stop"));
647         DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
648         DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
649         DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
650         DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
651         DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
652         DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
653         DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
654         DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
655         DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
656         DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
657         DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
658         DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
659         DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
660         DEFINE_ACTION("seek-next-frame", _("Next Frame"));
661         DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
662         DEFINE_ACTION("seek-next-second", _("Seek Forward"));
663         DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
664         DEFINE_ACTION("seek-begin", _("Seek to Begin"));
665         DEFINE_ACTION("seek-end", _("Seek to End"));
666
667         DEFINE_ACTION("action-group_add", _("Add group"));
668
669         DEFINE_ACTION("canvas-new", _("New Canvas"));
670
671         DEFINE_ACTION("amount-inc", _("Increase Amount"));
672         DEFINE_ACTION("amount-dec", _("Decrease Amount"));
673
674 #undef DEFINE_ACTION
675
676
677 // Set up synfigapp actions
678         /*{
679                 synfigapp::Action::Book::iterator iter;
680
681                 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
682                 {
683                         Gtk::StockID stock_id;
684
685                         if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
686                         {
687                                 //Gtk::Image* image(manage(new Gtk::Image()));
688                                 if(iter->second.task=="raise")                  stock_id=Gtk::Stock::GO_UP;
689                                 else if(iter->second.task=="lower")             stock_id=Gtk::Stock::GO_DOWN;
690                                 else if(iter->second.task=="move_top")  stock_id=Gtk::Stock::GOTO_TOP;
691                                 else if(iter->second.task=="move_bottom")       stock_id=Gtk::Stock::GOTO_BOTTOM;
692                                 else if(iter->second.task=="remove")    stock_id=Gtk::Stock::DELETE;
693                                 else if(iter->second.task=="set_on")    stock_id=Gtk::Stock::YES;
694                                 else if(iter->second.task=="set_off")   stock_id=Gtk::Stock::NO;
695                                 //else if(iter->second.task=="duplicate")       stock_id=Gtk::Stock::COPY;
696                                 else if(iter->second.task=="remove")    stock_id=Gtk::Stock::DELETE;
697                                 else                                                                    stock_id=Gtk::StockID("synfig-"+iter->second.task);
698
699                                 actions_action_group->add(Gtk::Action::create(
700                                         "action-"+iter->second.name,
701                                         stock_id,
702                                         iter->second.local_name,iter->second.local_name
703                                 ));
704                         }
705                 }
706         }
707 */
708
709
710     Glib::ustring ui_info =
711 "<ui>"
712 "       <popup name='menu-toolbox' action='menu-toolbox'>"
713 "       <menu action='menu-file'>"
714 "       </menu>"
715 "       </popup>"
716 "       <popup name='menu-main' action='menu-main'>"
717 "       <menu action='menu-file'>"
718 "               <menuitem action='save' />"
719 "               <menuitem action='save-as' />"
720 "               <menuitem action='revert' />"
721 "               <separator name='bleh01'/>"
722 "               <menuitem action='cvs-add' />"
723 "               <menuitem action='cvs-update' />"
724 "               <menuitem action='cvs-commit' />"
725 "               <menuitem action='cvs-revert' />"
726 "               <separator name='bleh02'/>"
727 "               <menuitem action='import' />"
728 "               <separator name='bleh03'/>"
729 "               <menuitem action='render' />"
730 "               <menuitem action='preview' />"
731 "               <menuitem action='sound' />"
732 "               <separator name='bleh04'/>"
733 "               <menuitem action='options' />"
734 "               <menuitem action='close' />"
735 "               <menuitem action='close-document' />"
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         delete state_manager;
1229
1230         delete ipc;
1231
1232         delete auto_recover;
1233
1234         toolbox->hide();
1235
1236 //      studio::App::iteration(false);
1237
1238         delete toolbox;
1239
1240 //      studio::App::iteration(false);
1241
1242 //      studio::App::iteration(false);
1243
1244         delete dialog_setup;
1245
1246         delete dialog_gradient;
1247
1248         delete dialog_color;
1249
1250         delete dialog_input;
1251
1252         delete dock_manager;
1253
1254         instance_list.clear();
1255
1256 //      studio::App::iteration(false);
1257 }
1258
1259 String
1260 App::get_user_app_directory()
1261 {
1262         return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1263 }
1264
1265 synfig::String
1266 App::get_config_file(const synfig::String& file)
1267 {
1268         return Glib::build_filename(get_user_app_directory(),file);
1269 }
1270
1271 void
1272 App::add_recent_file(const std::string &file_name)
1273 {
1274         std::string filename(file_name);
1275
1276         assert(!filename.empty());
1277
1278         if(filename.empty())
1279                 return;
1280
1281         // Toss out any "hidden" files
1282         if(basename(filename)[0]=='.')
1283                 return;
1284
1285         // If we aren't an absolute path, turn ourselves into one
1286         if(!is_absolute_path(filename))
1287                 filename=absolute_path(filename);
1288
1289         list<string>::iterator iter;
1290         // Check to see if the file is already on the list.
1291         // If it is, then remove it from the list
1292         for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1293                 if(*iter==filename)
1294                 {
1295                         recent_files.erase(iter);
1296                         break;
1297                 }
1298
1299
1300         // Push the filename to the front of the list
1301         recent_files.push_front(filename);
1302
1303         // Clean out the files at the end of the list.
1304         while(recent_files.size()>(unsigned)get_max_recent_files())
1305                 recent_files.pop_back();
1306
1307         signal_recent_files_changed_();
1308
1309         return;
1310 }
1311
1312 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1313
1314 Time::Format
1315 App::get_time_format()
1316 {
1317         return _App_time_format;
1318 }
1319
1320 void
1321 App::set_time_format(synfig::Time::Format x)
1322 {
1323         _App_time_format=x;
1324 }
1325
1326
1327 void
1328 App::save_settings()
1329 {
1330         char * old_locale;
1331         try
1332         {
1333         old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1334         setlocale(LC_NUMERIC, "C");
1335                 {
1336                         std::string filename=get_config_file("accelrc");
1337                         Gtk::AccelMap::save(filename);
1338                 }
1339                 do{
1340                         std::string filename=get_config_file("recentfiles");
1341
1342                         std::ofstream file(filename.c_str());
1343
1344                         if(!file)
1345                         {
1346                                 synfig::warning("Unable to save %s",filename.c_str());
1347                                 break;
1348                         }
1349
1350                         list<string>::reverse_iterator iter;
1351
1352                         for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1353                                 file<<*iter<<endl;
1354                 }while(0);
1355
1356                 std::string filename=get_config_file("settings");
1357                 synfigapp::Main::settings().save_to_file(filename);
1358         setlocale(LC_NUMERIC,old_locale);
1359         }
1360         catch(...)
1361         {
1362                 synfig::warning("Caught exception when attempting to save settings.");
1363         }
1364 }
1365
1366 void
1367 App::load_settings()
1368 {
1369         char  * old_locale;
1370         try
1371         {
1372         old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1373         setlocale(LC_NUMERIC, "C");
1374                 {
1375                         std::string filename=get_config_file("accelrc");
1376                         Gtk::AccelMap::load(filename);
1377                 }
1378                 {
1379                         std::string filename=get_config_file("recentfiles");
1380
1381                         std::ifstream file(filename.c_str());
1382
1383                         while(file)
1384                         {
1385                                 std::string recent_file;
1386                                 getline(file,recent_file);
1387                                 if(!recent_file.empty())
1388                                         add_recent_file(recent_file);
1389                         }
1390                 }
1391                 std::string filename=get_config_file("settings");
1392                 if(!synfigapp::Main::settings().load_from_file(filename))
1393                 {
1394                         //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1395                         //if(!synfigapp::Main::settings().load_from_file(filename))
1396                         {
1397                                 gamma.set_gamma(1.0/2.2);
1398                                 reset_initial_window_configuration();
1399                         }
1400                 }
1401         setlocale(LC_NUMERIC,old_locale);
1402         }
1403         catch(...)
1404         {
1405                 synfig::warning("Caught exception when attempting to load settings.");
1406         }
1407 }
1408
1409 void
1410 App::reset_initial_window_configuration()
1411 {
1412         synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1413         synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1414         synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1415         synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1416         synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1417         synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1418         synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1419         synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1420         synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1421         synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1422         synfigapp::Main::settings().set_value("pref.distance_system","pt");
1423         synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1424         synfigapp::Main::settings().set_value("pref.single_threaded","0");
1425         synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1426 }
1427
1428 bool
1429 App::shutdown_request(GdkEventAny*)
1430 {
1431         quit();
1432         return true;
1433         //return !shutdown_in_progress;
1434 }
1435
1436 void
1437 App::quit()
1438 {
1439         if(shutdown_in_progress)return;
1440
1441
1442         get_ui_interface()->task(_("Quit Request"));
1443         if(Busy::count)
1444         {
1445                 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1446                 return;
1447         }
1448
1449         std::list<etl::handle<Instance> >::iterator iter;
1450         for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1451         {
1452                 if(!(*iter)->safe_close())
1453                         return;
1454
1455 /*
1456                 if((*iter)->synfigapp::Instance::get_action_count())
1457                 {
1458                         handle<synfigapp::UIInterface> uim;
1459                         uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1460                         assert(uim);
1461                         string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1462                         switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1463                         {
1464                                 case synfigapp::UIInterface::RESPONSE_NO:
1465                                         break;
1466                                 case synfigapp::UIInterface::RESPONSE_YES:
1467                                         (*iter)->save();
1468                                         break;
1469                                 case synfigapp::UIInterface::RESPONSE_CANCEL:
1470                                         return;
1471                                 default:
1472                                         assert(0);
1473                                         return;
1474                         }
1475                 }
1476
1477
1478                 if((*iter)->synfigapp::Instance::is_modified())
1479                 {
1480                         handle<synfigapp::UIInterface> uim;
1481                         uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1482                         assert(uim);
1483                         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() );
1484                         switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1485                         {
1486                                 case synfigapp::UIInterface::RESPONSE_NO:
1487                                         break;
1488                                 case synfigapp::UIInterface::RESPONSE_YES:
1489                                         (*iter)->dialog_cvs_commit();
1490                                         break;
1491                                 case synfigapp::UIInterface::RESPONSE_CANCEL:
1492                                         return;
1493                                 default:
1494                                         assert(0);
1495                                         return;
1496                         }
1497                 }
1498 */
1499
1500                 // This next line causes things to crash for some reason
1501                 //(*iter)->close();
1502         }
1503
1504         shutdown_in_progress=true;
1505
1506         instance_list.clear();
1507
1508         while(studio::App::events_pending())studio::App::iteration(false);
1509
1510         Gtk::Main::quit();
1511         auto_recover->normal_shutdown();
1512
1513         get_ui_interface()->task(_("Quit Request sent"));
1514 }
1515
1516 void
1517 App::show_setup()
1518 {
1519         dialog_setup->refresh();
1520         dialog_setup->show();
1521 }
1522
1523 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1524 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1525
1526 //#ifdef WIN32
1527 //#define USE_WIN32_FILE_DIALOGS 1
1528 //#endif
1529
1530 #ifdef USE_WIN32_FILE_DIALOGS
1531 static OPENFILENAME ofn={};
1532 #endif
1533
1534 #ifdef WIN32
1535 #include <gdk/gdkwin32.h>
1536 #endif
1537
1538 bool
1539 App::dialog_open_file(const std::string &title, std::string &filename)
1540 {
1541 #ifdef USE_WIN32_FILE_DIALOGS
1542         static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1543
1544         GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1545         HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1546         HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1547
1548         ofn.lStructSize=sizeof(OPENFILENAME);
1549         ofn.hwndOwner = hWnd;
1550         ofn.hInstance = hInstance;
1551         ofn.lpstrFilter = szFilter;
1552 //      ofn.lpstrCustomFilter=NULL;
1553 //      ofn.nMaxCustFilter=0;
1554 //      ofn.nFilterIndex=0;
1555 //      ofn.lpstrFile=NULL;
1556         ofn.nMaxFile=MAX_PATH;
1557 //      ofn.lpstrFileTitle=NULL;
1558 //      ofn.lpstrInitialDir=NULL;
1559 //      ofn.lpstrTitle=NULL;
1560         ofn.Flags=OFN_HIDEREADONLY;
1561 //      ofn.nFileOffset=0;
1562 //      ofn.nFileExtension=0;
1563         ofn.lpstrDefExt=TEXT("sif");
1564 //      ofn.lCustData = 0l;
1565         ofn.lpfnHook=NULL;
1566 //      ofn.lpTemplateName=NULL;
1567
1568         CHAR szFilename[MAX_PATH];
1569         CHAR szTitle[500];
1570         strcpy(szFilename,filename.c_str());
1571         strcpy(szTitle,title.c_str());
1572
1573         ofn.lpstrFile=szFilename;
1574         ofn.lpstrFileTitle=szTitle;
1575
1576         if(GetOpenFileName(&ofn))
1577         {
1578                 filename=szFilename;
1579                 return true;
1580         }
1581         return false;
1582
1583 #else
1584         synfig::String prev_path;
1585         if(!_preferences.get_value("curr_path",prev_path))
1586                 prev_path=".";
1587         prev_path = absolute_path(prev_path);
1588
1589     Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_OPEN);
1590     dialog->set_current_folder(prev_path);
1591     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1592     dialog->add_button(Gtk::Stock::OPEN,   Gtk::RESPONSE_ACCEPT);
1593     if(!filename.empty())
1594                 if (is_absolute_path(filename))
1595                         dialog->set_filename(filename);
1596                 else
1597                         dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1598     if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1599         filename=dialog->get_filename();
1600         delete dialog;
1601         return true;
1602     }
1603     delete dialog;
1604     return false;
1605     /*
1606
1607         GtkWidget *ok;
1608         GtkWidget *cancel;
1609         int val=0;
1610
1611         GtkWidget *fileselection;
1612         fileselection = gtk_file_selection_new(title.c_str());
1613
1614
1615         if(basename(filename)==filename)
1616         {
1617                 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1618         }
1619         else
1620                 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1621
1622         gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1623
1624         ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1625         cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1626
1627         gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1628         gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1629
1630         gtk_widget_show(fileselection);
1631
1632         while(!val)
1633                 iteration();
1634
1635
1636         if(val==1)
1637         {
1638                 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1639                 _preferences.set_value("curr_path",dirname(filename));
1640         }
1641         else
1642         {
1643                 gtk_widget_destroy(fileselection);
1644                 return false;
1645         }
1646         gtk_widget_destroy(fileselection);
1647         return true;
1648     */
1649 #endif
1650 }
1651
1652 bool
1653 App::dialog_save_file(const std::string &title, std::string &filename)
1654 {
1655 #if USE_WIN32_FILE_DIALOGS
1656         static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1657
1658         GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1659         HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1660         HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1661
1662         ofn.lStructSize=sizeof(OPENFILENAME);
1663         ofn.hwndOwner = hWnd;
1664         ofn.hInstance = hInstance;
1665         ofn.lpstrFilter = szFilter;
1666 //      ofn.lpstrCustomFilter=NULL;
1667 //      ofn.nMaxCustFilter=0;
1668 //      ofn.nFilterIndex=0;
1669 //      ofn.lpstrFile=NULL;
1670         ofn.nMaxFile=MAX_PATH;
1671 //      ofn.lpstrFileTitle=NULL;
1672 //      ofn.lpstrInitialDir=NULL;
1673 //      ofn.lpstrTitle=NULL;
1674         ofn.Flags=OFN_OVERWRITEPROMPT;
1675 //      ofn.nFileOffset=0;
1676 //      ofn.nFileExtension=0;
1677         ofn.lpstrDefExt=TEXT("sif");
1678 //      ofn.lCustData = 0l;
1679         ofn.lpfnHook=NULL;
1680 //      ofn.lpTemplateName=NULL;
1681
1682         CHAR szFilename[MAX_PATH];
1683         CHAR szTitle[500];
1684         strcpy(szFilename,filename.c_str());
1685         strcpy(szTitle,title.c_str());
1686
1687         ofn.lpstrFile=szFilename;
1688         ofn.lpstrFileTitle=szTitle;
1689
1690         if(GetSaveFileName(&ofn))
1691         {
1692                 filename=szFilename;
1693                 _preferences.set_value("curr_path",dirname(filename));
1694                 return true;
1695         }
1696         return false;
1697 #else
1698         synfig::String prev_path;
1699         if(!_preferences.get_value("curr_path",prev_path))
1700                 prev_path=".";
1701         prev_path = absolute_path(prev_path);
1702
1703     Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
1704     dialog->set_current_folder(prev_path);
1705     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1706     dialog->add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_ACCEPT);
1707     if(!filename.empty())
1708         {
1709                 std::string full_path;
1710                 if (is_absolute_path(filename))
1711                         full_path = filename;
1712                 else
1713                         full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1714                 // select the file if it exists
1715                 dialog->set_filename(full_path);
1716
1717                 // if the file doesn't exist, put its name into the filename box
1718                 struct stat s;
1719                 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1720                         dialog->set_current_name(basename(filename));
1721         }
1722     if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1723         filename=dialog->get_filename();
1724         delete dialog;
1725                 _preferences.set_value("curr_path",dirname(filename));
1726         return true;
1727     }
1728     delete dialog;
1729     return false;
1730 //      return dialog_open_file(title, filename);
1731 #endif
1732 }
1733
1734 void
1735 App::dialog_error_blocking(const std::string &title, const std::string &message)
1736 {
1737         Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1738         dialog.set_title(title);
1739         dialog.show();
1740         dialog.run();
1741 }
1742
1743 void
1744 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1745 {
1746         Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1747         dialog.set_title(title);
1748         dialog.show();
1749         dialog.run();
1750 }
1751
1752 bool
1753 App::dialog_yes_no(const std::string &title, const std::string &message)
1754 {
1755         Gtk::Dialog dialog(
1756                 title,          // Title
1757                 true,           // Modal
1758                 true            // use_separator
1759         );
1760         Gtk::Label label(message);
1761         label.show();
1762
1763         dialog.get_vbox()->pack_start(label);
1764         dialog.add_button(Gtk::StockID("gtk-yes"),1);
1765         dialog.add_button(Gtk::StockID("gtk-no"),0);
1766         dialog.show();
1767         return dialog.run();
1768 }
1769
1770 int
1771 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1772 {
1773         Gtk::Dialog dialog(
1774                 title,          // Title
1775                 true,           // Modal
1776                 true            // use_separator
1777         );
1778         Gtk::Label label(message);
1779         label.show();
1780
1781         dialog.get_vbox()->pack_start(label);
1782         dialog.add_button(Gtk::StockID("gtk-yes"),1);
1783         dialog.add_button(Gtk::StockID("gtk-no"),0);
1784         dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1785         dialog.show();
1786         return dialog.run();
1787 }
1788
1789 void
1790 App::dialog_not_implemented()
1791 {
1792         Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1793         dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
1794         dialog.run();
1795 }
1796
1797 bool
1798 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1799 {
1800         Gtk::Dialog dialog(
1801                 title,          // Title
1802                 true,           // Modal
1803                 true            // use_separator
1804         );
1805         Gtk::Label label(message);
1806         label.show();
1807         dialog.get_vbox()->pack_start(label);
1808
1809         Gtk::Entry entry;
1810         entry.set_text(text);
1811         entry.show();
1812         entry.set_activates_default(true);
1813         dialog.get_vbox()->pack_start(entry);
1814
1815         dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1816         dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1817         dialog.set_default_response(Gtk::RESPONSE_OK);
1818         entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1819         dialog.show();
1820
1821         if(dialog.run()!=Gtk::RESPONSE_OK)
1822                 return false;
1823
1824         text=entry.get_text();
1825
1826         return true;
1827 }
1828
1829
1830
1831
1832 bool
1833 App::open(std::string filename)
1834 {
1835         return open_as(filename,filename);
1836 }
1837
1838 // this is called from autorecover.cpp:
1839 //   App::open_as(get_shadow_file_name(filename),filename)
1840 // other than that, 'filename' and 'as' are the same
1841 bool
1842 App::open_as(std::string filename,std::string as)
1843 {
1844 #ifdef WIN32
1845     char long_name[1024];
1846     if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1847     as=long_name;
1848 #endif
1849
1850         try
1851         {
1852                 OneMoment one_moment;
1853
1854                 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1855                 if(canvas && get_instance(canvas))
1856                 {
1857                         get_instance(canvas)->find_canvas_view(canvas)->present();
1858                         throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1859                 }
1860                 if(!canvas)
1861                         throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
1862
1863                 add_recent_file(as);
1864
1865                 handle<Instance> instance(Instance::create(canvas));
1866
1867                 if(!instance)
1868                         throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
1869
1870                 one_moment.hide();
1871
1872                 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)")))
1873                         instance->dialog_cvs_update();
1874         }
1875         catch(String x)
1876         {
1877                 dialog_error_blocking(_("Error"), x);
1878                 return false;
1879         }
1880         catch(...)
1881         {
1882                 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
1883                 return false;
1884         }
1885
1886         _preferences.set_value("curr_path",dirname(as));
1887
1888         return true;
1889 }
1890
1891
1892 void
1893 App::new_instance()
1894 {
1895         handle<synfig::Canvas> canvas=synfig::Canvas::create();
1896         canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1897
1898         String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1899
1900         canvas->rend_desc().set_frame_rate(24.0);
1901         canvas->rend_desc().set_time_start(0.0);
1902         canvas->rend_desc().set_time_end(00.0);
1903         canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
1904         canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
1905         canvas->rend_desc().set_tl(Vector(-4,2.25));
1906         canvas->rend_desc().set_br(Vector(4,-2.25));
1907         canvas->rend_desc().set_w(480);
1908         canvas->rend_desc().set_h(270);
1909         canvas->rend_desc().set_antialias(1);
1910         canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
1911         canvas->set_file_name(file_name);
1912
1913         handle<Instance> instance = Instance::create(canvas);
1914
1915         if (!getenv("SYNFIG_DISABLE_NEW_CANVAS_EDIT_PROPERTIES"))
1916                 instance->find_canvas_view(canvas)->canvas_properties.present();
1917 }
1918
1919 void
1920 App::dialog_open()
1921 {
1922         string filename="*.sif";
1923
1924         while(dialog_open_file("Open", filename))
1925         {
1926                 // If the filename still has wildcards, then we should
1927                 // continue looking for the file we want
1928                 if(find(filename.begin(),filename.end(),'*')!=filename.end())
1929                         continue;
1930
1931                 if(open(filename))
1932                         break;
1933
1934                 get_ui_interface()->error(_("Unable to open file"));
1935         }
1936 }
1937
1938 void
1939 App::set_selected_instance(etl::loose_handle<Instance> instance)
1940 {
1941 /*      if(get_selected_instance()==instance)
1942         {
1943                 selected_instance=instance;
1944                 signal_instance_selected()(instance);
1945                 return;
1946         }
1947         else
1948         {
1949 */
1950                 selected_instance=instance;
1951                 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
1952                 {
1953                         if(instance)
1954                         {
1955                                 instance->focus(instance->get_canvas());
1956                         }
1957                         else
1958                                 set_selected_canvas_view(0);
1959                 }
1960                 signal_instance_selected()(instance);
1961 }
1962
1963 void
1964 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
1965 {
1966         selected_canvas_view=canvas_view;
1967         signal_canvas_view_focus()(selected_canvas_view);
1968         if(canvas_view)
1969         {
1970                 selected_instance=canvas_view->get_instance();
1971                 signal_instance_selected()(canvas_view->get_instance());
1972         }
1973 /*
1974         if(get_selected_canvas_view()==canvas_view)
1975         {
1976                 signal_canvas_view_focus()(selected_canvas_view);
1977                 signal_instance_selected()(canvas_view->get_instance());
1978                 return;
1979         }
1980         selected_canvas_view=canvas_view;
1981         if(canvas_view && canvas_view->get_instance() != get_selected_instance())
1982                 set_selected_instance(canvas_view->get_instance());
1983         signal_canvas_view_focus()(selected_canvas_view);
1984 */
1985 }
1986
1987 etl::loose_handle<Instance>
1988 App::get_instance(etl::handle<synfig::Canvas> canvas)
1989 {
1990         if(!canvas) return 0;
1991         canvas=canvas->get_root();
1992
1993         std::list<etl::handle<Instance> >::iterator iter;
1994         for(iter=instance_list.begin();iter!=instance_list.end();++iter)
1995         {
1996                 if((*iter)->get_canvas()==canvas)
1997                         return *iter;
1998         }
1999         return 0;
2000 }
2001
2002 void
2003 App::dialog_about()
2004 {
2005         (new class About())->show();
2006 }
2007
2008 void
2009 studio::App::undo()
2010 {
2011         if(selected_instance)
2012                 selected_instance->undo();
2013 }
2014
2015 void
2016 studio::App::redo()
2017 {
2018         if(selected_instance)
2019                 selected_instance->redo();
2020 }
2021
2022 synfig::String
2023 studio::App::get_base_path()
2024 {
2025         return app_base_path_;
2026 }