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