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