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