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