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