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