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