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