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