Remember separate default directories for opening and writing each of animations...
[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, std::string preference)
1539 {
1540         info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1541
1542 #ifdef USE_WIN32_FILE_DIALOGS
1543         static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1544
1545         GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1546         HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1547         HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1548
1549         ofn.lStructSize=sizeof(OPENFILENAME);
1550         ofn.hwndOwner = hWnd;
1551         ofn.hInstance = hInstance;
1552         ofn.lpstrFilter = szFilter;
1553 //      ofn.lpstrCustomFilter=NULL;
1554 //      ofn.nMaxCustFilter=0;
1555 //      ofn.nFilterIndex=0;
1556 //      ofn.lpstrFile=NULL;
1557         ofn.nMaxFile=MAX_PATH;
1558 //      ofn.lpstrFileTitle=NULL;
1559 //      ofn.lpstrInitialDir=NULL;
1560 //      ofn.lpstrTitle=NULL;
1561         ofn.Flags=OFN_HIDEREADONLY;
1562 //      ofn.nFileOffset=0;
1563 //      ofn.nFileExtension=0;
1564         ofn.lpstrDefExt=TEXT("sif");
1565 //      ofn.lCustData = 0l;
1566         ofn.lpfnHook=NULL;
1567 //      ofn.lpTemplateName=NULL;
1568
1569         CHAR szFilename[MAX_PATH];
1570         CHAR szTitle[500];
1571         strcpy(szFilename,filename.c_str());
1572         strcpy(szTitle,title.c_str());
1573
1574         ofn.lpstrFile=szFilename;
1575         ofn.lpstrFileTitle=szTitle;
1576
1577         if(GetOpenFileName(&ofn))
1578         {
1579                 filename=szFilename;
1580                 return true;
1581         }
1582         return false;
1583
1584 #else
1585         synfig::String prev_path;
1586
1587         if(!_preferences.get_value(preference, prev_path))
1588                 prev_path = ".";
1589
1590         prev_path = absolute_path(prev_path);
1591
1592     Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1593
1594     dialog->set_current_folder(prev_path);
1595     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1596     dialog->add_button(Gtk::Stock::OPEN,   Gtk::RESPONSE_ACCEPT);
1597
1598     if (filename.empty())
1599                 dialog->set_filename(prev_path);
1600         else if (is_absolute_path(filename))
1601                 dialog->set_filename(filename);
1602         else
1603                 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1604
1605     if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1606         filename = dialog->get_filename();
1607                 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1608                 _preferences.set_value(preference, dirname(filename));
1609         delete dialog;
1610         return true;
1611     }
1612
1613     delete dialog;
1614     return false;
1615
1616     /*
1617
1618         GtkWidget *ok;
1619         GtkWidget *cancel;
1620         int val=0;
1621
1622         GtkWidget *fileselection;
1623         fileselection = gtk_file_selection_new(title.c_str());
1624
1625
1626         if(basename(filename)==filename)
1627         {
1628                 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1629         }
1630         else
1631                 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1632
1633         gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1634
1635         ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1636         cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1637
1638         gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1639         gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1640
1641         gtk_widget_show(fileselection);
1642
1643         while(!val)
1644                 iteration();
1645
1646
1647         if(val==1)
1648         {
1649                 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1650                 _preferences.set_value(preference,dirname(filename));
1651         }
1652         else
1653         {
1654                 gtk_widget_destroy(fileselection);
1655                 return false;
1656         }
1657         gtk_widget_destroy(fileselection);
1658         return true;
1659     */
1660 #endif
1661 }
1662
1663 bool
1664 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1665 {
1666         info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1667
1668 #if USE_WIN32_FILE_DIALOGS
1669         static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1670
1671         GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1672         HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1673         HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1674
1675         ofn.lStructSize=sizeof(OPENFILENAME);
1676         ofn.hwndOwner = hWnd;
1677         ofn.hInstance = hInstance;
1678         ofn.lpstrFilter = szFilter;
1679 //      ofn.lpstrCustomFilter=NULL;
1680 //      ofn.nMaxCustFilter=0;
1681 //      ofn.nFilterIndex=0;
1682 //      ofn.lpstrFile=NULL;
1683         ofn.nMaxFile=MAX_PATH;
1684 //      ofn.lpstrFileTitle=NULL;
1685 //      ofn.lpstrInitialDir=NULL;
1686 //      ofn.lpstrTitle=NULL;
1687         ofn.Flags=OFN_OVERWRITEPROMPT;
1688 //      ofn.nFileOffset=0;
1689 //      ofn.nFileExtension=0;
1690         ofn.lpstrDefExt=TEXT("sif");
1691 //      ofn.lCustData = 0l;
1692         ofn.lpfnHook=NULL;
1693 //      ofn.lpTemplateName=NULL;
1694
1695         CHAR szFilename[MAX_PATH];
1696         CHAR szTitle[500];
1697         strcpy(szFilename,filename.c_str());
1698         strcpy(szTitle,title.c_str());
1699
1700         ofn.lpstrFile=szFilename;
1701         ofn.lpstrFileTitle=szTitle;
1702
1703         if(GetSaveFileName(&ofn))
1704         {
1705                 filename=szFilename;
1706                 _preferences.set_value(preference,dirname(filename));
1707                 return true;
1708         }
1709         return false;
1710 #else
1711         synfig::String prev_path;
1712
1713         if(!_preferences.get_value(preference, prev_path))
1714                 prev_path=".";
1715
1716         prev_path = absolute_path(prev_path);
1717
1718     Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1719
1720     dialog->set_current_folder(prev_path);
1721     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1722     dialog->add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_ACCEPT);
1723
1724     if (filename.empty())
1725                 dialog->set_filename(prev_path);
1726     else
1727         {
1728                 std::string full_path;
1729                 if (is_absolute_path(filename))
1730                         full_path = filename;
1731                 else
1732                         full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1733
1734                 // select the file if it exists
1735                 dialog->set_filename(full_path);
1736
1737                 // if the file doesn't exist, put its name into the filename box
1738                 struct stat s;
1739                 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1740                         dialog->set_current_name(basename(filename));
1741         }
1742
1743     if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1744         filename = dialog->get_filename();
1745                 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
1746                 _preferences.set_value(preference, dirname(filename));
1747         delete dialog;
1748         return true;
1749     }
1750
1751     delete dialog;
1752     return false;
1753 #endif
1754 }
1755
1756 void
1757 App::dialog_error_blocking(const std::string &title, const std::string &message)
1758 {
1759         Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1760         dialog.set_title(title);
1761         dialog.show();
1762         dialog.run();
1763 }
1764
1765 void
1766 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1767 {
1768         Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1769         dialog.set_title(title);
1770         dialog.show();
1771         dialog.run();
1772 }
1773
1774 bool
1775 App::dialog_yes_no(const std::string &title, const std::string &message)
1776 {
1777         Gtk::Dialog dialog(
1778                 title,          // Title
1779                 true,           // Modal
1780                 true            // use_separator
1781         );
1782         Gtk::Label label(message);
1783         label.show();
1784
1785         dialog.get_vbox()->pack_start(label);
1786         dialog.add_button(Gtk::StockID("gtk-yes"),1);
1787         dialog.add_button(Gtk::StockID("gtk-no"),0);
1788         dialog.show();
1789         return dialog.run();
1790 }
1791
1792 int
1793 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1794 {
1795         Gtk::Dialog dialog(
1796                 title,          // Title
1797                 true,           // Modal
1798                 true            // use_separator
1799         );
1800         Gtk::Label label(message);
1801         label.show();
1802
1803         dialog.get_vbox()->pack_start(label);
1804         dialog.add_button(Gtk::StockID("gtk-yes"),1);
1805         dialog.add_button(Gtk::StockID("gtk-no"),0);
1806         dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1807         dialog.show();
1808         return dialog.run();
1809 }
1810
1811 void
1812 App::dialog_not_implemented()
1813 {
1814         Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1815         dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
1816         dialog.run();
1817 }
1818
1819 bool
1820 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1821 {
1822         Gtk::Dialog dialog(
1823                 title,          // Title
1824                 true,           // Modal
1825                 true            // use_separator
1826         );
1827         Gtk::Label label(message);
1828         label.show();
1829         dialog.get_vbox()->pack_start(label);
1830
1831         Gtk::Entry entry;
1832         entry.set_text(text);
1833         entry.show();
1834         entry.set_activates_default(true);
1835         dialog.get_vbox()->pack_start(entry);
1836
1837         dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1838         dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1839         dialog.set_default_response(Gtk::RESPONSE_OK);
1840         entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1841         dialog.show();
1842
1843         if(dialog.run()!=Gtk::RESPONSE_OK)
1844                 return false;
1845
1846         text=entry.get_text();
1847
1848         return true;
1849 }
1850
1851
1852
1853
1854 bool
1855 App::open(std::string filename)
1856 {
1857         return open_as(filename,filename);
1858 }
1859
1860 // this is called from autorecover.cpp:
1861 //   App::open_as(get_shadow_file_name(filename),filename)
1862 // other than that, 'filename' and 'as' are the same
1863 bool
1864 App::open_as(std::string filename,std::string as)
1865 {
1866 #ifdef WIN32
1867     char long_name[1024];
1868     if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1869     as=long_name;
1870 #endif
1871
1872         try
1873         {
1874                 OneMoment one_moment;
1875
1876                 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1877                 if(canvas && get_instance(canvas))
1878                 {
1879                         get_instance(canvas)->find_canvas_view(canvas)->present();
1880                         throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1881                 }
1882                 if(!canvas)
1883                         throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
1884
1885                 add_recent_file(as);
1886
1887                 handle<Instance> instance(Instance::create(canvas));
1888
1889                 if(!instance)
1890                         throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
1891
1892                 one_moment.hide();
1893
1894                 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)")))
1895                         instance->dialog_cvs_update();
1896         }
1897         catch(String x)
1898         {
1899                 dialog_error_blocking(_("Error"), x);
1900                 return false;
1901         }
1902         catch(...)
1903         {
1904                 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
1905                 return false;
1906         }
1907
1908         return true;
1909 }
1910
1911
1912 void
1913 App::new_instance()
1914 {
1915         handle<synfig::Canvas> canvas=synfig::Canvas::create();
1916         canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1917
1918         String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1919
1920         canvas->rend_desc().set_frame_rate(24.0);
1921         canvas->rend_desc().set_time_start(0.0);
1922         canvas->rend_desc().set_time_end(00.0);
1923         canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
1924         canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
1925         canvas->rend_desc().set_tl(Vector(-4,2.25));
1926         canvas->rend_desc().set_br(Vector(4,-2.25));
1927         canvas->rend_desc().set_w(480);
1928         canvas->rend_desc().set_h(270);
1929         canvas->rend_desc().set_antialias(1);
1930         canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
1931         canvas->set_file_name(file_name);
1932
1933         handle<Instance> instance = Instance::create(canvas);
1934
1935         if (!getenv("SYNFIG_DISABLE_NEW_CANVAS_EDIT_PROPERTIES"))
1936                 instance->find_canvas_view(canvas)->canvas_properties.present();
1937 }
1938
1939 void
1940 App::dialog_open()
1941 {
1942         string filename="*.sif";
1943
1944         while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
1945         {
1946                 // If the filename still has wildcards, then we should
1947                 // continue looking for the file we want
1948                 if(find(filename.begin(),filename.end(),'*')!=filename.end())
1949                         continue;
1950
1951                 if(open(filename))
1952                         break;
1953
1954                 get_ui_interface()->error(_("Unable to open file"));
1955         }
1956 }
1957
1958 void
1959 App::set_selected_instance(etl::loose_handle<Instance> instance)
1960 {
1961 /*      if(get_selected_instance()==instance)
1962         {
1963                 selected_instance=instance;
1964                 signal_instance_selected()(instance);
1965                 return;
1966         }
1967         else
1968         {
1969 */
1970                 selected_instance=instance;
1971                 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
1972                 {
1973                         if(instance)
1974                         {
1975                                 instance->focus(instance->get_canvas());
1976                         }
1977                         else
1978                                 set_selected_canvas_view(0);
1979                 }
1980                 signal_instance_selected()(instance);
1981 }
1982
1983 void
1984 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
1985 {
1986         selected_canvas_view=canvas_view;
1987         signal_canvas_view_focus()(selected_canvas_view);
1988         if(canvas_view)
1989         {
1990                 selected_instance=canvas_view->get_instance();
1991                 signal_instance_selected()(canvas_view->get_instance());
1992         }
1993 /*
1994         if(get_selected_canvas_view()==canvas_view)
1995         {
1996                 signal_canvas_view_focus()(selected_canvas_view);
1997                 signal_instance_selected()(canvas_view->get_instance());
1998                 return;
1999         }
2000         selected_canvas_view=canvas_view;
2001         if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2002                 set_selected_instance(canvas_view->get_instance());
2003         signal_canvas_view_focus()(selected_canvas_view);
2004 */
2005 }
2006
2007 etl::loose_handle<Instance>
2008 App::get_instance(etl::handle<synfig::Canvas> canvas)
2009 {
2010         if(!canvas) return 0;
2011         canvas=canvas->get_root();
2012
2013         std::list<etl::handle<Instance> >::iterator iter;
2014         for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2015         {
2016                 if((*iter)->get_canvas()==canvas)
2017                         return *iter;
2018         }
2019         return 0;
2020 }
2021
2022 void
2023 App::dialog_about()
2024 {
2025         (new class About())->show();
2026 }
2027
2028 void
2029 studio::App::undo()
2030 {
2031         if(selected_instance)
2032                 selected_instance->undo();
2033 }
2034
2035 void
2036 studio::App::redo()
2037 {
2038         if(selected_instance)
2039                 selected_instance->redo();
2040 }
2041
2042 synfig::String
2043 studio::App::get_base_path()
2044 {
2045         return app_base_path_;
2046 }