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