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