Switch from Ok, Cancel to Cancel, Open and Cancel, Save in the GTK based Open and...
[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                 // Disabled this tool because it should be
1243                 // considered deprecated. Use the bline tool instead.
1244                 if(getenv("SYNFIG_ENABLE_POLYGON")) state_manager->add_state(&state_polygon);
1245
1246                 // These tools are disabled by default for now,
1247                 // because they tend to confuse users.
1248                 if(getenv("SYNFIG_ENABLE_DRAW"  )) state_manager->add_state(&state_draw);
1249                 if(getenv("SYNFIG_ENABLE_SKETCH")) state_manager->add_state(&state_sketch);
1250                 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1251
1252                 studio_init_cb.task("Init ModPalette...");
1253                 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1254
1255                 studio_init_cb.task("Init ModMirror...");
1256                 module_list_.push_back(new ModMirror()); module_list_.back()->start();
1257
1258
1259                 studio_init_cb.task("Init Setup Dialog...");
1260                 dialog_setup=new studio::Dialog_Setup();
1261
1262                 studio_init_cb.task("Init Input Dialog...");
1263                 dialog_input=new Gtk::InputDialog();
1264                 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1265                 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1266
1267                 studio_init_cb.task("Init auto recovery...");
1268                 auto_recover=new AutoRecover();
1269
1270                 studio_init_cb.amount_complete(9250,10000);
1271                 studio_init_cb.task("Loading Settings...");
1272                 load_settings();
1273                 studio_init_cb.task("Checking auto-recover...");
1274
1275                 studio_init_cb.amount_complete(9900,10000);
1276
1277                 if(auto_recover->recovery_needed())
1278                 {
1279                         about_window.hide();
1280                         if(
1281                                 get_ui_interface()->yes_no(
1282                                         "Auto Recovery",
1283                                         "Synfig Studio seems to have crashed\n"
1284                                         "before you could save all your files.\n"
1285                                         "Would you like to re-open those files\n"
1286                                         "and recover your unsaved changes?"
1287                                 )==synfigapp::UIInterface::RESPONSE_YES
1288                         )
1289                         {
1290                                 if(!auto_recover->recover())
1291                                 {
1292                                         get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1293                                 }
1294                                 else
1295                                 get_ui_interface()->error(
1296                                         _("Synfig Studio has attempted to recover\n"
1297                                         "from a previous crash. The files that it has\n"
1298                                         "recovered are NOT YET SAVED. It would be a good\n"
1299                                         "idea to review them and save them now.")
1300                                 );
1301                         }
1302                         about_window.show();
1303                 }
1304
1305                 // Look for any files given on the command line,
1306                 // and load them if found.
1307                 for(;*argc>=1;(*argc)--)
1308                         if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1309                         {
1310                                 studio_init_cb.task("Loading files...");
1311                                 about_window.hide();
1312                                 open((*argv)[*argc]);
1313                                 about_window.show();
1314                         }
1315
1316                 studio_init_cb.task("Done.");
1317                 studio_init_cb.amount_complete(10000,10000);
1318
1319                 toolbox->present();
1320         }
1321         catch(...)
1322         {
1323                 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1324         }
1325 }
1326
1327 StateManager* App::get_state_manager() { return state_manager; }
1328
1329 App::~App()
1330 {
1331         shutdown_in_progress=true;
1332
1333         save_settings();
1334
1335         synfigapp::Main::settings().remove_domain("pref");
1336
1337         selected_instance=0;
1338
1339         // Unload all of the modules
1340         for(;!module_list_.empty();module_list_.pop_back());
1341
1342         delete state_manager;
1343
1344         delete ipc;
1345
1346         delete auto_recover;
1347
1348         toolbox->hide();
1349
1350 //      studio::App::iteration(false);
1351
1352         delete toolbox;
1353
1354 //      studio::App::iteration(false);
1355
1356 //      studio::App::iteration(false);
1357
1358         delete dialog_setup;
1359
1360         delete dialog_gradient;
1361
1362         delete dialog_color;
1363
1364         delete dialog_input;
1365
1366         delete dock_manager;
1367
1368         instance_list.clear();
1369
1370 //      studio::App::iteration(false);
1371 }
1372
1373 String
1374 App::get_user_app_directory()
1375 {
1376         return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1377 }
1378
1379 synfig::String
1380 App::get_config_file(const synfig::String& file)
1381 {
1382         return Glib::build_filename(get_user_app_directory(),file);
1383 }
1384
1385 void
1386 App::add_recent_file(const std::string &file_name)
1387 {
1388         std::string filename(file_name);
1389
1390         assert(!filename.empty());
1391
1392         if(filename.empty())
1393                 return;
1394
1395         // Toss out any "hidden" files
1396         if(basename(filename)[0]=='.')
1397                 return;
1398
1399         // If we aren't an absolute path, turn outselves into one
1400         if(!is_absolute_path(filename))
1401                 filename=absolute_path(filename);
1402
1403         list<string>::iterator iter;
1404         // Check to see if the file is already on the list.
1405         // If it is, then remove it from the list
1406         for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1407                 if(*iter==filename)
1408                 {
1409                         recent_files.erase(iter);
1410                         break;
1411                 }
1412
1413
1414         // Push the filename to the front of the list
1415         recent_files.push_front(filename);
1416
1417         // Clean out the files at the end of the list.
1418         while(recent_files.size()>(unsigned)get_max_recent_files())
1419                 recent_files.pop_back();
1420
1421         signal_recent_files_changed_();
1422
1423         return;
1424 }
1425
1426 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1427
1428 Time::Format
1429 App::get_time_format()
1430 {
1431         return _App_time_format;
1432 }
1433
1434 void
1435 App::set_time_format(synfig::Time::Format x)
1436 {
1437         _App_time_format=x;
1438 }
1439
1440
1441 void
1442 App::save_settings()
1443 {
1444         char * old_locale;
1445         try
1446         {
1447         old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1448         setlocale(LC_NUMERIC, "C");
1449                 {
1450                         std::string filename=get_config_file("accelrc");
1451                         Gtk::AccelMap::save(filename);
1452                 }
1453                 do{
1454                         std::string filename=get_config_file("recentfiles");
1455
1456                         std::ofstream file(filename.c_str());
1457
1458                         if(!file)
1459                         {
1460                                 synfig::warning("Unable to save %s",filename.c_str());
1461                                 break;
1462                         }
1463
1464                         list<string>::reverse_iterator iter;
1465
1466                         for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1467                                 file<<*iter<<endl;
1468                 }while(0);
1469
1470                 std::string filename=get_config_file("settings");
1471                 synfigapp::Main::settings().save_to_file(filename);
1472         setlocale(LC_NUMERIC,old_locale);
1473         }
1474         catch(...)
1475         {
1476                 synfig::warning("Caught exception when attempting to save settings.");
1477         }
1478 }
1479
1480 void
1481 App::load_settings()
1482 {
1483         char  * old_locale;
1484         try
1485         {
1486         old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1487         setlocale(LC_NUMERIC, "C");
1488                 {
1489                         std::string filename=get_config_file("accelrc");
1490                         Gtk::AccelMap::load(filename);
1491                 }
1492                 {
1493                         std::string filename=get_config_file("recentfiles");
1494
1495                         std::ifstream file(filename.c_str());
1496
1497                         while(file)
1498                         {
1499                                 std::string recent_file;
1500                                 getline(file,recent_file);
1501                                 if(!recent_file.empty())
1502                                         add_recent_file(recent_file);
1503                         }
1504                 }
1505                 std::string filename=get_config_file("settings");
1506                 if(!synfigapp::Main::settings().load_from_file(filename))
1507                 {
1508                         //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1509                         //if(!synfigapp::Main::settings().load_from_file(filename))
1510                         {
1511                                 gamma.set_gamma(1.0/2.2);
1512                                 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1513                                 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1514                                 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1515                                 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1516                                 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1517                                 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1518                                 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1519                                 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1520                                 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1521                                 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1522                                 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1523                                 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1524                                 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1525                         }
1526                 }
1527         setlocale(LC_NUMERIC,old_locale);
1528         }
1529         catch(...)
1530         {
1531                 synfig::warning("Caught exception when attempting to load settings.");
1532         }
1533 }
1534
1535 bool
1536 App::shutdown_request(GdkEventAny*)
1537 {
1538         quit();
1539         return true;
1540         //return !shutdown_in_progress;
1541 }
1542
1543 void
1544 App::quit()
1545 {
1546         if(shutdown_in_progress)return;
1547
1548
1549         get_ui_interface()->task("Quit Request");
1550         if(Busy::count)
1551         {
1552                 dialog_error_blocking("Cannot quit!","Tasks are currently running.\nPlease cancel the current tasks and try again");
1553                 return;
1554         }
1555
1556         std::list<etl::handle<Instance> >::iterator iter;
1557         for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1558         {
1559                 if(!(*iter)->safe_close())
1560                         return;
1561
1562 /*
1563                 if((*iter)->synfigapp::Instance::get_action_count())
1564                 {
1565                         handle<synfigapp::UIInterface> uim;
1566                         uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1567                         assert(uim);
1568                         string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1569                         switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1570                         {
1571                                 case synfigapp::UIInterface::RESPONSE_NO:
1572                                         break;
1573                                 case synfigapp::UIInterface::RESPONSE_YES:
1574                                         (*iter)->save();
1575                                         break;
1576                                 case synfigapp::UIInterface::RESPONSE_CANCEL:
1577                                         return;
1578                                 default:
1579                                         assert(0);
1580                                         return;
1581                         }
1582                 }
1583
1584
1585                 if((*iter)->synfigapp::Instance::is_modified())
1586                 {
1587                         handle<synfigapp::UIInterface> uim;
1588                         uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1589                         assert(uim);
1590                         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() );
1591                         switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1592                         {
1593                                 case synfigapp::UIInterface::RESPONSE_NO:
1594                                         break;
1595                                 case synfigapp::UIInterface::RESPONSE_YES:
1596                                         (*iter)->dialog_cvs_commit();
1597                                         break;
1598                                 case synfigapp::UIInterface::RESPONSE_CANCEL:
1599                                         return;
1600                                 default:
1601                                         assert(0);
1602                                         return;
1603                         }
1604                 }
1605 */
1606
1607                 // This next line causes things to crash for some reason
1608                 //(*iter)->close();
1609         }
1610
1611         shutdown_in_progress=true;
1612
1613         instance_list.clear();
1614
1615         while(studio::App::events_pending())studio::App::iteration(false);
1616
1617         Gtk::Main::quit();
1618         auto_recover->normal_shutdown();
1619
1620         get_ui_interface()->task("Quit Request sent");
1621 }
1622
1623 void
1624 App::show_setup()
1625 {
1626         dialog_setup->refresh();
1627         dialog_setup->show();
1628 }
1629
1630 gint Signal_Open_Ok(GtkWidget *widget, int *val){*val=1;return 0;}
1631 gint Signal_Open_Cancel(GtkWidget *widget, int *val){*val=2;return 0;}
1632
1633 //#ifdef WIN32
1634 //#define USE_WIN32_FILE_DIALOGS 1
1635 //#endif
1636
1637 #ifdef USE_WIN32_FILE_DIALOGS
1638 static OPENFILENAME ofn={};
1639 #endif
1640
1641 #ifdef WIN32
1642 #include <gdk/gdkwin32.h>
1643 #endif
1644
1645 bool
1646 App::dialog_open_file(const std::string &title, std::string &filename)
1647 {
1648 #ifdef USE_WIN32_FILE_DIALOGS
1649         static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1650
1651         GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1652         HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1653         HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1654
1655         ofn.lStructSize=sizeof(OPENFILENAME);
1656         ofn.hwndOwner = hWnd;
1657         ofn.hInstance = hInstance;
1658         ofn.lpstrFilter = szFilter;
1659 //      ofn.lpstrCustomFilter=NULL;
1660 //      ofn.nMaxCustFilter=0;
1661 //      ofn.nFilterIndex=0;
1662 //      ofn.lpstrFile=NULL;
1663         ofn.nMaxFile=MAX_PATH;
1664 //      ofn.lpstrFileTitle=NULL;
1665 //      ofn.lpstrInitialDir=NULL;
1666 //      ofn.lpstrTitle=NULL;
1667         ofn.Flags=OFN_HIDEREADONLY;
1668 //      ofn.nFileOffset=0;
1669 //      ofn.nFileExtension=0;
1670         ofn.lpstrDefExt=TEXT("sif");
1671 //      ofn.lCustData = 0l;
1672         ofn.lpfnHook=NULL;
1673 //      ofn.lpTemplateName=NULL;
1674
1675         CHAR szFilename[MAX_PATH];
1676         CHAR szTitle[500];
1677         strcpy(szFilename,filename.c_str());
1678         strcpy(szTitle,title.c_str());
1679
1680         ofn.lpstrFile=szFilename;
1681         ofn.lpstrFileTitle=szTitle;
1682
1683         if(GetOpenFileName(&ofn))
1684         {
1685                 filename=szFilename;
1686                 return true;
1687         }
1688         return false;
1689
1690 #else
1691         synfig::String prev_path;
1692         if(!_preferences.get_value("curr_path",prev_path))
1693                 prev_path=".";
1694
1695     Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_OPEN);
1696     dialog->set_current_folder(prev_path);
1697     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1698     dialog->add_button(Gtk::Stock::OPEN,   Gtk::RESPONSE_ACCEPT);
1699     if(!filename.empty())
1700         dialog->set_filename(filename);
1701     if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1702         filename=dialog->get_filename();
1703         delete dialog;
1704         return true;
1705     }
1706     delete dialog;
1707     return false;
1708     /*
1709
1710         GtkWidget *ok;
1711         GtkWidget *cancel;
1712         int val=0;
1713
1714         GtkWidget *fileselection;
1715         fileselection = gtk_file_selection_new(title.c_str());
1716
1717
1718         if(basename(filename)==filename)
1719         {
1720                 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPERATOR).c_str());
1721         }
1722         else
1723                 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1724
1725         gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1726
1727         ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1728         cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1729
1730         gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1731         gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1732
1733         gtk_widget_show(fileselection);
1734
1735         while(!val)
1736                 iteration();
1737
1738
1739         if(val==1)
1740         {
1741                 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1742                 _preferences.set_value("curr_path",dirname(filename));
1743         }
1744         else
1745         {
1746                 gtk_widget_destroy(fileselection);
1747                 return false;
1748         }
1749         gtk_widget_destroy(fileselection);
1750         return true;
1751     */
1752 #endif
1753 }
1754
1755 bool
1756 App::dialog_save_file(const std::string &title, std::string &filename)
1757 {
1758 #ifdef USE_WIN32_FILE_DIALOGS
1759         static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1760
1761         GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1762         HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1763         HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1764
1765         ofn.lStructSize=sizeof(OPENFILENAME);
1766         ofn.hwndOwner = hWnd;
1767         ofn.hInstance = hInstance;
1768         ofn.lpstrFilter = szFilter;
1769 //      ofn.lpstrCustomFilter=NULL;
1770 //      ofn.nMaxCustFilter=0;
1771 //      ofn.nFilterIndex=0;
1772 //      ofn.lpstrFile=NULL;
1773         ofn.nMaxFile=MAX_PATH;
1774 //      ofn.lpstrFileTitle=NULL;
1775 //      ofn.lpstrInitialDir=NULL;
1776 //      ofn.lpstrTitle=NULL;
1777         ofn.Flags=OFN_OVERWRITEPROMPT;
1778 //      ofn.nFileOffset=0;
1779 //      ofn.nFileExtension=0;
1780         ofn.lpstrDefExt=TEXT("sif");
1781 //      ofn.lCustData = 0l;
1782         ofn.lpfnHook=NULL;
1783 //      ofn.lpTemplateName=NULL;
1784
1785         CHAR szFilename[MAX_PATH];
1786         CHAR szTitle[500];
1787         strcpy(szFilename,filename.c_str());
1788         strcpy(szTitle,title.c_str());
1789
1790         ofn.lpstrFile=szFilename;
1791         ofn.lpstrFileTitle=szTitle;
1792
1793         if(GetSaveFileName(&ofn))
1794         {
1795                 filename=szFilename;
1796                 return true;
1797         }
1798         return false;
1799 #else
1800         synfig::String prev_path;
1801         if(!_preferences.get_value("curr_path",prev_path))
1802                 prev_path=".";
1803
1804     Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
1805     dialog->set_current_folder(prev_path);
1806     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1807     dialog->add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_ACCEPT);
1808     if(!filename.empty())
1809         dialog->set_filename(filename);
1810     if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1811         filename=dialog->get_filename();
1812         delete dialog;
1813         return true;
1814     }
1815     delete dialog;
1816     return false;
1817 //      return dialog_open_file(title, filename);
1818 #endif
1819 }
1820
1821 bool
1822 App::dialog_saveas_file(const std::string &title, std::string &filename)
1823 {
1824 #if USE_WIN32_FILE_DIALOGS
1825         static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1826
1827         GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1828         HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1829         HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1830
1831         ofn.lStructSize=sizeof(OPENFILENAME);
1832         ofn.hwndOwner = hWnd;
1833         ofn.hInstance = hInstance;
1834         ofn.lpstrFilter = szFilter;
1835 //      ofn.lpstrCustomFilter=NULL;
1836 //      ofn.nMaxCustFilter=0;
1837 //      ofn.nFilterIndex=0;
1838 //      ofn.lpstrFile=NULL;
1839         ofn.nMaxFile=MAX_PATH;
1840 //      ofn.lpstrFileTitle=NULL;
1841 //      ofn.lpstrInitialDir=NULL;
1842 //      ofn.lpstrTitle=NULL;
1843         ofn.Flags=OFN_OVERWRITEPROMPT;
1844 //      ofn.nFileOffset=0;
1845 //      ofn.nFileExtension=0;
1846         ofn.lpstrDefExt=TEXT("sif");
1847 //      ofn.lCustData = 0l;
1848         ofn.lpfnHook=NULL;
1849 //      ofn.lpTemplateName=NULL;
1850
1851         CHAR szFilename[MAX_PATH];
1852         CHAR szTitle[500];
1853         strcpy(szFilename,filename.c_str());
1854         strcpy(szTitle,title.c_str());
1855
1856         ofn.lpstrFile=szFilename;
1857         ofn.lpstrFileTitle=szTitle;
1858
1859         if(GetSaveFileName(&ofn))
1860         {
1861                 filename=szFilename;
1862                 return true;
1863         }
1864         return false;
1865 #else
1866         synfig::String prev_path;
1867         if(!_preferences.get_value("curr_path",prev_path))
1868                 prev_path=".";
1869
1870     Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
1871     dialog->set_current_folder(prev_path);
1872     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1873     dialog->add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_ACCEPT);
1874     if(!filename.empty())
1875         dialog->set_filename(filename);
1876     if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1877         filename=dialog->get_filename();
1878         delete dialog;
1879         return true;
1880     }
1881     delete dialog;
1882     return false;
1883 //      return dialog_open_file(title, filename);
1884 #endif
1885 }
1886
1887 void
1888 App::dialog_error_blocking(const std::string &title, const std::string &message)
1889 {
1890         Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1891         dialog.set_title(title);
1892         dialog.show();
1893         dialog.run();
1894 }
1895
1896 void
1897 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1898 {
1899         Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1900         dialog.set_title(title);
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::MessageDialog dialog("Feature not available", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1946         dialog.set_secondary_text("Sorry, this feature has not yet been implemented.");
1947         dialog.run();
1948 }
1949
1950 bool
1951 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1952 {
1953         Gtk::Dialog dialog(
1954                 title,          // Title
1955                 true,           // Modal
1956                 true            // use_separator
1957         );
1958         Gtk::Label label(message);
1959         label.show();
1960         dialog.get_vbox()->pack_start(label);
1961
1962         Gtk::Entry entry;
1963         entry.set_text(text);
1964         entry.show();
1965         entry.set_activates_default(true);
1966         dialog.get_vbox()->pack_start(entry);
1967
1968         dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1969         dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1970         dialog.set_default_response(Gtk::RESPONSE_OK);
1971         entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1972         dialog.show();
1973
1974         if(dialog.run()!=Gtk::RESPONSE_OK)
1975                 return false;
1976
1977         text=entry.get_text();
1978
1979         return true;
1980 }
1981
1982
1983
1984
1985 bool
1986 App::open(std::string filename)
1987 {
1988         return open_as(filename,filename);
1989 }
1990
1991 bool
1992 App::open_as(std::string filename,std::string as)
1993 {
1994 #ifdef WIN32
1995     char long_name[1024];
1996     if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1997     as=long_name;
1998 #endif
1999
2000         try
2001         {
2002                 OneMoment one_moment;
2003
2004                 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
2005                 if(canvas && get_instance(canvas))
2006                 {
2007                         get_instance(canvas)->find_canvas_view(canvas)->present();
2008                         throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2009                 }
2010                 if(!canvas)
2011                         throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2012
2013                 add_recent_file(as);
2014
2015                 handle<Instance> instance(Instance::create(canvas));
2016
2017                 if(!instance)
2018                         throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2019
2020                 one_moment.hide();
2021
2022                 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)")))
2023                         instance->dialog_cvs_update();
2024         }
2025         catch(String x)
2026         {
2027                 dialog_error_blocking(_("Error"), x);
2028                 return false;
2029         }
2030         catch(...)
2031         {
2032                 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2033                 return false;
2034         }
2035
2036         _preferences.set_value("curr_path",dirname(as));
2037
2038         return true;
2039 }
2040
2041
2042 void
2043 App::new_instance()
2044 {
2045         handle<synfig::Canvas> canvas=synfig::Canvas::create();
2046         canvas->set_name(strprintf("Untitled%d",Instance::get_count()));
2047
2048         String file_name(strprintf("untitled%d.sif",Instance::get_count()));
2049
2050         canvas->rend_desc().set_frame_rate(24.0);
2051         canvas->rend_desc().set_time_start(0.0);
2052         canvas->rend_desc().set_time_end(00.0);
2053         canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2054         canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2055         canvas->rend_desc().set_tl(Vector(-4,2.25));
2056         canvas->rend_desc().set_br(Vector(4,-2.25));
2057         canvas->rend_desc().set_w(480);
2058         canvas->rend_desc().set_h(270);
2059         canvas->rend_desc().set_antialias(1);
2060         canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2061         canvas->set_file_name(file_name);
2062
2063         Instance::create(canvas)->find_canvas_view(canvas)->canvas_properties.present();
2064 }
2065
2066 void
2067 App::dialog_open()
2068 {
2069         string filename="*.sif";
2070
2071         while(dialog_open_file("Open", filename))
2072         {
2073                 // If the filename still has wildcards, then we should
2074                 // continue looking for the file we want
2075                 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2076                         continue;
2077
2078                 if(open(filename))
2079                         break;
2080
2081                 get_ui_interface()->error(_("Unable to open file"));
2082         }
2083 }
2084
2085 void
2086 App::set_selected_instance(etl::loose_handle<Instance> instance)
2087 {
2088 /*      if(get_selected_instance()==instance)
2089         {
2090                 selected_instance=instance;
2091                 signal_instance_selected()(instance);
2092                 return;
2093         }
2094         else
2095         {
2096 */
2097                 selected_instance=instance;
2098                 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2099                 {
2100                         if(instance)
2101                         {
2102                                 instance->focus(instance->get_canvas());
2103                         }
2104                         else
2105                                 set_selected_canvas_view(0);
2106                 }
2107                 signal_instance_selected()(instance);
2108 }
2109
2110 void
2111 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2112 {
2113         selected_canvas_view=canvas_view;
2114         signal_canvas_view_focus()(selected_canvas_view);
2115         if(canvas_view)
2116         {
2117                 selected_instance=canvas_view->get_instance();
2118                 signal_instance_selected()(canvas_view->get_instance());
2119         }
2120 /*
2121         if(get_selected_canvas_view()==canvas_view)
2122         {
2123                 signal_canvas_view_focus()(selected_canvas_view);
2124                 signal_instance_selected()(canvas_view->get_instance());
2125                 return;
2126         }
2127         selected_canvas_view=canvas_view;
2128         if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2129                 set_selected_instance(canvas_view->get_instance());
2130         signal_canvas_view_focus()(selected_canvas_view);
2131 */
2132 }
2133
2134 etl::loose_handle<Instance>
2135 App::get_instance(Canvas::Handle canvas)
2136 {
2137         if(!canvas) return 0;
2138         canvas=canvas->get_root();
2139
2140         std::list<etl::handle<Instance> >::iterator iter;
2141         for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2142         {
2143                 if((*iter)->get_canvas()==canvas)
2144                         return *iter;
2145         }
2146         return 0;
2147 }
2148
2149 void
2150 App::dialog_about()
2151 {
2152         (new class About())->show();
2153 }
2154
2155 void
2156 studio::App::undo()
2157 {
2158         if(selected_instance)
2159                 selected_instance->undo();
2160 }
2161
2162 void
2163 studio::App::redo()
2164 {
2165         if(selected_instance)
2166                 selected_instance->redo();
2167 }
2168
2169 synfig::String
2170 studio::App::get_base_path()
2171 {
2172         return app_base_path_;
2173 }