1 /* === S Y N F I G ========================================================= */
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
10 ** Copyright (c) 2008 Gerald Young
12 ** This package is free software; you can redistribute it and/or
13 ** modify it under the terms of the GNU General Public License as
14 ** published by the Free Software Foundation; either version 2 of
15 ** the License, or (at your option) any later version.
17 ** This package is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ** General Public License for more details.
23 /* ========================================================================= */
25 /* === H E A D E R S ======================================================= */
44 #ifdef HAVE_SYS_ERRNO_H
45 #include <sys/errno.h>
47 #include <gtkmm/fileselection.h>
48 #include <gtkmm/dialog.h>
49 #include <gtkmm/messagedialog.h>
50 #include <gtkmm/label.h>
51 #include <gtkmm/stock.h>
52 #include <gtkmm/stockitem.h>
53 #include <gtkmm/iconsource.h>
54 #include <gtkmm/inputdialog.h>
55 #include <gtkmm/accelmap.h>
56 #include <gtkmm/uimanager.h>
57 #include <gtkmm/textview.h>
61 #include <gdkmm/general.h>
63 #include <synfig/loadcanvas.h>
64 #include <synfig/savecanvas.h>
70 #include "canvasview.h"
71 #include "dialog_setup.h"
72 #include "dialog_gradient.h"
73 #include "dialog_color.h"
76 #include "onemoment.h"
78 #include "dockmanager.h"
80 #include "state_eyedrop.h"
81 #include "state_normal.h"
82 #include "state_draw.h"
83 #include "state_fill.h"
84 #include "state_bline.h"
85 #include "state_polygon.h"
86 #include "state_sketch.h"
87 #include "state_gradient.h"
88 #include "state_circle.h"
89 #include "state_rectangle.h"
90 #include "state_smoothmove.h"
91 #include "state_scale.h"
92 #include "state_star.h"
93 #include "state_text.h"
94 #include "state_width.h"
95 #include "state_rotate.h"
96 #include "state_zoom.h"
98 #include "devicetracker.h"
99 #include "dialog_tooloptions.h"
100 #include "widget_enum.h"
102 #include "autorecover.h"
104 #include <synfigapp/settings.h>
105 #include "dock_history.h"
106 #include "dock_canvases.h"
107 #include "dock_keyframes.h"
108 #include "dock_layers.h"
109 #include "dock_params.h"
110 #include "dock_metadata.h"
111 #include "dock_children.h"
112 #include "dock_info.h"
113 #include "dock_navigator.h"
114 #include "dock_layergroups.h"
115 #include "dock_timetrack.h"
116 #include "dock_curves.h"
118 #include "mod_palette/mod_palette.h"
119 #include "mod_mirror/mod_mirror.h"
121 #include <sys/stat.h>
127 #include "statemanager.h"
133 #include <gtkmm/accelmap.h>
134 #include <gtkmm/filechooser.h>
135 #include <gtkmm/filechooserdialog.h>
141 /* === U S I N G =========================================================== */
145 using namespace synfig;
146 using namespace studio;
148 /* === M A C R O S ========================================================= */
150 #ifndef SYNFIG_USER_APP_DIR
152 #define SYNFIG_USER_APP_DIR "Library/Synfig"
153 #elif defined(_WIN32)
154 #define SYNFIG_USER_APP_DIR "Synfig"
156 #define SYNFIG_USER_APP_DIR ".synfig"
161 #define DPM2DPI(x) (float(x)/39.3700787402f)
162 #define DPI2DPM(x) (float(x)*39.3700787402f)
168 # define IMAGE_DIR "share\\pixmaps"
173 # define IMAGE_DIR "/usr/local/share/pixmaps"
177 # define IMAGE_EXT "tif"
180 #include <synfigapp/main.h>
182 /* === S I G N A L S ======================================================= */
184 static sigc::signal<void> signal_present_all_;
186 App::signal_present_all() { return signal_present_all_; }
188 static sigc::signal<void> signal_recent_files_changed_;
190 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
192 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
193 sigc::signal<void,etl::loose_handle<CanvasView> >&
194 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
196 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
197 sigc::signal<void,etl::handle<Instance> >&
198 App::signal_instance_selected() { return signal_instance_selected_; }
200 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
201 sigc::signal<void,etl::handle<Instance> >&
202 App::signal_instance_created() { return signal_instance_created_; }
204 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
205 sigc::signal<void,etl::handle<Instance> >&
206 App::signal_instance_deleted() { return signal_instance_deleted_; }
208 /* === G L O B A L S ======================================================= */
210 static std::list<std::string> recent_files;
211 const std::list<std::string>& App::get_recent_files() { return recent_files; }
213 static std::list<std::string> recent_files_window_size;
215 int App::Busy::count;
216 bool App::shutdown_in_progress;
218 synfig::Gamma App::gamma;
220 Glib::RefPtr<studio::UIManager> App::ui_manager_;
222 synfig::Distance::System App::distance_system;
224 studio::Dialog_Setup* App::dialog_setup;
226 etl::handle< studio::ModPalette > mod_palette_;
227 //studio::Dialog_Palette* App::dialog_palette;
229 std::list<etl::handle<Instance> > App::instance_list;
231 static etl::handle<synfigapp::UIInterface> ui_interface_;
232 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
234 etl::handle<Instance> App::selected_instance;
235 etl::handle<CanvasView> App::selected_canvas_view;
237 studio::About *studio::App::about=NULL;
239 studio::Toolbox *studio::App::toolbox=NULL;
241 studio::AutoRecover *studio::App::auto_recover=NULL;
243 studio::IPC *ipc=NULL;
245 studio::DockManager* studio::App::dock_manager=0;
247 studio::DeviceTracker* studio::App::device_tracker=0;
249 studio::Dialog_Gradient* studio::App::dialog_gradient;
251 studio::Dialog_Color* studio::App::dialog_color;
253 Gtk::InputDialog* studio::App::dialog_input;
255 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
257 studio::Dock_History* dock_history;
258 studio::Dock_Canvases* dock_canvases;
259 studio::Dock_Keyframes* dock_keyframes;
260 studio::Dock_Layers* dock_layers;
261 studio::Dock_Params* dock_params;
262 studio::Dock_MetaData* dock_meta_data;
263 studio::Dock_Children* dock_children;
264 studio::Dock_Info* dock_info;
265 studio::Dock_LayerGroups* dock_layer_groups;
266 studio::Dock_Navigator* dock_navigator;
267 studio::Dock_Timetrack* dock_timetrack;
268 studio::Dock_Curves* dock_curves;
270 std::list< etl::handle< studio::Module > > module_list_;
272 bool studio::App::use_colorspace_gamma=true;
273 #ifdef SINGLE_THREADED
274 bool studio::App::single_threaded=false;
276 bool studio::App::restrict_radius_ducks=false;
277 #ifdef USE_OPEN_FOR_URLS
278 String studio::App::browser_command("open"); // MacOS only
280 String studio::App::browser_command("xdg-open"); // Linux XDG standard
283 static int max_recent_files_=25;
284 int studio::App::get_max_recent_files() { return max_recent_files_; }
285 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
287 static synfig::String app_base_path_;
292 really_delete_widget(Gtk::Widget *widget)
294 // synfig::info("really delete %p", (void*)widget);
299 // nasty workaround - when we've finished with a popup menu, we want to delete it
300 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
301 // so schedule the real delete to happen in 50ms, giving the action a chance to run
303 delete_widget(Gtk::Widget *widget)
305 // synfig::info("delete %p", (void*)widget);
306 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
309 }; // END of namespace studio
310 studio::StateManager* state_manager;
315 class GlobalUIInterface : public synfigapp::UIInterface
319 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
324 true // use_separator
326 Gtk::Label label(message);
329 dialog.get_vbox()->pack_start(label);
330 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
331 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
333 dialog.set_default_response(dflt);
335 return (Response)dialog.run();
337 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
342 true // use_separator
344 Gtk::Label label(message);
347 dialog.get_vbox()->pack_start(label);
348 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
349 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
350 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
352 dialog.set_default_response(dflt);
354 return (Response)dialog.run();
356 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
361 true // use_separator
363 Gtk::Label label(message);
366 dialog.get_vbox()->pack_start(label);
367 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
368 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
370 dialog.set_default_response(dflt);
372 return (Response)dialog.run();
376 task(const std::string &task)
378 std::cerr<<task<<std::endl;
379 while(studio::App::events_pending())studio::App::iteration(false);
384 error(const std::string &err)
386 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
393 warning(const std::string &err)
395 std::cerr<<"warning: "<<err<<std::endl;
396 while(studio::App::events_pending())studio::App::iteration(false);
401 amount_complete(int /*current*/, int /*total*/)
403 while(studio::App::events_pending())studio::App::iteration(false);
408 /* === P R O C E D U R E S ================================================= */
412 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
414 action_group_list.push_back(action_group);
415 Gtk::UIManager::insert_action_group(action_group, pos);
419 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
421 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
422 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
423 if(*iter==action_group)
425 action_group_list.erase(iter);
426 Gtk::UIManager::remove_action_group(action_group);
429 synfig::error("Unable to find action group");
433 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
435 ui_manager->insert_action_group(group,0);
437 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
438 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
440 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
442 if(*iter && (*iter)->get_name()!="menus")
444 synfig::info("Removing action group "+(*iter)->get_name());
445 ui_manager->remove_action_group(*iter);
448 ui_manager->insert_action_group(group,0);
450 for(;!prev_groups.empty();prev_groups.pop_front())
452 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
453 ui_manager->insert_action_group(prev_groups.front(),1);
457 class Preferences : public synfigapp::Settings
460 virtual bool get_value(const synfig::String& key, synfig::String& value)const
464 value=strprintf("%f %f %f %f",
465 App::gamma.get_gamma_r(),
466 App::gamma.get_gamma_g(),
467 App::gamma.get_gamma_b(),
468 App::gamma.get_black_level()
472 if(key=="time_format")
474 value=strprintf("%i",App::get_time_format());
477 if(key=="file_history.size")
479 value=strprintf("%i",App::get_max_recent_files());
482 if(key=="use_colorspace_gamma")
484 value=strprintf("%i",(int)App::use_colorspace_gamma);
487 if(key=="distance_system")
489 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
492 #ifdef SINGLE_THREADED
493 if(key=="single_threaded")
495 value=strprintf("%i",(int)App::single_threaded);
499 if(key=="auto_recover_backup_interval")
501 value=strprintf("%i",App::auto_recover->get_timeout());
504 if(key=="restrict_radius_ducks")
506 value=strprintf("%i",(int)App::restrict_radius_ducks);
509 if(key=="browser_command")
511 value=App::browser_command;
515 return synfigapp::Settings::get_value(key,value);
518 virtual bool set_value(const synfig::String& key,const synfig::String& value)
524 strscanf(value,"%f %f %f %f",
531 App::gamma.set_all(r,g,b,blk);
535 if(key=="time_format")
537 int i(atoi(value.c_str()));
538 App::set_time_format(static_cast<synfig::Time::Format>(i));
541 if(key=="auto_recover_backup_interval")
543 int i(atoi(value.c_str()));
544 App::auto_recover->set_timeout(i);
547 if(key=="file_history.size")
549 int i(atoi(value.c_str()));
550 App::set_max_recent_files(i);
553 if(key=="use_colorspace_gamma")
555 int i(atoi(value.c_str()));
556 App::use_colorspace_gamma=i;
559 if(key=="distance_system")
561 App::distance_system=Distance::ident_system(value);;
564 #ifdef SINGLE_THREADED
565 if(key=="single_threaded")
567 int i(atoi(value.c_str()));
568 App::single_threaded=i;
572 if(key=="restrict_radius_ducks")
574 int i(atoi(value.c_str()));
575 App::restrict_radius_ducks=i;
578 if(key=="browser_command")
580 App::browser_command=value;
584 return synfigapp::Settings::set_value(key,value);
587 virtual KeyList get_key_list()const
589 KeyList ret(synfigapp::Settings::get_key_list());
590 ret.push_back("gamma");
591 ret.push_back("time_format");
592 ret.push_back("distance_system");
593 ret.push_back("file_history.size");
594 ret.push_back("use_colorspace_gamma");
595 #ifdef SINGLE_THREADED
596 ret.push_back("single_threaded");
598 ret.push_back("auto_recover_backup_interval");
599 ret.push_back("restrict_radius_ducks");
600 ret.push_back("browser_command");
605 static ::Preferences _preferences;
610 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
612 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
614 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
616 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
617 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
618 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
619 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
620 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
621 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
622 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
623 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
624 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
625 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
626 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
627 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
628 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
630 // Add the synfigapp actions...
631 synfigapp::Action::Book::iterator iter;
632 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
634 actions_action_group->add(Gtk::Action::create(
635 "action-"+iter->second.name,
636 get_action_stock_id(iter->second),
637 iter->second.local_name,iter->second.local_name
641 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
642 #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); }
643 #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); }
645 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
646 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
647 DEFINE_ACTION("new", Gtk::Stock::NEW);
648 DEFINE_ACTION("open", Gtk::Stock::OPEN);
649 DEFINE_ACTION("save", Gtk::Stock::SAVE);
650 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
651 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
652 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
653 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
654 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
655 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
656 DEFINE_ACTION("import", _("Import"));
657 DEFINE_ACTION("render", _("Render"));
658 DEFINE_ACTION("preview", _("Preview"));
659 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
660 DEFINE_ACTION("sound", _("Sound File"));
661 DEFINE_ACTION("options", _("Options"));
662 DEFINE_ACTION("close", _("Close View"));
663 DEFINE_ACTION("close-document", _("Close Document"));
664 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
667 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
668 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
669 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
670 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
671 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
672 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
673 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
674 DEFINE_ACTION("properties", _("Properties"));
676 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
677 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
678 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
679 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
680 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
681 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
682 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
683 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
684 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
685 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
686 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
687 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
688 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
689 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
690 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
691 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
692 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
693 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
694 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
695 DEFINE_ACTION("play", _("Play"));
696 // DEFINE_ACTION("pause", _("Pause"));
697 DEFINE_ACTION("stop", _("Stop"));
698 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
699 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
700 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
701 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
702 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
703 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
704 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
705 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
706 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
707 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
708 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
709 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
710 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
711 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
712 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
713 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
714 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
715 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
716 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
717 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
718 DEFINE_ACTION("seek-end", _("Seek to End"));
720 DEFINE_ACTION("action-group_add", _("Add group"));
722 DEFINE_ACTION("canvas-new", _("New Canvas"));
724 DEFINE_ACTION("amount-inc", _("Increase Amount"));
725 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
730 // Set up synfigapp actions
732 synfigapp::Action::Book::iterator iter;
734 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
736 Gtk::StockID stock_id;
738 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
740 //Gtk::Image* image(manage(new Gtk::Image()));
741 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
742 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
743 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
744 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
745 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
746 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
747 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
748 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
749 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
750 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
752 actions_action_group->add(Gtk::Action::create(
753 "action-"+iter->second.name,
755 iter->second.local_name,iter->second.local_name
763 Glib::ustring ui_info =
765 " <popup name='menu-toolbox' action='menu-toolbox'>"
766 " <menu action='menu-file'>"
769 " <popup name='menu-main' action='menu-main'>"
770 " <menu action='menu-file'>"
771 " <menuitem action='new' />"
772 " <menuitem action='open' />"
773 " <menuitem action='save' />"
774 " <menuitem action='save-as' />"
775 " <menuitem action='revert' />"
776 " <separator name='bleh01'/>"
777 " <menuitem action='cvs-add' />"
778 " <menuitem action='cvs-update' />"
779 " <menuitem action='cvs-commit' />"
780 " <menuitem action='cvs-revert' />"
781 " <separator name='bleh02'/>"
782 " <menuitem action='import' />"
783 " <separator name='bleh03'/>"
784 " <menuitem action='render' />"
785 " <menuitem action='preview' />"
786 " <menuitem action='sound' />"
787 " <separator name='bleh04'/>"
788 " <menuitem action='options' />"
789 " <menuitem action='close' />"
790 " <menuitem action='close-document' />"
791 " <menuitem action='quit' />"
793 " <menu action='menu-edit'>"
794 " <menuitem action='undo'/>"
795 " <menuitem action='redo'/>"
796 " <separator name='bleh05'/>"
797 " <menuitem action='cut'/>"
798 " <menuitem action='copy'/>"
799 " <menuitem action='paste'/>"
800 " <separator name='bleh06'/>"
801 " <menuitem action='select-all-ducks'/>"
802 " <menuitem action='unselect-all-layers'/>"
803 " <separator name='bleh07'/>"
804 " <menuitem action='properties'/>"
806 " <menu action='menu-view'>"
807 " <menu action='menu-duck-mask'>"
808 " <menuitem action='mask-position-ducks' />"
809 " <menuitem action='mask-vertex-ducks' />"
810 " <menuitem action='mask-tangent-ducks' />"
811 " <menuitem action='mask-radius-ducks' />"
812 " <menuitem action='mask-width-ducks' />"
813 " <menuitem action='mask-angle-ducks' />"
815 " <menu action='menu-preview-quality'>"
816 " <menuitem action='quality-00' />"
817 " <menuitem action='quality-01' />"
818 " <menuitem action='quality-02' />"
819 " <menuitem action='quality-03' />"
820 " <menuitem action='quality-04' />"
821 " <menuitem action='quality-05' />"
822 " <menuitem action='quality-06' />"
823 " <menuitem action='quality-07' />"
824 " <menuitem action='quality-08' />"
825 " <menuitem action='quality-09' />"
826 " <menuitem action='quality-10' />"
828 " <menu action='menu-lowres-pixel'>"
829 " <menuitem action='decrease-low-res-pixel-size'/>"
830 " <menuitem action='increase-low-res-pixel-size'/>"
831 " <separator name='pixel-size-separator'/>"
834 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
835 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
839 " <separator name='bleh08'/>"
840 " <menuitem action='play'/>"
841 //" <menuitem action='pause'/>"
842 " <menuitem action='stop'/>"
843 " <menuitem action='dialog-flipbook'/>"
844 " <separator name='bleh09'/>"
845 " <menuitem action='toggle-grid-show'/>"
846 " <menuitem action='toggle-grid-snap'/>"
847 " <menuitem action='toggle-guide-show'/>"
848 " <menuitem action='toggle-low-res'/>"
849 " <menuitem action='toggle-onion-skin'/>"
850 " <separator name='bleh10'/>"
851 " <menuitem action='canvas-zoom-in'/>"
852 " <menuitem action='canvas-zoom-out'/>"
853 " <menuitem action='canvas-zoom-fit'/>"
854 " <menuitem action='canvas-zoom-100'/>"
855 " <separator name='bleh11'/>"
856 " <menuitem action='time-zoom-in'/>"
857 " <menuitem action='time-zoom-out'/>"
858 " <separator name='bleh12'/>"
859 " <menuitem action='jump-next-keyframe'/>"
860 " <menuitem action='jump-prev-keyframe'/>"
861 " <menuitem action='seek-next-frame'/>"
862 " <menuitem action='seek-prev-frame'/>"
863 " <menuitem action='seek-next-second'/>"
864 " <menuitem action='seek-prev-second'/>"
865 " <menuitem action='seek-begin'/>"
866 " <menuitem action='seek-end'/>"
868 " <menu action='menu-canvas'>"
869 " <menuitem action='canvas-new'/>"
871 " <menu name='menu-state' action='menu-state'>"
873 " <menu action='menu-group'>"
874 " <menuitem action='action-group_add'/>"
876 " <menu action='menu-layer'>"
877 //" <menuitem action='cut'/>"
878 //" <menuitem action='copy'/>"
879 //" <menuitem action='paste'/>"
880 //" <separator name='bleh06'/>"
881 " <menu action='menu-layer-new'></menu>"
882 " <menuitem action='amount-inc'/>"
883 " <menuitem action='amount-dec'/>"
885 " <menu action='menu-keyframe'>"
886 " <menuitem action='keyframe-properties'/>"
893 " <menubar name='MenuBar'>"
894 " <menu action='MenuFile'>"
895 " <menuitem action='New'/>"
896 " <menuitem action='Open'/>"
898 " <menuitem action='Quit'/>"
900 " <menu action='MenuEdit'>"
901 " <menuitem action='Cut'/>"
902 " <menuitem action='Copy'/>"
903 " <menuitem action='Paste'/>"
906 " <toolbar name='ToolBar'>"
907 " <toolitem action='Open'/>"
908 " <toolitem action='Quit'/>"
914 actions_action_group->set_sensitive(false);
915 App::ui_manager()->set_add_tearoffs(true);
916 App::ui_manager()->insert_action_group(menus_action_group,1);
917 App::ui_manager()->insert_action_group(actions_action_group,1);
918 App::ui_manager()->add_ui_from_string(ui_info);
920 //App::ui_manager()->get_accel_group()->unlock();
922 catch(const Glib::Error& ex)
924 synfig::error("building menus and toolbars failed: " + ex.what());
927 // Add default keyboard accelerators
928 #define ACCEL(path,accel) \
930 Gtk::AccelKey accel_key(accel,path); \
931 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
934 #define ACCEL2(accel) \
936 Gtk::AccelKey accel_key(accel); \
937 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
940 ACCEL("<Actions>//select-all-ducks","<Control>a");
941 ACCEL("<Actions>//unselect-all-layers","<Control>d");
942 ACCEL("<Actions>//render","F9");
943 ACCEL("<Actions>//preview","F11");
944 ACCEL("<Actions>//properties","F8");
945 ACCEL("<Actions>//options","F12");
946 ACCEL("<Actions>//import","<control>i");
947 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
948 ACCEL("<Actions>//toggle-grid-show","<Control>g");
949 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
950 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
951 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
952 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
953 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
954 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
955 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
956 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
958 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
959 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
961 ACCEL("<Actions>//quality-01","<Control>1");
962 ACCEL("<Actions>//quality-02","<Control>2");
963 ACCEL("<Actions>//quality-03","<Control>3");
964 ACCEL("<Actions>//quality-04","<Control>4");
965 ACCEL("<Actions>//quality-05","<Control>5");
966 ACCEL("<Actions>//quality-06","<Control>6");
967 ACCEL("<Actions>//quality-07","<Control>7");
968 ACCEL("<Actions>//quality-08","<Control>8");
969 ACCEL("<Actions>//quality-09","<Control>9");
970 ACCEL("<Actions>//quality-10","<Control>0");
971 ACCEL("<Actions>//undo","<Control>z");
972 ACCEL("<Actions>//redo","<Control>r");
973 ACCEL("<Actions>//action-layer_remove","Delete");
975 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
976 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
977 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
978 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
979 ACCEL("<Actions>//time-zoom-in","+");
980 ACCEL("<Actions>//time-zoom-out","_");
982 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
983 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
985 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
986 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
988 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
989 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
990 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
991 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
992 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
993 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
994 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
995 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
996 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
997 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
998 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
999 ACCEL("<Actions>//play", "<Control>p");
1000 ACCEL("<Actions>//seek-begin","Home");
1001 ACCEL("<Actions>//seek-end","End");
1003 ACCEL("<Actions>//state-normal", "<Mod1>a");
1004 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1005 ACCEL("<Actions>//state-scale", "<Mod1>s");
1006 ACCEL("<Actions>//state-rotate", "<Mod1>t");
1008 ACCEL("<Actions>//state-bline", "<Mod1>b");
1009 ACCEL("<Actions>//state-circle", "<Mod1>c");
1010 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1011 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1013 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1014 ACCEL("<Actions>//state-fill", "<Mod1>f");
1015 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1016 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1018 ACCEL("<Actions>//state-draw", "<Mod1>w");
1019 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1020 ACCEL("<Actions>//state-width", "<Mod1>t");
1021 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1023 ACCEL("<Actions>//state-text", "<Mod1>x");
1024 ACCEL("<Actions>//state-star", "<Mod1>q");
1026 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1032 #define mkdir(x,y) mkdir(x)
1035 /* === M E T H O D S ======================================================= */
1037 App::App(int *argc, char ***argv):
1038 Gtk::Main(argc,argv),
1039 IconController(etl::dirname((*argv)[0]))
1041 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1044 ui_interface_=new GlobalUIInterface();
1048 // don't call thread_init() if threads are already initialized
1049 // on some machines bonobo_init() initialized threads before we get here
1050 if (!g_thread_supported())
1051 Glib::thread_init();
1053 distance_system=Distance::SYSTEM_UNITS;
1055 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1058 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1062 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1068 if(!SYNFIG_CHECK_VERSION())
1070 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1071 dialog_error_blocking("Synfig Studio",
1072 "This copy of Synfig Studio was compiled against a\n"
1073 "different version of libsynfig than what is currently\n"
1074 "installed. Synfig Studio will now abort. Try downloading\n"
1075 "the latest version from the Synfig website at\n"
1076 "http://synfig.org/Download"
1080 Glib::set_application_name(_("Synfig Studio"));
1082 Splash splash_screen;
1083 splash_screen.show();
1085 shutdown_in_progress=false;
1086 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1087 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1089 // Initialize the Synfig library
1090 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1093 get_ui_interface()->error(_("Failed to initialize synfig!"));
1097 // add the preferences to the settings
1098 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1102 studio_init_cb.task(_("Init UI Manager..."));
1103 App::ui_manager_=studio::UIManager::create();
1106 studio_init_cb.task(_("Init Dock Manager..."));
1107 dock_manager=new studio::DockManager();
1109 studio_init_cb.task(_("Init State Manager..."));
1110 state_manager=new StateManager();
1112 studio_init_cb.task(_("Init Toolbox..."));
1113 toolbox=new studio::Toolbox();
1115 studio_init_cb.task(_("Init About Dialog..."));
1116 about=new studio::About();
1118 studio_init_cb.task(_("Init Tool Options..."));
1119 dialog_tool_options=new studio::Dialog_ToolOptions();
1120 dock_manager->register_dockable(*dialog_tool_options);
1122 studio_init_cb.task(_("Init History..."));
1123 dock_history=new studio::Dock_History();
1124 dock_manager->register_dockable(*dock_history);
1126 studio_init_cb.task(_("Init Canvases..."));
1127 dock_canvases=new studio::Dock_Canvases();
1128 dock_manager->register_dockable(*dock_canvases);
1130 studio_init_cb.task(_("Init Keyframes..."));
1131 dock_keyframes=new studio::Dock_Keyframes();
1132 dock_manager->register_dockable(*dock_keyframes);
1134 studio_init_cb.task(_("Init Layers..."));
1135 dock_layers=new studio::Dock_Layers();
1136 dock_manager->register_dockable(*dock_layers);
1138 studio_init_cb.task(_("Init Params..."));
1139 dock_params=new studio::Dock_Params();
1140 dock_manager->register_dockable(*dock_params);
1142 studio_init_cb.task(_("Init MetaData..."));
1143 dock_meta_data=new studio::Dock_MetaData();
1144 dock_manager->register_dockable(*dock_meta_data);
1146 studio_init_cb.task(_("Init Children..."));
1147 dock_children=new studio::Dock_Children();
1148 dock_manager->register_dockable(*dock_children);
1150 studio_init_cb.task(_("Init Info..."));
1151 dock_info = new studio::Dock_Info();
1152 dock_manager->register_dockable(*dock_info);
1154 studio_init_cb.task(_("Init Navigator..."));
1155 dock_navigator = new studio::Dock_Navigator();
1156 dock_manager->register_dockable(*dock_navigator);
1158 studio_init_cb.task(_("Init Timetrack..."));
1159 dock_timetrack = new studio::Dock_Timetrack();
1160 dock_manager->register_dockable(*dock_timetrack);
1162 studio_init_cb.task(_("Init Curve Editor..."));
1163 dock_curves = new studio::Dock_Curves();
1164 dock_manager->register_dockable(*dock_curves);
1166 studio_init_cb.task(_("Init Layer Groups..."));
1167 dock_layer_groups = new studio::Dock_LayerGroups();
1168 dock_manager->register_dockable(*dock_layer_groups);
1171 studio_init_cb.task(_("Init Color Dialog..."));
1172 dialog_color=new studio::Dialog_Color();
1174 studio_init_cb.task(_("Init Gradient Dialog..."));
1175 dialog_gradient=new studio::Dialog_Gradient();
1177 studio_init_cb.task(_("Init DeviceTracker..."));
1178 device_tracker=new studio::DeviceTracker();
1180 studio_init_cb.task(_("Init Tools..."));
1183 state_manager->add_state(&state_normal);
1184 state_manager->add_state(&state_smooth_move);
1185 state_manager->add_state(&state_scale);
1186 state_manager->add_state(&state_rotate);
1187 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1190 state_manager->add_state(&state_circle);
1191 state_manager->add_state(&state_rectangle);
1192 state_manager->add_state(&state_star);
1193 state_manager->add_state(&state_gradient);
1194 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1197 state_manager->add_state(&state_bline);
1198 state_manager->add_state(&state_text);
1199 state_manager->add_state(&state_fill);
1200 state_manager->add_state(&state_eyedrop);
1201 state_manager->add_state(&state_zoom);
1203 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1204 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1206 // Disabled by default - it doesn't work properly?
1207 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1209 studio_init_cb.task(_("Init ModPalette..."));
1210 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1212 studio_init_cb.task(_("Init Setup Dialog..."));
1213 dialog_setup=new studio::Dialog_Setup();
1215 studio_init_cb.task(_("Init Input Dialog..."));
1216 dialog_input=new Gtk::InputDialog();
1217 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1218 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1220 studio_init_cb.task(_("Init auto recovery..."));
1221 auto_recover=new AutoRecover();
1223 studio_init_cb.amount_complete(9250,10000);
1224 studio_init_cb.task(_("Loading Settings..."));
1226 studio_init_cb.task(_("Checking auto-recover..."));
1228 studio_init_cb.amount_complete(9900,10000);
1230 bool opened_any = false;
1231 if(auto_recover->recovery_needed())
1233 splash_screen.hide();
1234 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1235 _("Synfig Studio seems to have crashed\n"
1236 "before you could save all your files.\n"
1237 "Would you like to re-open those files\n"
1238 "and recover your unsaved changes?")) ==
1239 synfigapp::UIInterface::RESPONSE_YES)
1241 int number_recovered;
1242 if(!auto_recover->recover(number_recovered))
1243 if (number_recovered)
1244 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1246 get_ui_interface()->error(_("Unable to recover from previous crash"));
1248 get_ui_interface()->error(
1249 _("Synfig Studio has attempted to recover\n"
1250 "from a previous crash. The files that it has\n"
1251 "recovered are NOT YET SAVED. It would be a good\n"
1252 "idea to review them and save them now."));
1254 if (number_recovered)
1257 splash_screen.show();
1260 // Look for any files given on the command line,
1261 // and load them if found.
1262 for(;*argc>=1;(*argc)--)
1263 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1265 studio_init_cb.task(_("Loading files..."));
1266 splash_screen.hide();
1267 open((*argv)[*argc]);
1269 splash_screen.show();
1272 // if no file was specified to be opened, create a new document to help new users get started more easily
1273 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1276 studio_init_cb.task(_("Done."));
1277 studio_init_cb.amount_complete(10000,10000);
1283 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1287 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1291 StateManager* App::get_state_manager() { return state_manager; }
1295 shutdown_in_progress=true;
1299 synfigapp::Main::settings().remove_domain("pref");
1301 selected_instance=0;
1303 // Unload all of the modules
1304 for(;!module_list_.empty();module_list_.pop_back())
1307 delete state_manager;
1311 delete auto_recover;
1317 // studio::App::iteration(false);
1321 // studio::App::iteration(false);
1323 // studio::App::iteration(false);
1325 delete dialog_setup;
1327 delete dialog_gradient;
1329 delete dialog_color;
1331 delete dialog_input;
1333 delete dock_manager;
1335 instance_list.clear();
1337 // studio::App::iteration(false);
1341 App::get_user_app_directory()
1343 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1345 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1347 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1352 App::get_config_file(const synfig::String& file)
1354 return Glib::build_filename(get_user_app_directory(),file);
1357 #define SCALE_FACTOR (1280)
1358 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1360 App::set_recent_file_window_size(etl::handle<Instance> instance)
1362 int screen_w(Gdk::screen_width());
1363 int screen_h(Gdk::screen_height());
1365 const std::string &canvas_window_size = *recent_files_window_size.begin();
1367 if(canvas_window_size.empty())
1370 synfig::String::size_type current=0;
1371 bool seen_root(false), shown_non_root(false);
1373 while(current != synfig::String::npos)
1375 // find end of first field (canvas) or return
1376 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1377 if(separator == synfig::String::npos) break;
1380 synfig::Canvas::Handle canvas;
1382 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current));
1384 catch(Exception::IDNotFound) {
1385 // can't find the canvas; skip to the next canvas or return
1386 separator = canvas_window_size.find_first_of('\t', current);
1387 if(separator == synfig::String::npos) return;
1388 current = separator+1;
1392 if (canvas->is_root())
1395 shown_non_root = true;
1397 // check that we have the tab character the ends this canvas' data or return
1398 current = separator+1;
1399 separator = canvas_window_size.find_first_of('\t', current);
1400 if(separator == synfig::String::npos) return;
1403 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1405 current = separator+1;
1409 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1410 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1411 x=x*screen_w/SCALE_FACTOR;
1412 y=y*screen_h/SCALE_FACTOR;
1413 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1414 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1415 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1416 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1418 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1419 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1421 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1422 canvasview->move(x,y);
1423 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1424 canvasview->present();
1426 current = separator+1;
1429 if (shown_non_root && !seen_root)
1430 instance->find_canvas_view(instance->get_canvas())->hide();
1434 App::add_recent_file(const etl::handle<Instance> instance)
1436 int screen_w(Gdk::screen_width());
1437 int screen_h(Gdk::screen_height());
1439 std::string canvas_window_size;
1441 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1442 Instance::CanvasViewList::const_iterator iter;
1444 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1446 if( !((*iter)->is_visible()) )
1449 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1450 int x_pos, y_pos, x_size, y_size;
1451 (*iter)->get_position(x_pos,y_pos);
1452 (*iter)->get_size(x_size,y_size);
1454 canvas_window_size += strprintf("%s %d %d %d %d\t",
1455 canvas->get_relative_id(canvas->get_root()).c_str(),
1456 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1457 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1460 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1465 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1467 std::string filename(file_name);
1469 assert(!filename.empty());
1471 if(filename.empty())
1474 // Toss out any "hidden" files
1475 if(basename(filename)[0]=='.')
1478 // If we aren't an absolute path, turn ourselves into one
1479 if(!is_absolute_path(filename))
1480 filename=absolute_path(filename);
1482 std::string old_window_size;
1484 list<string>::iterator iter;
1485 list<string>::iterator iter_wsize;
1486 // Check to see if the file is already on the list.
1487 // If it is, then remove it from the list
1488 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1491 recent_files.erase(iter);
1492 old_window_size = *iter_wsize;
1493 recent_files_window_size.erase(iter_wsize);
1498 // Push the filename to the front of the list
1499 recent_files.push_front(filename);
1500 if(window_size.empty())
1501 recent_files_window_size.push_front(old_window_size);
1503 recent_files_window_size.push_front(window_size);
1505 // Clean out the files at the end of the list.
1506 while(recent_files.size()>(unsigned)get_max_recent_files())
1508 recent_files.pop_back();
1509 recent_files_window_size.pop_back();
1512 signal_recent_files_changed_();
1517 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1520 App::get_time_format()
1522 return _App_time_format;
1526 App::set_time_format(synfig::Time::Format x)
1533 App::save_settings()
1538 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1539 setlocale(LC_NUMERIC, "C");
1541 std::string filename=get_config_file("accelrc");
1542 Gtk::AccelMap::save(filename);
1545 std::string filename=get_config_file("recentfiles");
1547 std::ofstream file(filename.c_str());
1551 synfig::warning("Unable to save %s",filename.c_str());
1555 list<string>::reverse_iterator iter;
1557 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1561 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1563 std::ofstream file(filename.c_str());
1567 synfig::warning("Unable to save %s",filename.c_str());
1571 list<string>::reverse_iterator iter;
1573 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1577 std::string filename=get_config_file("settings");
1578 synfigapp::Main::settings().save_to_file(filename);
1579 setlocale(LC_NUMERIC,old_locale);
1583 synfig::warning("Caught exception when attempting to save settings.");
1588 App::load_settings()
1593 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1594 setlocale(LC_NUMERIC, "C");
1596 std::string filename=get_config_file("accelrc");
1597 Gtk::AccelMap::load(filename);
1600 bool window_size_broken = false;
1602 std::string filename=get_config_file("recentfiles");
1603 std::string filename_window_size=filename+std::string("_window_size");
1605 std::ifstream file(filename.c_str());
1606 std::ifstream file_window_size(filename_window_size.c_str());
1608 if(!file_window_size)
1609 window_size_broken = true;
1613 std::string recent_file;
1614 std::string recent_file_window_size;
1615 getline(file,recent_file);
1616 if(!window_size_broken)
1617 getline(file_window_size,recent_file_window_size);
1618 if(!recent_file.empty())
1620 if(!window_size_broken && !file_window_size)
1621 window_size_broken = true;
1622 if(!window_size_broken)
1623 add_recent_file(recent_file,recent_file_window_size);
1625 add_recent_file(recent_file);
1628 if(!window_size_broken && file_window_size)
1629 window_size_broken = true;
1631 if(window_size_broken)
1633 recent_files_window_size.clear();
1634 recent_files_window_size.resize(recent_files.size());
1637 std::string filename=get_config_file("settings");
1638 if(!synfigapp::Main::settings().load_from_file(filename))
1640 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1641 //if(!synfigapp::Main::settings().load_from_file(filename))
1643 gamma.set_gamma(1.0/2.2);
1644 reset_initial_window_configuration();
1647 setlocale(LC_NUMERIC,old_locale);
1651 synfig::warning("Caught exception when attempting to load settings.");
1656 App::reset_initial_window_configuration()
1658 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1659 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1660 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1661 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1662 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1663 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1664 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1665 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1666 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1667 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1668 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1669 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1670 #ifdef SINGLE_THREADED
1671 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1673 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1674 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1678 App::shutdown_request(GdkEventAny*)
1682 //return !shutdown_in_progress;
1688 if(shutdown_in_progress)return;
1691 get_ui_interface()->task(_("Quit Request"));
1694 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1698 std::list<etl::handle<Instance> >::iterator iter;
1699 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1701 if(!(*iter)->safe_close())
1705 if((*iter)->synfigapp::Instance::get_action_count())
1707 handle<synfigapp::UIInterface> uim;
1708 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1710 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1711 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1713 case synfigapp::UIInterface::RESPONSE_NO:
1715 case synfigapp::UIInterface::RESPONSE_YES:
1718 case synfigapp::UIInterface::RESPONSE_CANCEL:
1727 if((*iter)->synfigapp::Instance::is_modified())
1729 handle<synfigapp::UIInterface> uim;
1730 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1732 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() );
1733 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1735 case synfigapp::UIInterface::RESPONSE_NO:
1737 case synfigapp::UIInterface::RESPONSE_YES:
1738 (*iter)->dialog_cvs_commit();
1740 case synfigapp::UIInterface::RESPONSE_CANCEL:
1749 // This next line causes things to crash for some reason
1753 shutdown_in_progress=true;
1755 instance_list.clear();
1757 while(studio::App::events_pending())studio::App::iteration(false);
1760 auto_recover->normal_shutdown();
1762 get_ui_interface()->task(_("Quit Request sent"));
1768 dialog_setup->refresh();
1769 dialog_setup->show();
1772 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1773 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1776 //#define USE_WIN32_FILE_DIALOGS 1
1779 #ifdef USE_WIN32_FILE_DIALOGS
1780 static OPENFILENAME ofn={};
1784 #include <gdk/gdkwin32.h>
1788 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1790 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1792 #ifdef USE_WIN32_FILE_DIALOGS
1793 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1795 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1796 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1797 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1799 ofn.lStructSize=sizeof(OPENFILENAME);
1800 ofn.hwndOwner = hWnd;
1801 ofn.hInstance = hInstance;
1802 ofn.lpstrFilter = szFilter;
1803 // ofn.lpstrCustomFilter=NULL;
1804 // ofn.nMaxCustFilter=0;
1805 // ofn.nFilterIndex=0;
1806 // ofn.lpstrFile=NULL;
1807 ofn.nMaxFile=MAX_PATH;
1808 // ofn.lpstrFileTitle=NULL;
1809 // ofn.lpstrInitialDir=NULL;
1810 // ofn.lpstrTitle=NULL;
1811 ofn.Flags=OFN_HIDEREADONLY;
1812 // ofn.nFileOffset=0;
1813 // ofn.nFileExtension=0;
1814 ofn.lpstrDefExt=TEXT("sif");
1815 // ofn.lCustData = 0l;
1817 // ofn.lpTemplateName=NULL;
1819 CHAR szFilename[MAX_PATH];
1821 strcpy(szFilename,filename.c_str());
1822 strcpy(szTitle,title.c_str());
1824 ofn.lpstrFile=szFilename;
1825 ofn.lpstrFileTitle=szTitle;
1827 if(GetOpenFileName(&ofn))
1829 filename=szFilename;
1835 synfig::String prev_path;
1837 if(!_preferences.get_value(preference, prev_path))
1840 prev_path = absolute_path(prev_path);
1842 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1844 dialog->set_current_folder(prev_path);
1845 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1846 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1848 if (filename.empty())
1849 dialog->set_filename(prev_path);
1850 else if (is_absolute_path(filename))
1851 dialog->set_filename(filename);
1853 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1855 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1856 filename = dialog->get_filename();
1857 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1858 _preferences.set_value(preference, dirname(filename));
1872 GtkWidget *fileselection;
1873 fileselection = gtk_file_selection_new(title.c_str());
1876 if(basename(filename)==filename)
1878 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1881 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1883 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1885 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1886 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1888 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1889 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1891 gtk_widget_show(fileselection);
1899 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1900 _preferences.set_value(preference,dirname(filename));
1904 gtk_widget_destroy(fileselection);
1907 gtk_widget_destroy(fileselection);
1914 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1916 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1918 #if USE_WIN32_FILE_DIALOGS
1919 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1921 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1922 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1923 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1925 ofn.lStructSize=sizeof(OPENFILENAME);
1926 ofn.hwndOwner = hWnd;
1927 ofn.hInstance = hInstance;
1928 ofn.lpstrFilter = szFilter;
1929 // ofn.lpstrCustomFilter=NULL;
1930 // ofn.nMaxCustFilter=0;
1931 // ofn.nFilterIndex=0;
1932 // ofn.lpstrFile=NULL;
1933 ofn.nMaxFile=MAX_PATH;
1934 // ofn.lpstrFileTitle=NULL;
1935 // ofn.lpstrInitialDir=NULL;
1936 // ofn.lpstrTitle=NULL;
1937 ofn.Flags=OFN_OVERWRITEPROMPT;
1938 // ofn.nFileOffset=0;
1939 // ofn.nFileExtension=0;
1940 ofn.lpstrDefExt=TEXT("sif");
1941 // ofn.lCustData = 0l;
1943 // ofn.lpTemplateName=NULL;
1945 CHAR szFilename[MAX_PATH];
1947 strcpy(szFilename,filename.c_str());
1948 strcpy(szTitle,title.c_str());
1950 ofn.lpstrFile=szFilename;
1951 ofn.lpstrFileTitle=szTitle;
1953 if(GetSaveFileName(&ofn))
1955 filename=szFilename;
1956 _preferences.set_value(preference,dirname(filename));
1961 synfig::String prev_path;
1963 if(!_preferences.get_value(preference, prev_path))
1966 prev_path = absolute_path(prev_path);
1968 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1970 dialog->set_current_folder(prev_path);
1971 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1972 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1974 Widget_Enum *file_type_enum = 0;
1975 if (preference == ANIMATION_DIR_PREFERENCE)
1977 file_type_enum = manage(new Widget_Enum());
1978 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
1979 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
1980 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
1981 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
1982 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
1983 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
1985 Gtk::HBox *hbox = manage(new Gtk::HBox);
1986 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
1987 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
1990 dialog->set_extra_widget(*hbox);
1993 if (filename.empty())
1994 dialog->set_filename(prev_path);
1997 std::string full_path;
1998 if (is_absolute_path(filename))
1999 full_path = filename;
2001 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2003 // select the file if it exists
2004 dialog->set_filename(full_path);
2006 // if the file doesn't exist, put its name into the filename box
2008 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2009 dialog->set_current_name(basename(filename));
2012 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2013 if (preference == ANIMATION_DIR_PREFERENCE)
2014 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2015 filename = dialog->get_filename();
2016 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2017 _preferences.set_value(preference, dirname(filename));
2028 App::dialog_error_blocking(const std::string &title, const std::string &message)
2030 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2031 dialog.set_title(title);
2037 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2039 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2040 dialog.set_title(title);
2046 App::dialog_yes_no(const std::string &title, const std::string &message)
2051 true // use_separator
2053 Gtk::Label label(message);
2056 dialog.get_vbox()->pack_start(label);
2057 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2058 dialog.add_button(Gtk::StockID("gtk-no"),0);
2060 return dialog.run();
2064 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2069 true // use_separator
2071 Gtk::Label label(message);
2074 dialog.get_vbox()->pack_start(label);
2075 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2076 dialog.add_button(Gtk::StockID("gtk-no"),0);
2077 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2079 return dialog.run();
2083 App::dialog_not_implemented()
2085 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2086 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2091 try_open_url(const std::string &url)
2094 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2096 std::vector<std::string> command_line;
2097 std::vector<std::string> browsers;
2098 browsers.reserve(23);
2100 // Browser wrapper scripts
2101 #ifdef USE_OPEN_FOR_URLS
2102 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2104 browsers.push_back("xdg-open"); // XDG wrapper
2105 browsers.push_back("sensible-browser"); // Debian wrapper
2106 browsers.push_back("gnome-open"); // GNOME wrapper
2107 browsers.push_back("kfmclient"); // KDE wrapper
2108 browsers.push_back("exo-open"); // XFCE wrapper
2110 // Alternatives system
2111 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2112 browsers.push_back("x-www-browser"); // Debian GUI alternative
2114 // Individual browsers
2115 browsers.push_back("firefox");
2116 browsers.push_back("epiphany-browser");
2117 browsers.push_back("epiphany");
2118 browsers.push_back("konqueror");
2119 browsers.push_back("iceweasel");
2120 browsers.push_back("mozilla");
2121 browsers.push_back("netscape");
2122 browsers.push_back("icecat");
2123 browsers.push_back("galeon");
2124 browsers.push_back("midori");
2125 browsers.push_back("safari");
2126 browsers.push_back("opera");
2127 browsers.push_back("amaya");
2128 browsers.push_back("netsurf");
2129 browsers.push_back("dillo");
2131 // Try the user-specified browser first
2132 command_line.push_back(App::browser_command);
2133 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2134 command_line.push_back(url);
2136 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2137 catch( Glib::SpawnError& exception ){
2139 while ( !browsers.empty() )
2141 // Skip the browser if we already tried it
2142 if( browsers[0] == App::browser_command )
2145 // Construct the command line
2146 command_line.clear();
2147 command_line.push_back(browsers[0]);
2148 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2149 command_line.push_back(url);
2151 // Remove the browser from the list
2152 browsers.erase(browsers.begin());
2154 // Try to spawn the browser
2155 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2156 // Failed, move on to the next one
2157 catch(Glib::SpawnError& exception){ continue; }
2158 return true; // No exception means we succeeded!
2169 if (!try_open_url("http://synfig.org/Documentation"))
2171 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2172 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2173 dialog.set_title(_("Help"));
2179 App::open_url(const std::string &url)
2181 if(!try_open_url(url))
2183 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2184 dialog.set_secondary_text(url);
2185 dialog.set_title(_("No browser found"));
2191 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2196 true); // use_separator
2198 Gtk::Label label(message);
2200 dialog.get_vbox()->pack_start(label);
2203 entry.set_text(text);
2205 entry.set_activates_default(true);
2207 dialog.get_vbox()->pack_start(entry);
2209 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2210 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2211 dialog.set_default_response(Gtk::RESPONSE_OK);
2213 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2216 if(dialog.run()!=Gtk::RESPONSE_OK)
2219 text=entry.get_text();
2225 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2230 true); // use_separator
2232 Gtk::Label label(message);
2234 dialog.get_vbox()->pack_start(label);
2236 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2237 text_buffer->set_text(text);
2238 Gtk::TextView text_view(text_buffer);
2241 dialog.get_vbox()->pack_start(text_view);
2243 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2244 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2245 dialog.set_default_response(Gtk::RESPONSE_OK);
2247 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2250 if(dialog.run()!=Gtk::RESPONSE_OK)
2253 text=text_buffer->get_text();
2259 App::open(std::string filename)
2261 return open_as(filename,filename);
2264 // this is called from autorecover.cpp:
2265 // App::open_as(get_shadow_file_name(filename),filename)
2266 // other than that, 'filename' and 'as' are the same
2268 App::open_as(std::string filename,std::string as)
2271 char long_name[1024];
2272 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2273 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2274 // don't use it if that's the case
2275 if (long_name[0] != '\0')
2281 OneMoment one_moment;
2283 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
2284 if(canvas && get_instance(canvas))
2286 get_instance(canvas)->find_canvas_view(canvas)->present();
2287 info("%s is already open", filename.c_str());
2288 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2293 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2295 if (as.find(DEFAULT_FILENAME_PREFIX) != 0)
2296 add_recent_file(as);
2298 handle<Instance> instance(Instance::create(canvas));
2301 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2303 set_recent_file_window_size(instance);
2307 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)")))
2308 instance->dialog_cvs_update();
2313 dialog_error_blocking(_("Error"), x);
2318 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2329 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2331 String file_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2332 canvas->set_name(file_name);
2333 file_name += ".sifz";
2335 canvas->rend_desc().set_frame_rate(24.0);
2336 canvas->rend_desc().set_time_start(0.0);
2337 canvas->rend_desc().set_time_end(5.0);
2338 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2339 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2340 canvas->rend_desc().set_tl(Vector(-4,2.25));
2341 canvas->rend_desc().set_br(Vector(4,-2.25));
2342 canvas->rend_desc().set_w(480);
2343 canvas->rend_desc().set_h(270);
2344 canvas->rend_desc().set_antialias(1);
2345 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2346 canvas->set_file_name(file_name);
2348 handle<Instance> instance = Instance::create(canvas);
2350 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2351 instance->find_canvas_view(canvas)->canvas_properties.present();
2355 App::dialog_open(string filename)
2357 if (filename.empty())
2360 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2362 // If the filename still has wildcards, then we should
2363 // continue looking for the file we want
2364 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2370 get_ui_interface()->error(_("Unable to open file"));
2375 App::set_selected_instance(etl::loose_handle<Instance> instance)
2377 /* if(get_selected_instance()==instance)
2379 selected_instance=instance;
2380 signal_instance_selected()(instance);
2386 selected_instance=instance;
2387 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2391 instance->focus(instance->get_canvas());
2394 set_selected_canvas_view(0);
2396 signal_instance_selected()(instance);
2400 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2402 selected_canvas_view=canvas_view;
2403 signal_canvas_view_focus()(selected_canvas_view);
2406 selected_instance=canvas_view->get_instance();
2407 signal_instance_selected()(canvas_view->get_instance());
2410 if(get_selected_canvas_view()==canvas_view)
2412 signal_canvas_view_focus()(selected_canvas_view);
2413 signal_instance_selected()(canvas_view->get_instance());
2416 selected_canvas_view=canvas_view;
2417 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2418 set_selected_instance(canvas_view->get_instance());
2419 signal_canvas_view_focus()(selected_canvas_view);
2423 etl::loose_handle<Instance>
2424 App::get_instance(etl::handle<synfig::Canvas> canvas)
2426 if(!canvas) return 0;
2427 canvas=canvas->get_root();
2429 std::list<etl::handle<Instance> >::iterator iter;
2430 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2432 if((*iter)->get_canvas()==canvas)
2448 if(selected_instance)
2449 selected_instance->undo();
2455 if(selected_instance)
2456 selected_instance->redo();
2460 studio::App::get_base_path()
2462 return app_base_path_;