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