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