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