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