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