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