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