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