Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-studio / tags / synfigstudio_0_61_05 / 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 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", "Mask 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", _("Mask Position Ducks"));
740         DEFINE_ACTION("mask-vertex-ducks", _("Mask Vertex Ducks"));
741         DEFINE_ACTION("mask-tangent-ducks", _("Mask Tangent Ducks"));
742         DEFINE_ACTION("mask-radius-ducks", _("Mask Radius Ducks"));
743         DEFINE_ACTION("mask-width-ducks", _("Mask Width Ducks"));
744         DEFINE_ACTION("mask-angle-ducks", _("Mask 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                 state_manager->add_state(&state_polygon);
1215                 state_manager->add_state(&state_circle);
1216                 state_manager->add_state(&state_rectangle);
1217
1218                 state_manager->add_state(&state_draw);
1219                 state_manager->add_state(&state_sketch);
1220
1221                 state_manager->add_state(&state_eyedrop);
1222                 state_manager->add_state(&state_fill);
1223                 
1224                 state_manager->add_state(&state_width);
1225                 state_manager->add_state(&state_gradient);
1226                 
1227                 state_manager->add_state(&state_zoom);
1228
1229                 studio_init_cb.task("Init ModPalette...");
1230                 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1231
1232                 studio_init_cb.task("Init ModMirror...");
1233                 module_list_.push_back(new ModMirror()); module_list_.back()->start();
1234
1235
1236                 studio_init_cb.task("Init Setup Dialog...");
1237                 dialog_setup=new studio::Dialog_Setup();
1238                 
1239                 studio_init_cb.task("Init Input Dialog...");
1240                 dialog_input=new Gtk::InputDialog();
1241
1242                 studio_init_cb.task("Init auto recovery...");
1243                 auto_recover=new AutoRecover();
1244
1245                 studio_init_cb.amount_complete(9250,10000);
1246                 studio_init_cb.task("Loading Settings...");
1247                 load_settings();
1248                 studio_init_cb.task("Checking auto-recover...");
1249         
1250                 studio_init_cb.amount_complete(9900,10000);
1251         
1252                 if(auto_recover->recovery_needed())
1253                 {
1254                         about_window.hide();
1255                         if(
1256                                 get_ui_interface()->yes_no(
1257                                         "Auto Recovery",
1258                                         "SYNFIG Studio seems to have crashed\n"
1259                                         "before you could save all your files.\n"
1260                                         "Would you like to re-open those files\n"
1261                                         "and recover your unsaved changes?"
1262                                 )==synfigapp::UIInterface::RESPONSE_YES
1263                         )
1264                         {
1265                                 if(!auto_recover->recover())
1266                                 {
1267                                         get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1268                                 }
1269                                 else
1270                                 get_ui_interface()->error(
1271                                         _("SYNFIG Studio has attempted to recover\n"
1272                                         "from a previous crash. The files that it has\n"
1273                                         "recovered are NOT YET SAVED. It would be a good\n"
1274                                         "idea to review them and save them now.")
1275                                 );
1276                         }
1277                         about_window.show();
1278                 }
1279                 
1280                 // Look for any files given on the command line,
1281                 // and load them if found.
1282                 for(;*argc>=1;(*argc)--)
1283                         if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1284                         {
1285                                 studio_init_cb.task("Loading files...");
1286                                 about_window.hide();
1287                                 open((*argv)[*argc]);
1288                                 about_window.show();
1289                         }
1290                 
1291                 studio_init_cb.task("Done.");
1292                 studio_init_cb.amount_complete(10000,10000);
1293         
1294                 toolbox->present();
1295         }
1296         catch(...)
1297         {
1298                 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1299         }
1300 }
1301
1302 StateManager* App::get_state_manager() { return state_manager; }
1303
1304 App::~App()
1305 {
1306         shutdown_in_progress=true;
1307
1308         save_settings();
1309
1310         synfigapp::Main::settings().remove_domain("pref");
1311         
1312         selected_instance=0;
1313
1314         // Unload all of the modules
1315         for(;!module_list_.empty();module_list_.pop_back());
1316         
1317         delete state_manager;
1318
1319         delete ipc;
1320         
1321         delete auto_recover;
1322
1323         toolbox->hide();
1324
1325 //      studio::App::iteration(false); 
1326         
1327         delete toolbox;
1328         
1329 //      studio::App::iteration(false); 
1330
1331 //      studio::App::iteration(false); 
1332
1333         delete dialog_setup;
1334
1335         delete dialog_gradient;
1336
1337         delete dialog_color;
1338
1339         delete dialog_input;
1340
1341         delete dock_manager;
1342
1343         instance_list.clear();
1344
1345 //      studio::App::iteration(false);
1346 }
1347
1348 String
1349 App::get_user_app_directory()
1350 {
1351         return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1352 }
1353
1354 synfig::String
1355 App::get_config_file(const synfig::String& file)
1356 {
1357         return Glib::build_filename(get_user_app_directory(),file);
1358 }
1359
1360 void
1361 App::add_recent_file(const std::string &file_name)
1362 {
1363         std::string filename(file_name);
1364
1365         assert(!filename.empty());
1366         
1367         if(filename.empty())
1368                 return;
1369         
1370         // Toss out any "hidden" files
1371         if(basename(filename)[0]=='.')
1372                 return;
1373                 
1374         // If we aren't an absolute path, turn outselves into one
1375         if(!is_absolute_path(filename))
1376                 filename=absolute_path(filename);
1377         
1378         list<string>::iterator iter;
1379         // Check to see if the file is already on the list.
1380         // If it is, then remove it from the list
1381         for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1382                 if(*iter==filename)
1383                 {
1384                         recent_files.erase(iter);
1385                         break;
1386                 }
1387
1388         
1389         // Push the filename to the front of the list
1390         recent_files.push_front(filename);
1391                 
1392         // Clean out the files at the end of the list.
1393         while(recent_files.size()>(unsigned)get_max_recent_files())
1394                 recent_files.pop_back();
1395         
1396         signal_recent_files_changed_();
1397         
1398         return;
1399 }
1400
1401 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1402
1403 Time::Format
1404 App::get_time_format()
1405 {
1406         return _App_time_format;
1407 }
1408
1409 void
1410 App::set_time_format(synfig::Time::Format x)
1411 {
1412         _App_time_format=x;
1413 }
1414
1415
1416 void
1417 App::save_settings()
1418 {
1419         try
1420         {
1421                 {
1422                         std::string filename=get_config_file("accelrc");
1423                         Gtk::AccelMap::save(filename);
1424                 }
1425                 do{
1426                         std::string filename=get_config_file("recentfiles");
1427
1428                         std::ofstream file(filename.c_str());
1429                 
1430                         if(!file)
1431                         {
1432                                 synfig::warning("Unable to save %s",filename.c_str());
1433                                 break;
1434                         }
1435                 
1436                         list<string>::reverse_iterator iter;
1437         
1438                         for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1439                                 file<<*iter<<endl;
1440                 }while(0);
1441
1442                 std::string filename=get_config_file("settings");
1443                 synfigapp::Main::settings().save_to_file(filename);
1444         }
1445         catch(...)
1446         {
1447                 synfig::warning("Caught exception when attempting to save settings.");
1448         }
1449 }
1450
1451 void
1452 App::load_settings()
1453 {
1454         try
1455         {
1456                 {
1457                         std::string filename=get_config_file("accelrc");
1458                         Gtk::AccelMap::load(filename);
1459                 }
1460                 {
1461                         std::string filename=get_config_file("recentfiles");
1462
1463                         std::ifstream file(filename.c_str());
1464         
1465                         while(file)
1466                         {
1467                                 std::string recent_file;
1468                                 getline(file,recent_file);
1469                                 if(!recent_file.empty())
1470                                         add_recent_file(recent_file);
1471                         }
1472                 }
1473                 std::string filename=get_config_file("settings");
1474                 if(!synfigapp::Main::settings().load_from_file(filename))
1475                 {
1476                         //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1477                         //if(!synfigapp::Main::settings().load_from_file(filename))
1478                         {
1479                                 gamma.set_gamma(1.0/2.2);
1480                                 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1481                                 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1482                                 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1483                                 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1484                                 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1485                                 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1486                                 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1487                                 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1488                                 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1489                                 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1490                                 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1491                                 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1492                                 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1493                         }
1494                 }
1495                 
1496         }
1497         catch(...)
1498         {
1499                 synfig::warning("Caught exception when attempting to load settings.");
1500         }
1501 }
1502
1503 bool
1504 App::shutdown_request(GdkEventAny*)
1505 {
1506         quit();
1507         return true;
1508         //return !shutdown_in_progress;
1509 }
1510
1511 void
1512 App::quit()
1513 {
1514         if(shutdown_in_progress)return;
1515                 
1516         
1517         get_ui_interface()->task("Quit Request");
1518         if(Busy::count)
1519         {
1520                 dialog_error_blocking("Cannot quit!","Tasks are currently running.\nPlease cancel the current tasks and try again");
1521                 return;
1522         }
1523
1524         std::list<etl::handle<Instance> >::iterator iter;
1525         for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1526         {
1527                 if(!(*iter)->safe_close())
1528                         return;
1529
1530 /*
1531                 if((*iter)->synfigapp::Instance::get_action_count())
1532                 {
1533                         handle<synfigapp::UIInterface> uim;
1534                         uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1535                         assert(uim);
1536                         string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1537                         switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1538                         {
1539                                 case synfigapp::UIInterface::RESPONSE_NO:
1540                                         break;
1541                                 case synfigapp::UIInterface::RESPONSE_YES:
1542                                         (*iter)->save();
1543                                         break;
1544                                 case synfigapp::UIInterface::RESPONSE_CANCEL:
1545                                         return;
1546                                 default:
1547                                         assert(0);
1548                                         return;
1549                         }
1550                 }
1551
1552
1553                 if((*iter)->synfigapp::Instance::is_modified())
1554                 {
1555                         handle<synfigapp::UIInterface> uim;
1556                         uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1557                         assert(uim);
1558                         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() );
1559                         switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1560                         {
1561                                 case synfigapp::UIInterface::RESPONSE_NO:
1562                                         break;
1563                                 case synfigapp::UIInterface::RESPONSE_YES:
1564                                         (*iter)->dialog_cvs_commit();
1565                                         break;
1566                                 case synfigapp::UIInterface::RESPONSE_CANCEL:
1567                                         return;
1568                                 default:
1569                                         assert(0);
1570                                         return;
1571                         }
1572                 }
1573 */              
1574                 
1575                 // This next line causes things to crash for some reason
1576                 //(*iter)->close(); 
1577         }
1578         
1579         shutdown_in_progress=true;
1580
1581         instance_list.clear();
1582
1583         while(studio::App::events_pending())studio::App::iteration(false);
1584                 
1585         Gtk::Main::quit();
1586         auto_recover->normal_shutdown();
1587
1588         get_ui_interface()->task("Quit Request sent");
1589 }
1590
1591 void
1592 App::show_setup()
1593 {
1594         dialog_setup->refresh();
1595         dialog_setup->show();
1596 }
1597
1598 gint Signal_Open_Ok(GtkWidget *widget, int *val){*val=1;return 0;}
1599 gint Signal_Open_Cancel(GtkWidget *widget, int *val){*val=2;return 0;}
1600
1601 //#ifdef WIN32
1602 //#define USE_WIN32_FILE_DIALOGS 1
1603 //#endif
1604
1605 #ifdef USE_WIN32_FILE_DIALOGS
1606 static OPENFILENAME ofn={};
1607 #endif
1608
1609 #ifdef WIN32
1610 #include <gdk/gdkwin32.h>
1611 #endif
1612         
1613 bool
1614 App::dialog_open_file(const std::string &title, std::string &filename)
1615 {
1616 #ifdef USE_WIN32_FILE_DIALOGS
1617         static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1618
1619         GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1620         HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1621         HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1622         
1623         ofn.lStructSize=sizeof(OPENFILENAME);
1624         ofn.hwndOwner = hWnd;
1625         ofn.hInstance = hInstance;
1626         ofn.lpstrFilter = szFilter;
1627 //      ofn.lpstrCustomFilter=NULL;
1628 //      ofn.nMaxCustFilter=0;
1629 //      ofn.nFilterIndex=0;
1630 //      ofn.lpstrFile=NULL;
1631         ofn.nMaxFile=MAX_PATH;
1632 //      ofn.lpstrFileTitle=NULL;
1633 //      ofn.lpstrInitialDir=NULL;
1634 //      ofn.lpstrTitle=NULL;
1635         ofn.Flags=OFN_HIDEREADONLY;
1636 //      ofn.nFileOffset=0;
1637 //      ofn.nFileExtension=0;
1638         ofn.lpstrDefExt=TEXT("sif");
1639 //      ofn.lCustData = 0l;
1640         ofn.lpfnHook=NULL;
1641 //      ofn.lpTemplateName=NULL;
1642         
1643         CHAR szFilename[MAX_PATH];
1644         CHAR szTitle[500];
1645         strcpy(szFilename,filename.c_str());
1646         strcpy(szTitle,title.c_str());
1647         
1648         ofn.lpstrFile=szFilename;
1649         ofn.lpstrFileTitle=szTitle;
1650         
1651         if(GetOpenFileName(&ofn))
1652         {
1653                 filename=szFilename;
1654                 return true;
1655         }
1656         return false;
1657         
1658 #else
1659         synfig::String prev_path;
1660         if(!_preferences.get_value("curr_path",prev_path))
1661                 prev_path=".";
1662         
1663     Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_OPEN);
1664     dialog->set_current_folder(prev_path);
1665     dialog->add_button(Gtk::StockID("gtk-ok"),GTK_RESPONSE_ACCEPT);
1666     dialog->add_button(Gtk::StockID("gtk-cancel"),GTK_RESPONSE_CANCEL);
1667     if(!filename.empty())
1668         dialog->set_filename(filename);
1669     if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1670         filename=dialog->get_filename();
1671         delete dialog;
1672         return true;
1673     }
1674     delete dialog;
1675     return false;
1676     /*
1677     
1678         GtkWidget *ok;
1679         GtkWidget *cancel;
1680         int val=0;
1681         
1682         GtkWidget *fileselection;
1683         fileselection = gtk_file_selection_new(title.c_str());
1684
1685         
1686         if(basename(filename)==filename)
1687         {
1688                 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPERATOR).c_str());         
1689         }
1690         else
1691                 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1692
1693         gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1694
1695         ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1696         cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1697
1698         gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);              
1699         gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);              
1700
1701         gtk_widget_show(fileselection);
1702
1703         while(!val)
1704                 iteration();            
1705         
1706         
1707         if(val==1)
1708         {
1709                 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1710                 _preferences.set_value("curr_path",dirname(filename));
1711         }
1712         else
1713         {
1714                 gtk_widget_destroy(fileselection);
1715                 return false;
1716         }
1717         gtk_widget_destroy(fileselection);
1718         return true;
1719     */
1720 #endif
1721 }
1722
1723 bool
1724 App::dialog_save_file(const std::string &title, std::string &filename)
1725 {
1726 #ifdef USE_WIN32_FILE_DIALOGS
1727         static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1728         
1729         GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1730         HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1731         HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1732         
1733         ofn.lStructSize=sizeof(OPENFILENAME);
1734         ofn.hwndOwner = hWnd;
1735         ofn.hInstance = hInstance;
1736         ofn.lpstrFilter = szFilter;
1737 //      ofn.lpstrCustomFilter=NULL;
1738 //      ofn.nMaxCustFilter=0;
1739 //      ofn.nFilterIndex=0;
1740 //      ofn.lpstrFile=NULL;
1741         ofn.nMaxFile=MAX_PATH;
1742 //      ofn.lpstrFileTitle=NULL;
1743 //      ofn.lpstrInitialDir=NULL;
1744 //      ofn.lpstrTitle=NULL;
1745         ofn.Flags=OFN_OVERWRITEPROMPT;
1746 //      ofn.nFileOffset=0;
1747 //      ofn.nFileExtension=0;
1748         ofn.lpstrDefExt=TEXT("sif");
1749 //      ofn.lCustData = 0l;
1750         ofn.lpfnHook=NULL;
1751 //      ofn.lpTemplateName=NULL;
1752         
1753         CHAR szFilename[MAX_PATH];
1754         CHAR szTitle[500];
1755         strcpy(szFilename,filename.c_str());
1756         strcpy(szTitle,title.c_str());
1757         
1758         ofn.lpstrFile=szFilename;
1759         ofn.lpstrFileTitle=szTitle;
1760         
1761         if(GetSaveFileName(&ofn))
1762         {
1763                 filename=szFilename;
1764                 return true;
1765         }
1766         return false;
1767 #else
1768         synfig::String prev_path;
1769         if(!_preferences.get_value("curr_path",prev_path))
1770                 prev_path=".";
1771         
1772     Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
1773     dialog->set_current_folder(prev_path);
1774     dialog->add_button(Gtk::StockID("gtk-ok"),GTK_RESPONSE_ACCEPT);
1775     dialog->add_button(Gtk::StockID("gtk-cancel"),GTK_RESPONSE_CANCEL);
1776     if(!filename.empty())
1777         dialog->set_filename(filename);
1778     if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1779         filename=dialog->get_filename();
1780         delete dialog;
1781         return true;
1782     }
1783     delete dialog;
1784     return false;
1785 //      return dialog_open_file(title, filename);
1786 #endif
1787 }
1788
1789 bool
1790 App::dialog_saveas_file(const std::string &title, std::string &filename)
1791 {
1792 #if USE_WIN32_FILE_DIALOGS
1793         static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1794         
1795         GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1796         HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1797         HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1798         
1799         ofn.lStructSize=sizeof(OPENFILENAME);
1800         ofn.hwndOwner = hWnd;
1801         ofn.hInstance = hInstance;
1802         ofn.lpstrFilter = szFilter;
1803 //      ofn.lpstrCustomFilter=NULL;
1804 //      ofn.nMaxCustFilter=0;
1805 //      ofn.nFilterIndex=0;
1806 //      ofn.lpstrFile=NULL;
1807         ofn.nMaxFile=MAX_PATH;
1808 //      ofn.lpstrFileTitle=NULL;
1809 //      ofn.lpstrInitialDir=NULL;
1810 //      ofn.lpstrTitle=NULL;
1811         ofn.Flags=OFN_OVERWRITEPROMPT;
1812 //      ofn.nFileOffset=0;
1813 //      ofn.nFileExtension=0;
1814         ofn.lpstrDefExt=TEXT("sif");
1815 //      ofn.lCustData = 0l;
1816         ofn.lpfnHook=NULL;
1817 //      ofn.lpTemplateName=NULL;
1818         
1819         CHAR szFilename[MAX_PATH];
1820         CHAR szTitle[500];
1821         strcpy(szFilename,filename.c_str());
1822         strcpy(szTitle,title.c_str());
1823         
1824         ofn.lpstrFile=szFilename;
1825         ofn.lpstrFileTitle=szTitle;
1826         
1827         if(GetSaveFileName(&ofn))
1828         {
1829                 filename=szFilename;
1830                 return true;
1831         }
1832         return false;
1833 #else
1834         synfig::String prev_path;
1835         if(!_preferences.get_value("curr_path",prev_path))
1836                 prev_path=".";
1837         
1838     Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
1839     dialog->set_current_folder(prev_path);
1840     dialog->add_button(Gtk::StockID("gtk-ok"),GTK_RESPONSE_ACCEPT);
1841     dialog->add_button(Gtk::StockID("gtk-cancel"),GTK_RESPONSE_CANCEL);
1842     if(!filename.empty())
1843         dialog->set_filename(filename);
1844     if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1845         filename=dialog->get_filename();
1846         delete dialog;
1847         return true;
1848     }
1849     delete dialog;
1850     return false;
1851 //      return dialog_open_file(title, filename);
1852 #endif
1853 }
1854
1855 void
1856 App::dialog_error_blocking(const std::string &title, const std::string &message)
1857 {
1858         Gtk::Dialog dialog(
1859                 title,          // Title
1860                 true,           // Modal
1861                 true            // use_separator
1862         );
1863         Gtk::Label label(message);
1864         label.show();
1865         
1866         dialog.get_vbox()->pack_start(label);
1867         dialog.add_button(Gtk::StockID("gtk-ok"),1);
1868         dialog.show();
1869         dialog.run();
1870 }
1871
1872 void
1873 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1874 {
1875         Gtk::Dialog dialog(
1876                 title,          // Title
1877                 true,           // Modal
1878                 true            // use_separator
1879         );
1880         Gtk::Label label(message);
1881         label.show();
1882
1883         dialog.get_vbox()->pack_start(label);
1884         dialog.add_button(Gtk::StockID("gtk-ok"),1);
1885         dialog.show();
1886         dialog.run();
1887 }
1888
1889 bool
1890 App::dialog_yes_no(const std::string &title, const std::string &message)
1891 {
1892         Gtk::Dialog dialog(
1893                 title,          // Title
1894                 true,           // Modal
1895                 true            // use_separator
1896         );
1897         Gtk::Label label(message);
1898         label.show();
1899         
1900         dialog.get_vbox()->pack_start(label);
1901         dialog.add_button(Gtk::StockID("gtk-yes"),1);
1902         dialog.add_button(Gtk::StockID("gtk-no"),0);
1903         dialog.show();
1904         return dialog.run();
1905 }
1906
1907 int
1908 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1909 {
1910         Gtk::Dialog dialog(
1911                 title,          // Title
1912                 true,           // Modal
1913                 true            // use_separator
1914         );
1915         Gtk::Label label(message);
1916         label.show();
1917
1918         dialog.get_vbox()->pack_start(label);
1919         dialog.add_button(Gtk::StockID("gtk-yes"),1);
1920         dialog.add_button(Gtk::StockID("gtk-no"),0);
1921         dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1922         dialog.show();
1923         return dialog.run();
1924 }
1925
1926 void
1927 App::dialog_not_implemented()
1928 {
1929         Gtk::Dialog dialog(
1930                 "Feature not available",                // Title
1931                 true,           // Modal
1932                 true            // use_separator
1933         );
1934         Gtk::Label label("Sorry, this feature has not yet been implemented.");
1935         label.show();
1936         
1937         dialog.get_vbox()->pack_start(label);
1938         dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1939         dialog.show();
1940         dialog.run();
1941 }
1942
1943 bool
1944 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1945 {
1946         Gtk::Dialog dialog(
1947                 title,          // Title
1948                 true,           // Modal
1949                 true            // use_separator
1950         );
1951         Gtk::Label label(message);
1952         label.show();
1953         dialog.get_vbox()->pack_start(label);
1954
1955         Gtk::Entry entry;
1956         entry.set_text(text);
1957         entry.show();
1958         entry.set_activates_default(true);
1959         dialog.get_vbox()->pack_start(entry);
1960
1961         dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1962         dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1963         dialog.set_default_response(Gtk::RESPONSE_OK);
1964         entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1965         dialog.show();
1966
1967         if(dialog.run()!=Gtk::RESPONSE_OK)
1968                 return false;
1969
1970         text=entry.get_text();
1971
1972         return true;
1973 }
1974
1975
1976
1977
1978 bool
1979 App::open(std::string filename)
1980 {
1981         return open_as(filename,filename);
1982 }
1983
1984 bool
1985 App::open_as(std::string filename,std::string as)
1986 {
1987 #ifdef WIN32
1988     char long_name[1024];
1989     if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1990     as=long_name;
1991 #endif
1992
1993         try
1994         {
1995                 OneMoment one_moment;
1996         
1997                 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1998                 if(canvas && get_instance(canvas))
1999                 {
2000                         get_instance(canvas)->find_canvas_view(canvas)->present();
2001                         throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());              
2002                 }
2003                 if(!canvas)
2004                         throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2005
2006                 add_recent_file(as);
2007                 
2008                 handle<Instance> instance(Instance::create(canvas));
2009
2010                 if(!instance)
2011                         throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2012                 
2013                 one_moment.hide();
2014                 
2015                 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)")))
2016                         instance->dialog_cvs_update();
2017         }
2018         catch(String x)
2019         {
2020                 dialog_error_blocking(_("Error"), x);
2021                 return false;
2022         }
2023         catch(...)
2024         {
2025                 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2026                 return false;
2027         }
2028
2029         _preferences.set_value("curr_path",dirname(as));
2030         
2031         return true;
2032 }
2033
2034
2035 void
2036 App::new_instance()
2037 {
2038         handle<synfig::Canvas> canvas=synfig::Canvas::create();
2039         canvas->set_name(strprintf("Untitled%d",Instance::get_count()));
2040
2041         String file_name(strprintf("untitled%d.sif",Instance::get_count()));
2042         
2043         canvas->rend_desc().set_frame_rate(24.0);
2044         canvas->rend_desc().set_time_start(0.0);
2045         canvas->rend_desc().set_time_end(00.0);
2046         canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2047         canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2048         canvas->rend_desc().set_tl(Vector(-4,2.25));
2049         canvas->rend_desc().set_br(Vector(4,-2.25));
2050         canvas->rend_desc().set_w(480);
2051         canvas->rend_desc().set_h(270);
2052         canvas->rend_desc().set_antialias(1);
2053         canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2054         canvas->set_file_name(file_name);
2055         
2056         Instance::create(canvas)->find_canvas_view(canvas)->canvas_properties.present();
2057 }
2058
2059 void
2060 App::dialog_open()
2061 {
2062         string filename="*.sif";
2063
2064         while(dialog_open_file("Open", filename))
2065         {
2066                 // If the filename still has wildcards, then we should
2067                 // continue looking for the file we want
2068                 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2069                         continue;
2070
2071                 if(open(filename))
2072                         break;
2073
2074                 get_ui_interface()->error(_("Unable to open file"));
2075         }
2076 }
2077
2078 void
2079 App::set_selected_instance(etl::loose_handle<Instance> instance)
2080 {
2081 /*      if(get_selected_instance()==instance)
2082         {
2083                 selected_instance=instance;
2084                 signal_instance_selected()(instance);
2085                 return;
2086         }
2087         else
2088         {
2089 */
2090                 selected_instance=instance;
2091                 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2092                 {
2093                         if(instance)
2094                         {
2095                                 instance->focus(instance->get_canvas());
2096                         }
2097                         else
2098                                 set_selected_canvas_view(0);
2099                 }
2100                 signal_instance_selected()(instance);
2101 }
2102
2103 void
2104 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2105 {
2106         selected_canvas_view=canvas_view;
2107         signal_canvas_view_focus()(selected_canvas_view);
2108         if(canvas_view)
2109         {
2110                 selected_instance=canvas_view->get_instance();
2111                 signal_instance_selected()(canvas_view->get_instance());
2112         }
2113 /*
2114         if(get_selected_canvas_view()==canvas_view)
2115         {
2116                 signal_canvas_view_focus()(selected_canvas_view);
2117                 signal_instance_selected()(canvas_view->get_instance());
2118                 return;
2119         }
2120         selected_canvas_view=canvas_view;
2121         if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2122                 set_selected_instance(canvas_view->get_instance());
2123         signal_canvas_view_focus()(selected_canvas_view);
2124 */
2125 }
2126
2127 etl::loose_handle<Instance>
2128 App::get_instance(Canvas::Handle canvas)
2129 {
2130         if(!canvas) return 0;
2131         canvas=canvas->get_root();
2132
2133         std::list<etl::handle<Instance> >::iterator iter;
2134         for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2135         {
2136                 if((*iter)->get_canvas()==canvas)
2137                         return *iter;
2138         }
2139         return 0;
2140 }
2141
2142 void
2143 App::dialog_about()
2144 {
2145         (new class About())->show();
2146 }
2147
2148 void
2149 studio::App::undo()
2150 {
2151         if(selected_instance)
2152                 selected_instance->undo();
2153 }
2154
2155 void
2156 studio::App::redo()
2157 {
2158         if(selected_instance)
2159                 selected_instance->redo();
2160 }
2161
2162 synfig::String
2163 studio::App::get_base_path()
2164 {
2165         return app_base_path_;
2166 }