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