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