Use a checkbox in the gui (Toolbox > File > Setup > Misc) for single_threaded, rather...
[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=true;
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         Glib::thread_init();
1107
1108         distance_system=Distance::SYSTEM_UNITS;
1109
1110         if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1111         {
1112                 if(errno!=EEXIST)
1113                         synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1114         }
1115         else
1116         {
1117                 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1118         }
1119
1120
1121         ipc=new IPC();
1122
1123         try
1124         {
1125                 if(!SYNFIG_CHECK_VERSION())
1126                 {
1127                 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1128                 dialog_error_blocking("Synfig Studio",
1129                         "This copy of Synfig Studio was compiled against a\n"
1130                         "different version of libsynfig than what is currently\n"
1131                         "installed. Synfig Studio will now abort. Try downloading\n"
1132                         "the latest version from the Synfig website at\n"
1133                         "http://www.synfig.com/ "
1134                 );
1135                 throw 40;
1136                 }
1137         }
1138         catch(synfig::SoftwareExpired)
1139         {
1140                 cerr<<"FATAL: Software Expired"<<endl;
1141                 dialog_error_blocking("Synfig Studio",
1142                         "This copy of Synfig Studio has expired.\n"
1143                         "Please erase this copy, or download and\n"
1144                         "install the latest copy from the Synfig\n"
1145                         "website at http://www.synfig.com/ ."
1146                 );
1147                 throw 39;
1148         }
1149         Glib::set_application_name(_("Synfig Studio"));
1150
1151         About about_window;
1152         about_window.set_can_self_destruct(false);
1153         about_window.show();
1154
1155         shutdown_in_progress=false;
1156         SuperCallback synfig_init_cb(about_window.get_callback(),0,9000,10000);
1157         SuperCallback studio_init_cb(about_window.get_callback(),9000,10000,10000);
1158
1159         // Initialize the Synfig library
1160         try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1161         catch(...)
1162         {
1163                 get_ui_interface()->error("Failed to initialize synfig!");
1164                 throw;
1165         }
1166
1167         // add the preferences to the settings
1168         synfigapp::Main::settings().add_domain(&_preferences,"pref");
1169
1170         try
1171         {
1172                 studio_init_cb.task("Init UI Manager...");
1173                 App::ui_manager_=studio::UIManager::create();
1174                 init_ui_manager();
1175
1176                 studio_init_cb.task("Init Dock Manager...");
1177                 dock_manager=new studio::DockManager();
1178
1179                 studio_init_cb.task("Init State Manager...");
1180                 state_manager=new StateManager();
1181
1182                 studio_init_cb.task("Init Toolbox...");
1183                 toolbox=new studio::Toolbox();
1184
1185                 studio_init_cb.task("Init Tool Options...");
1186                 dialog_tool_options=new studio::Dialog_ToolOptions();
1187                 dock_manager->register_dockable(*dialog_tool_options);
1188
1189                 studio_init_cb.task("Init History...");
1190                 dock_history=new studio::Dock_History();
1191                 dock_manager->register_dockable(*dock_history);
1192
1193                 studio_init_cb.task("Init Canvases...");
1194                 dock_canvases=new studio::Dock_Canvases();
1195                 dock_manager->register_dockable(*dock_canvases);
1196
1197                 studio_init_cb.task("Init Keyframes...");
1198                 dock_keyframes=new studio::Dock_Keyframes();
1199                 dock_manager->register_dockable(*dock_keyframes);
1200
1201                 studio_init_cb.task("Init Layers...");
1202                 dock_layers=new studio::Dock_Layers();
1203                 dock_manager->register_dockable(*dock_layers);
1204
1205                 studio_init_cb.task("Init Params...");
1206                 dock_params=new studio::Dock_Params();
1207                 dock_manager->register_dockable(*dock_params);
1208
1209                 studio_init_cb.task("Init MetaData...");
1210                 dock_meta_data=new studio::Dock_MetaData();
1211                 dock_manager->register_dockable(*dock_meta_data);
1212
1213                 studio_init_cb.task("Init Children...");
1214                 dock_children=new studio::Dock_Children();
1215                 dock_manager->register_dockable(*dock_children);
1216
1217                 studio_init_cb.task("Init Info...");
1218                 dock_info = new studio::Dock_Info();
1219                 dock_manager->register_dockable(*dock_info);
1220
1221                 studio_init_cb.task("Init Navigator...");
1222                 dock_navigator = new studio::Dock_Navigator();
1223                 dock_manager->register_dockable(*dock_navigator);
1224
1225                 studio_init_cb.task("Init Timetrack...");
1226                 dock_timetrack = new studio::Dock_Timetrack();
1227                 dock_manager->register_dockable(*dock_timetrack);
1228
1229                 studio_init_cb.task("Init Curve Editor...");
1230                 dock_curves = new studio::Dock_Curves();
1231                 dock_manager->register_dockable(*dock_curves);
1232
1233                 studio_init_cb.task("Init Layer Groups...");
1234                 dock_layer_groups = new studio::Dock_LayerGroups();
1235                 dock_manager->register_dockable(*dock_layer_groups);
1236
1237
1238                 studio_init_cb.task("Init Color Dialog...");
1239                 dialog_color=new studio::Dialog_Color();
1240
1241                 studio_init_cb.task("Init Gradient Dialog...");
1242                 dialog_gradient=new studio::Dialog_Gradient();
1243
1244                 studio_init_cb.task("Init DeviceTracker...");
1245                 device_tracker=new studio::DeviceTracker();
1246
1247                 studio_init_cb.task("Init Tools...");
1248                 state_manager->add_state(&state_normal);
1249                 state_manager->add_state(&state_smooth_move);
1250                 state_manager->add_state(&state_scale);
1251                 state_manager->add_state(&state_rotate);
1252
1253                 state_manager->add_state(&state_bline);
1254
1255
1256                 state_manager->add_state(&state_circle);
1257                 state_manager->add_state(&state_rectangle);
1258
1259                 state_manager->add_state(&state_gradient);
1260                 state_manager->add_state(&state_eyedrop);
1261                 state_manager->add_state(&state_fill);
1262
1263                 state_manager->add_state(&state_zoom);
1264
1265                 // Enabled - it's useful to be able to work with polygons without tangent ducks getting in the way.
1266                 // I know we can switch tangent ducks off, but why not allow this kind of layer as well?
1267                 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon);
1268
1269                 // Enabled for now.  Let's see whether they're good enough yet.
1270                 if(!getenv("SYNFIG_DISABLE_DRAW"   )) state_manager->add_state(&state_draw);
1271                 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1272
1273                 // Disabled by default - it doesn't work properly?
1274                 if(getenv("SYNFIG_ENABLE_WIDTH"    )) state_manager->add_state(&state_width);
1275
1276                 studio_init_cb.task("Init ModPalette...");
1277                 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1278
1279                 studio_init_cb.task("Init ModMirror...");
1280                 module_list_.push_back(new ModMirror()); module_list_.back()->start();
1281
1282
1283                 studio_init_cb.task("Init Setup Dialog...");
1284                 dialog_setup=new studio::Dialog_Setup();
1285
1286                 studio_init_cb.task("Init Input Dialog...");
1287                 dialog_input=new Gtk::InputDialog();
1288                 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1289                 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1290
1291                 studio_init_cb.task("Init auto recovery...");
1292                 auto_recover=new AutoRecover();
1293
1294                 studio_init_cb.amount_complete(9250,10000);
1295                 studio_init_cb.task("Loading Settings...");
1296                 load_settings();
1297                 studio_init_cb.task("Checking auto-recover...");
1298
1299                 studio_init_cb.amount_complete(9900,10000);
1300
1301                 if(auto_recover->recovery_needed())
1302                 {
1303                         about_window.hide();
1304                         if(
1305                                 get_ui_interface()->yes_no(
1306                                         "Auto Recovery",
1307                                         "Synfig Studio seems to have crashed\n"
1308                                         "before you could save all your files.\n"
1309                                         "Would you like to re-open those files\n"
1310                                         "and recover your unsaved changes?"
1311                                 )==synfigapp::UIInterface::RESPONSE_YES
1312                         )
1313                         {
1314                                 if(!auto_recover->recover())
1315                                 {
1316                                         get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1317                                 }
1318                                 else
1319                                 get_ui_interface()->error(
1320                                         _("Synfig Studio has attempted to recover\n"
1321                                         "from a previous crash. The files that it has\n"
1322                                         "recovered are NOT YET SAVED. It would be a good\n"
1323                                         "idea to review them and save them now.")
1324                                 );
1325                         }
1326                         about_window.show();
1327                 }
1328
1329                 // Look for any files given on the command line,
1330                 // and load them if found.
1331                 for(;*argc>=1;(*argc)--)
1332                         if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1333                         {
1334                                 studio_init_cb.task("Loading files...");
1335                                 about_window.hide();
1336                                 open((*argv)[*argc]);
1337                                 about_window.show();
1338                         }
1339
1340                 studio_init_cb.task("Done.");
1341                 studio_init_cb.amount_complete(10000,10000);
1342
1343                 toolbox->present();
1344         }
1345         catch(...)
1346         {
1347                 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1348         }
1349 }
1350
1351 StateManager* App::get_state_manager() { return state_manager; }
1352
1353 App::~App()
1354 {
1355         shutdown_in_progress=true;
1356
1357         save_settings();
1358
1359         synfigapp::Main::settings().remove_domain("pref");
1360
1361         selected_instance=0;
1362
1363         // Unload all of the modules
1364         for(;!module_list_.empty();module_list_.pop_back());
1365
1366         delete state_manager;
1367
1368         delete ipc;
1369
1370         delete auto_recover;
1371
1372         toolbox->hide();
1373
1374 //      studio::App::iteration(false);
1375
1376         delete toolbox;
1377
1378 //      studio::App::iteration(false);
1379
1380 //      studio::App::iteration(false);
1381
1382         delete dialog_setup;
1383
1384         delete dialog_gradient;
1385
1386         delete dialog_color;
1387
1388         delete dialog_input;
1389
1390         delete dock_manager;
1391
1392         instance_list.clear();
1393
1394 //      studio::App::iteration(false);
1395 }
1396
1397 String
1398 App::get_user_app_directory()
1399 {
1400         return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1401 }
1402
1403 synfig::String
1404 App::get_config_file(const synfig::String& file)
1405 {
1406         return Glib::build_filename(get_user_app_directory(),file);
1407 }
1408
1409 void
1410 App::add_recent_file(const std::string &file_name)
1411 {
1412         std::string filename(file_name);
1413
1414         assert(!filename.empty());
1415
1416         if(filename.empty())
1417                 return;
1418
1419         // Toss out any "hidden" files
1420         if(basename(filename)[0]=='.')
1421                 return;
1422
1423         // If we aren't an absolute path, turn outselves into one
1424         if(!is_absolute_path(filename))
1425                 filename=absolute_path(filename);
1426
1427         list<string>::iterator iter;
1428         // Check to see if the file is already on the list.
1429         // If it is, then remove it from the list
1430         for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1431                 if(*iter==filename)
1432                 {
1433                         recent_files.erase(iter);
1434                         break;
1435                 }
1436
1437
1438         // Push the filename to the front of the list
1439         recent_files.push_front(filename);
1440
1441         // Clean out the files at the end of the list.
1442         while(recent_files.size()>(unsigned)get_max_recent_files())
1443                 recent_files.pop_back();
1444
1445         signal_recent_files_changed_();
1446
1447         return;
1448 }
1449
1450 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1451
1452 Time::Format
1453 App::get_time_format()
1454 {
1455         return _App_time_format;
1456 }
1457
1458 void
1459 App::set_time_format(synfig::Time::Format x)
1460 {
1461         _App_time_format=x;
1462 }
1463
1464
1465 void
1466 App::save_settings()
1467 {
1468         char * old_locale;
1469         try
1470         {
1471         old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1472         setlocale(LC_NUMERIC, "C");
1473                 {
1474                         std::string filename=get_config_file("accelrc");
1475                         Gtk::AccelMap::save(filename);
1476                 }
1477                 do{
1478                         std::string filename=get_config_file("recentfiles");
1479
1480                         std::ofstream file(filename.c_str());
1481
1482                         if(!file)
1483                         {
1484                                 synfig::warning("Unable to save %s",filename.c_str());
1485                                 break;
1486                         }
1487
1488                         list<string>::reverse_iterator iter;
1489
1490                         for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1491                                 file<<*iter<<endl;
1492                 }while(0);
1493
1494                 std::string filename=get_config_file("settings");
1495                 synfigapp::Main::settings().save_to_file(filename);
1496         setlocale(LC_NUMERIC,old_locale);
1497         }
1498         catch(...)
1499         {
1500                 synfig::warning("Caught exception when attempting to save settings.");
1501         }
1502 }
1503
1504 void
1505 App::load_settings()
1506 {
1507         char  * old_locale;
1508         try
1509         {
1510         old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1511         setlocale(LC_NUMERIC, "C");
1512                 {
1513                         std::string filename=get_config_file("accelrc");
1514                         Gtk::AccelMap::load(filename);
1515                 }
1516                 {
1517                         std::string filename=get_config_file("recentfiles");
1518
1519                         std::ifstream file(filename.c_str());
1520
1521                         while(file)
1522                         {
1523                                 std::string recent_file;
1524                                 getline(file,recent_file);
1525                                 if(!recent_file.empty())
1526                                         add_recent_file(recent_file);
1527                         }
1528                 }
1529                 std::string filename=get_config_file("settings");
1530                 if(!synfigapp::Main::settings().load_from_file(filename))
1531                 {
1532                         //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1533                         //if(!synfigapp::Main::settings().load_from_file(filename))
1534                         {
1535                                 gamma.set_gamma(1.0/2.2);
1536                                 reset_initial_window_configuration();
1537                         }
1538                 }
1539         setlocale(LC_NUMERIC,old_locale);
1540         }
1541         catch(...)
1542         {
1543                 synfig::warning("Caught exception when attempting to load settings.");
1544         }
1545 }
1546
1547 void
1548 App::reset_initial_window_configuration()
1549 {
1550         synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1551         synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1552         synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1553         synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1554         synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1555         synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1556         synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1557         synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1558         synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1559         synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1560         synfigapp::Main::settings().set_value("pref.distance_system","pt");
1561         synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1562         synfigapp::Main::settings().set_value("pref.single_threaded","0");
1563         synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1564 }
1565
1566 bool
1567 App::shutdown_request(GdkEventAny*)
1568 {
1569         quit();
1570         return true;
1571         //return !shutdown_in_progress;
1572 }
1573
1574 void
1575 App::quit()
1576 {
1577         if(shutdown_in_progress)return;
1578
1579
1580         get_ui_interface()->task("Quit Request");
1581         if(Busy::count)
1582         {
1583                 dialog_error_blocking("Cannot quit!","Tasks are currently running.\nPlease cancel the current tasks and try again");
1584                 return;
1585         }
1586
1587         std::list<etl::handle<Instance> >::iterator iter;
1588         for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1589         {
1590                 if(!(*iter)->safe_close())
1591                         return;
1592
1593 /*
1594                 if((*iter)->synfigapp::Instance::get_action_count())
1595                 {
1596                         handle<synfigapp::UIInterface> uim;
1597                         uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1598                         assert(uim);
1599                         string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1600                         switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1601                         {
1602                                 case synfigapp::UIInterface::RESPONSE_NO:
1603                                         break;
1604                                 case synfigapp::UIInterface::RESPONSE_YES:
1605                                         (*iter)->save();
1606                                         break;
1607                                 case synfigapp::UIInterface::RESPONSE_CANCEL:
1608                                         return;
1609                                 default:
1610                                         assert(0);
1611                                         return;
1612                         }
1613                 }
1614
1615
1616                 if((*iter)->synfigapp::Instance::is_modified())
1617                 {
1618                         handle<synfigapp::UIInterface> uim;
1619                         uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1620                         assert(uim);
1621                         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() );
1622                         switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1623                         {
1624                                 case synfigapp::UIInterface::RESPONSE_NO:
1625                                         break;
1626                                 case synfigapp::UIInterface::RESPONSE_YES:
1627                                         (*iter)->dialog_cvs_commit();
1628                                         break;
1629                                 case synfigapp::UIInterface::RESPONSE_CANCEL:
1630                                         return;
1631                                 default:
1632                                         assert(0);
1633                                         return;
1634                         }
1635                 }
1636 */
1637
1638                 // This next line causes things to crash for some reason
1639                 //(*iter)->close();
1640         }
1641
1642         shutdown_in_progress=true;
1643
1644         instance_list.clear();
1645
1646         while(studio::App::events_pending())studio::App::iteration(false);
1647
1648         Gtk::Main::quit();
1649         auto_recover->normal_shutdown();
1650
1651         get_ui_interface()->task("Quit Request sent");
1652 }
1653
1654 void
1655 App::show_setup()
1656 {
1657         dialog_setup->refresh();
1658         dialog_setup->show();
1659 }
1660
1661 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1662 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1663
1664 //#ifdef WIN32
1665 //#define USE_WIN32_FILE_DIALOGS 1
1666 //#endif
1667
1668 #ifdef USE_WIN32_FILE_DIALOGS
1669 static OPENFILENAME ofn={};
1670 #endif
1671
1672 #ifdef WIN32
1673 #include <gdk/gdkwin32.h>
1674 #endif
1675
1676 bool
1677 App::dialog_open_file(const std::string &title, std::string &filename)
1678 {
1679 #ifdef USE_WIN32_FILE_DIALOGS
1680         static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1681
1682         GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1683         HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1684         HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1685
1686         ofn.lStructSize=sizeof(OPENFILENAME);
1687         ofn.hwndOwner = hWnd;
1688         ofn.hInstance = hInstance;
1689         ofn.lpstrFilter = szFilter;
1690 //      ofn.lpstrCustomFilter=NULL;
1691 //      ofn.nMaxCustFilter=0;
1692 //      ofn.nFilterIndex=0;
1693 //      ofn.lpstrFile=NULL;
1694         ofn.nMaxFile=MAX_PATH;
1695 //      ofn.lpstrFileTitle=NULL;
1696 //      ofn.lpstrInitialDir=NULL;
1697 //      ofn.lpstrTitle=NULL;
1698         ofn.Flags=OFN_HIDEREADONLY;
1699 //      ofn.nFileOffset=0;
1700 //      ofn.nFileExtension=0;
1701         ofn.lpstrDefExt=TEXT("sif");
1702 //      ofn.lCustData = 0l;
1703         ofn.lpfnHook=NULL;
1704 //      ofn.lpTemplateName=NULL;
1705
1706         CHAR szFilename[MAX_PATH];
1707         CHAR szTitle[500];
1708         strcpy(szFilename,filename.c_str());
1709         strcpy(szTitle,title.c_str());
1710
1711         ofn.lpstrFile=szFilename;
1712         ofn.lpstrFileTitle=szTitle;
1713
1714         if(GetOpenFileName(&ofn))
1715         {
1716                 filename=szFilename;
1717                 return true;
1718         }
1719         return false;
1720
1721 #else
1722         synfig::String prev_path;
1723         if(!_preferences.get_value("curr_path",prev_path))
1724                 prev_path=".";
1725         prev_path = absolute_path(prev_path);
1726
1727     Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_OPEN);
1728     dialog->set_current_folder(prev_path);
1729     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1730     dialog->add_button(Gtk::Stock::OPEN,   Gtk::RESPONSE_ACCEPT);
1731     if(!filename.empty())
1732                 if (is_absolute_path(filename))
1733                         dialog->set_filename(filename);
1734                 else
1735                         dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1736     if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1737         filename=dialog->get_filename();
1738         delete dialog;
1739         return true;
1740     }
1741     delete dialog;
1742     return false;
1743     /*
1744
1745         GtkWidget *ok;
1746         GtkWidget *cancel;
1747         int val=0;
1748
1749         GtkWidget *fileselection;
1750         fileselection = gtk_file_selection_new(title.c_str());
1751
1752
1753         if(basename(filename)==filename)
1754         {
1755                 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1756         }
1757         else
1758                 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1759
1760         gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1761
1762         ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1763         cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1764
1765         gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1766         gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1767
1768         gtk_widget_show(fileselection);
1769
1770         while(!val)
1771                 iteration();
1772
1773
1774         if(val==1)
1775         {
1776                 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1777                 _preferences.set_value("curr_path",dirname(filename));
1778         }
1779         else
1780         {
1781                 gtk_widget_destroy(fileselection);
1782                 return false;
1783         }
1784         gtk_widget_destroy(fileselection);
1785         return true;
1786     */
1787 #endif
1788 }
1789
1790 bool
1791 App::dialog_save_file(const std::string &title, std::string &filename)
1792 {
1793 #if USE_WIN32_FILE_DIALOGS
1794         static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1795
1796         GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1797         HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1798         HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1799
1800         ofn.lStructSize=sizeof(OPENFILENAME);
1801         ofn.hwndOwner = hWnd;
1802         ofn.hInstance = hInstance;
1803         ofn.lpstrFilter = szFilter;
1804 //      ofn.lpstrCustomFilter=NULL;
1805 //      ofn.nMaxCustFilter=0;
1806 //      ofn.nFilterIndex=0;
1807 //      ofn.lpstrFile=NULL;
1808         ofn.nMaxFile=MAX_PATH;
1809 //      ofn.lpstrFileTitle=NULL;
1810 //      ofn.lpstrInitialDir=NULL;
1811 //      ofn.lpstrTitle=NULL;
1812         ofn.Flags=OFN_OVERWRITEPROMPT;
1813 //      ofn.nFileOffset=0;
1814 //      ofn.nFileExtension=0;
1815         ofn.lpstrDefExt=TEXT("sif");
1816 //      ofn.lCustData = 0l;
1817         ofn.lpfnHook=NULL;
1818 //      ofn.lpTemplateName=NULL;
1819
1820         CHAR szFilename[MAX_PATH];
1821         CHAR szTitle[500];
1822         strcpy(szFilename,filename.c_str());
1823         strcpy(szTitle,title.c_str());
1824
1825         ofn.lpstrFile=szFilename;
1826         ofn.lpstrFileTitle=szTitle;
1827
1828         if(GetSaveFileName(&ofn))
1829         {
1830                 filename=szFilename;
1831                 _preferences.set_value("curr_path",dirname(filename));
1832                 return true;
1833         }
1834         return false;
1835 #else
1836         synfig::String prev_path;
1837         if(!_preferences.get_value("curr_path",prev_path))
1838                 prev_path=".";
1839         prev_path = absolute_path(prev_path);
1840
1841     Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
1842     dialog->set_current_folder(prev_path);
1843     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1844     dialog->add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_ACCEPT);
1845     if(!filename.empty())
1846         {
1847                 std::string full_path;
1848                 if (is_absolute_path(filename))
1849                         full_path = filename;
1850                 else
1851                         full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1852                 // select the file if it exists
1853                 dialog->set_filename(full_path);
1854
1855                 // if the file doesn't exist, put its name into the filename box
1856                 struct stat s;
1857                 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1858                         dialog->set_current_name(basename(filename));
1859         }
1860     if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1861         filename=dialog->get_filename();
1862         delete dialog;
1863                 _preferences.set_value("curr_path",dirname(filename));
1864         return true;
1865     }
1866     delete dialog;
1867     return false;
1868 //      return dialog_open_file(title, filename);
1869 #endif
1870 }
1871
1872 void
1873 App::dialog_error_blocking(const std::string &title, const std::string &message)
1874 {
1875         Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1876         dialog.set_title(title);
1877         dialog.show();
1878         dialog.run();
1879 }
1880
1881 void
1882 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1883 {
1884         Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1885         dialog.set_title(title);
1886         dialog.show();
1887         dialog.run();
1888 }
1889
1890 bool
1891 App::dialog_yes_no(const std::string &title, const std::string &message)
1892 {
1893         Gtk::Dialog dialog(
1894                 title,          // Title
1895                 true,           // Modal
1896                 true            // use_separator
1897         );
1898         Gtk::Label label(message);
1899         label.show();
1900
1901         dialog.get_vbox()->pack_start(label);
1902         dialog.add_button(Gtk::StockID("gtk-yes"),1);
1903         dialog.add_button(Gtk::StockID("gtk-no"),0);
1904         dialog.show();
1905         return dialog.run();
1906 }
1907
1908 int
1909 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1910 {
1911         Gtk::Dialog dialog(
1912                 title,          // Title
1913                 true,           // Modal
1914                 true            // use_separator
1915         );
1916         Gtk::Label label(message);
1917         label.show();
1918
1919         dialog.get_vbox()->pack_start(label);
1920         dialog.add_button(Gtk::StockID("gtk-yes"),1);
1921         dialog.add_button(Gtk::StockID("gtk-no"),0);
1922         dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1923         dialog.show();
1924         return dialog.run();
1925 }
1926
1927 void
1928 App::dialog_not_implemented()
1929 {
1930         Gtk::MessageDialog dialog("Feature not available", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1931         dialog.set_secondary_text("Sorry, this feature has not yet been implemented.");
1932         dialog.run();
1933 }
1934
1935 bool
1936 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1937 {
1938         Gtk::Dialog dialog(
1939                 title,          // Title
1940                 true,           // Modal
1941                 true            // use_separator
1942         );
1943         Gtk::Label label(message);
1944         label.show();
1945         dialog.get_vbox()->pack_start(label);
1946
1947         Gtk::Entry entry;
1948         entry.set_text(text);
1949         entry.show();
1950         entry.set_activates_default(true);
1951         dialog.get_vbox()->pack_start(entry);
1952
1953         dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1954         dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1955         dialog.set_default_response(Gtk::RESPONSE_OK);
1956         entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1957         dialog.show();
1958
1959         if(dialog.run()!=Gtk::RESPONSE_OK)
1960                 return false;
1961
1962         text=entry.get_text();
1963
1964         return true;
1965 }
1966
1967
1968
1969
1970 bool
1971 App::open(std::string filename)
1972 {
1973         return open_as(filename,filename);
1974 }
1975
1976 // this is called from autorecover.cpp:
1977 //   App::open_as(get_shadow_file_name(filename),filename)
1978 // other than that, 'filename' and 'as' are the same
1979 bool
1980 App::open_as(std::string filename,std::string as)
1981 {
1982 #ifdef WIN32
1983     char long_name[1024];
1984     if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1985     as=long_name;
1986 #endif
1987
1988         try
1989         {
1990                 OneMoment one_moment;
1991
1992                 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1993                 if(canvas && get_instance(canvas))
1994                 {
1995                         get_instance(canvas)->find_canvas_view(canvas)->present();
1996                         throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1997                 }
1998                 if(!canvas)
1999                         throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2000
2001                 add_recent_file(as);
2002
2003                 handle<Instance> instance(Instance::create(canvas));
2004
2005                 if(!instance)
2006                         throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2007
2008                 one_moment.hide();
2009
2010                 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)")))
2011                         instance->dialog_cvs_update();
2012         }
2013         catch(String x)
2014         {
2015                 dialog_error_blocking(_("Error"), x);
2016                 return false;
2017         }
2018         catch(...)
2019         {
2020                 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2021                 return false;
2022         }
2023
2024         _preferences.set_value("curr_path",dirname(as));
2025
2026         return true;
2027 }
2028
2029
2030 void
2031 App::new_instance()
2032 {
2033         handle<synfig::Canvas> canvas=synfig::Canvas::create();
2034         canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2035
2036         String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2037
2038         canvas->rend_desc().set_frame_rate(24.0);
2039         canvas->rend_desc().set_time_start(0.0);
2040         canvas->rend_desc().set_time_end(00.0);
2041         canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2042         canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2043         canvas->rend_desc().set_tl(Vector(-4,2.25));
2044         canvas->rend_desc().set_br(Vector(4,-2.25));
2045         canvas->rend_desc().set_w(480);
2046         canvas->rend_desc().set_h(270);
2047         canvas->rend_desc().set_antialias(1);
2048         canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2049         canvas->set_file_name(file_name);
2050
2051         Instance::create(canvas)->find_canvas_view(canvas)->canvas_properties.present();
2052 }
2053
2054 void
2055 App::dialog_open()
2056 {
2057         string filename="*.sif";
2058
2059         while(dialog_open_file("Open", filename))
2060         {
2061                 // If the filename still has wildcards, then we should
2062                 // continue looking for the file we want
2063                 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2064                         continue;
2065
2066                 if(open(filename))
2067                         break;
2068
2069                 get_ui_interface()->error(_("Unable to open file"));
2070         }
2071 }
2072
2073 void
2074 App::set_selected_instance(etl::loose_handle<Instance> instance)
2075 {
2076 /*      if(get_selected_instance()==instance)
2077         {
2078                 selected_instance=instance;
2079                 signal_instance_selected()(instance);
2080                 return;
2081         }
2082         else
2083         {
2084 */
2085                 selected_instance=instance;
2086                 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2087                 {
2088                         if(instance)
2089                         {
2090                                 instance->focus(instance->get_canvas());
2091                         }
2092                         else
2093                                 set_selected_canvas_view(0);
2094                 }
2095                 signal_instance_selected()(instance);
2096 }
2097
2098 void
2099 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2100 {
2101         selected_canvas_view=canvas_view;
2102         signal_canvas_view_focus()(selected_canvas_view);
2103         if(canvas_view)
2104         {
2105                 selected_instance=canvas_view->get_instance();
2106                 signal_instance_selected()(canvas_view->get_instance());
2107         }
2108 /*
2109         if(get_selected_canvas_view()==canvas_view)
2110         {
2111                 signal_canvas_view_focus()(selected_canvas_view);
2112                 signal_instance_selected()(canvas_view->get_instance());
2113                 return;
2114         }
2115         selected_canvas_view=canvas_view;
2116         if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2117                 set_selected_instance(canvas_view->get_instance());
2118         signal_canvas_view_focus()(selected_canvas_view);
2119 */
2120 }
2121
2122 etl::loose_handle<Instance>
2123 App::get_instance(Canvas::Handle canvas)
2124 {
2125         if(!canvas) return 0;
2126         canvas=canvas->get_root();
2127
2128         std::list<etl::handle<Instance> >::iterator iter;
2129         for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2130         {
2131                 if((*iter)->get_canvas()==canvas)
2132                         return *iter;
2133         }
2134         return 0;
2135 }
2136
2137 void
2138 App::dialog_about()
2139 {
2140         (new class About())->show();
2141 }
2142
2143 void
2144 studio::App::undo()
2145 {
2146         if(selected_instance)
2147                 selected_instance->undo();
2148 }
2149
2150 void
2151 studio::App::redo()
2152 {
2153         if(selected_instance)
2154                 selected_instance->redo();
2155 }
2156
2157 synfig::String
2158 studio::App::get_base_path()
2159 {
2160         return app_base_path_;
2161 }