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