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