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