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