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