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