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