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");
1007 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1009 ACCEL("<Actions>//state-circle", "<Mod1>c");
1010 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1011 ACCEL("<Actions>//state-star", "<Mod1>q");
1012 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1013 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1015 ACCEL("<Actions>//state-bline", "<Mod1>b");
1016 ACCEL("<Actions>//state-text", "<Mod1>x");
1017 ACCEL("<Actions>//state-fill", "<Mod1>f");
1018 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1019 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1021 ACCEL("<Actions>//state-draw", "<Mod1>w");
1022 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1023 ACCEL("<Actions>//state-width", "<Mod1>t");
1025 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1031 #define mkdir(x,y) mkdir(x)
1034 /* === M E T H O D S ======================================================= */
1036 App::App(int *argc, char ***argv):
1037 Gtk::Main(argc,argv),
1038 IconController(etl::dirname((*argv)[0]))
1040 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1043 ui_interface_=new GlobalUIInterface();
1047 // don't call thread_init() if threads are already initialized
1048 // on some machines bonobo_init() initialized threads before we get here
1049 if (!g_thread_supported())
1050 Glib::thread_init();
1052 distance_system=Distance::SYSTEM_UNITS;
1054 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1057 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1061 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1067 if(!SYNFIG_CHECK_VERSION())
1069 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1070 dialog_error_blocking("Synfig Studio",
1071 "This copy of Synfig Studio was compiled against a\n"
1072 "different version of libsynfig than what is currently\n"
1073 "installed. Synfig Studio will now abort. Try downloading\n"
1074 "the latest version from the Synfig website at\n"
1075 "http://synfig.org/Download"
1079 Glib::set_application_name(_("Synfig Studio"));
1081 Splash splash_screen;
1082 splash_screen.show();
1084 shutdown_in_progress=false;
1085 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1086 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1088 // Initialize the Synfig library
1089 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1092 get_ui_interface()->error(_("Failed to initialize synfig!"));
1096 // add the preferences to the settings
1097 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1101 studio_init_cb.task(_("Init UI Manager..."));
1102 App::ui_manager_=studio::UIManager::create();
1105 studio_init_cb.task(_("Init Dock Manager..."));
1106 dock_manager=new studio::DockManager();
1108 studio_init_cb.task(_("Init State Manager..."));
1109 state_manager=new StateManager();
1111 studio_init_cb.task(_("Init Toolbox..."));
1112 toolbox=new studio::Toolbox();
1114 studio_init_cb.task(_("Init About Dialog..."));
1115 about=new studio::About();
1117 studio_init_cb.task(_("Init Tool Options..."));
1118 dialog_tool_options=new studio::Dialog_ToolOptions();
1119 dock_manager->register_dockable(*dialog_tool_options);
1121 studio_init_cb.task(_("Init History..."));
1122 dock_history=new studio::Dock_History();
1123 dock_manager->register_dockable(*dock_history);
1125 studio_init_cb.task(_("Init Canvases..."));
1126 dock_canvases=new studio::Dock_Canvases();
1127 dock_manager->register_dockable(*dock_canvases);
1129 studio_init_cb.task(_("Init Keyframes..."));
1130 dock_keyframes=new studio::Dock_Keyframes();
1131 dock_manager->register_dockable(*dock_keyframes);
1133 studio_init_cb.task(_("Init Layers..."));
1134 dock_layers=new studio::Dock_Layers();
1135 dock_manager->register_dockable(*dock_layers);
1137 studio_init_cb.task(_("Init Params..."));
1138 dock_params=new studio::Dock_Params();
1139 dock_manager->register_dockable(*dock_params);
1141 studio_init_cb.task(_("Init MetaData..."));
1142 dock_meta_data=new studio::Dock_MetaData();
1143 dock_manager->register_dockable(*dock_meta_data);
1145 studio_init_cb.task(_("Init Children..."));
1146 dock_children=new studio::Dock_Children();
1147 dock_manager->register_dockable(*dock_children);
1149 studio_init_cb.task(_("Init Info..."));
1150 dock_info = new studio::Dock_Info();
1151 dock_manager->register_dockable(*dock_info);
1153 studio_init_cb.task(_("Init Navigator..."));
1154 dock_navigator = new studio::Dock_Navigator();
1155 dock_manager->register_dockable(*dock_navigator);
1157 studio_init_cb.task(_("Init Timetrack..."));
1158 dock_timetrack = new studio::Dock_Timetrack();
1159 dock_manager->register_dockable(*dock_timetrack);
1161 studio_init_cb.task(_("Init Curve Editor..."));
1162 dock_curves = new studio::Dock_Curves();
1163 dock_manager->register_dockable(*dock_curves);
1165 studio_init_cb.task(_("Init Layer Groups..."));
1166 dock_layer_groups = new studio::Dock_LayerGroups();
1167 dock_manager->register_dockable(*dock_layer_groups);
1170 studio_init_cb.task(_("Init Color Dialog..."));
1171 dialog_color=new studio::Dialog_Color();
1173 studio_init_cb.task(_("Init Gradient Dialog..."));
1174 dialog_gradient=new studio::Dialog_Gradient();
1176 studio_init_cb.task(_("Init DeviceTracker..."));
1177 device_tracker=new studio::DeviceTracker();
1179 studio_init_cb.task(_("Init Tools..."));
1182 state_manager->add_state(&state_normal);
1183 state_manager->add_state(&state_smooth_move);
1184 state_manager->add_state(&state_scale);
1185 state_manager->add_state(&state_rotate);
1186 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1189 state_manager->add_state(&state_circle);
1190 state_manager->add_state(&state_rectangle);
1191 state_manager->add_state(&state_star);
1192 state_manager->add_state(&state_gradient);
1193 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1196 state_manager->add_state(&state_bline);
1197 state_manager->add_state(&state_text);
1198 state_manager->add_state(&state_fill);
1199 state_manager->add_state(&state_eyedrop);
1200 state_manager->add_state(&state_zoom);
1202 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1203 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1205 // Disabled by default - it doesn't work properly?
1206 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1208 studio_init_cb.task(_("Init ModPalette..."));
1209 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1211 studio_init_cb.task(_("Init Setup Dialog..."));
1212 dialog_setup=new studio::Dialog_Setup();
1214 studio_init_cb.task(_("Init Input Dialog..."));
1215 dialog_input=new Gtk::InputDialog();
1216 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1217 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1219 studio_init_cb.task(_("Init auto recovery..."));
1220 auto_recover=new AutoRecover();
1222 studio_init_cb.amount_complete(9250,10000);
1223 studio_init_cb.task(_("Loading Settings..."));
1225 studio_init_cb.task(_("Checking auto-recover..."));
1227 studio_init_cb.amount_complete(9900,10000);
1229 bool opened_any = false;
1230 if(auto_recover->recovery_needed())
1232 splash_screen.hide();
1233 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1234 _("Synfig Studio seems to have crashed\n"
1235 "before you could save all your files.\n"
1236 "Would you like to re-open those files\n"
1237 "and recover your unsaved changes?")) ==
1238 synfigapp::UIInterface::RESPONSE_YES)
1240 int number_recovered;
1241 if(!auto_recover->recover(number_recovered))
1242 if (number_recovered)
1243 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1245 get_ui_interface()->error(_("Unable to recover from previous crash"));
1247 get_ui_interface()->error(
1248 _("Synfig Studio has attempted to recover\n"
1249 "from a previous crash. The files that it has\n"
1250 "recovered are NOT YET SAVED. It would be a good\n"
1251 "idea to review them and save them now."));
1253 if (number_recovered)
1256 splash_screen.show();
1259 // Look for any files given on the command line,
1260 // and load them if found.
1261 for(;*argc>=1;(*argc)--)
1262 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1264 studio_init_cb.task(_("Loading files..."));
1265 splash_screen.hide();
1266 open((*argv)[*argc]);
1268 splash_screen.show();
1271 // if no file was specified to be opened, create a new document to help new users get started more easily
1272 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1275 studio_init_cb.task(_("Done."));
1276 studio_init_cb.amount_complete(10000,10000);
1282 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1286 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1290 StateManager* App::get_state_manager() { return state_manager; }
1294 shutdown_in_progress=true;
1298 synfigapp::Main::settings().remove_domain("pref");
1300 selected_instance=0;
1302 // Unload all of the modules
1303 for(;!module_list_.empty();module_list_.pop_back())
1306 delete state_manager;
1310 delete auto_recover;
1316 // studio::App::iteration(false);
1320 // studio::App::iteration(false);
1322 // studio::App::iteration(false);
1324 delete dialog_setup;
1326 delete dialog_gradient;
1328 delete dialog_color;
1330 delete dialog_input;
1332 delete dock_manager;
1334 instance_list.clear();
1336 // studio::App::iteration(false);
1340 App::get_user_app_directory()
1342 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1344 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1346 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1351 App::get_config_file(const synfig::String& file)
1353 return Glib::build_filename(get_user_app_directory(),file);
1356 #define SCALE_FACTOR (1280)
1357 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1359 App::set_recent_file_window_size(etl::handle<Instance> instance)
1361 int screen_w(Gdk::screen_width());
1362 int screen_h(Gdk::screen_height());
1364 const std::string &canvas_window_size = *recent_files_window_size.begin();
1366 if(canvas_window_size.empty())
1369 synfig::String::size_type current=0;
1370 bool seen_root(false), shown_non_root(false);
1372 while(current != synfig::String::npos)
1374 // find end of first field (canvas) or return
1375 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1376 if(separator == synfig::String::npos) break;
1379 synfig::Canvas::Handle canvas;
1381 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current));
1383 catch(Exception::IDNotFound) {
1384 // can't find the canvas; skip to the next canvas or return
1385 separator = canvas_window_size.find_first_of('\t', current);
1386 if(separator == synfig::String::npos) return;
1387 current = separator+1;
1391 if (canvas->is_root())
1394 shown_non_root = true;
1396 // check that we have the tab character the ends this canvas' data or return
1397 current = separator+1;
1398 separator = canvas_window_size.find_first_of('\t', current);
1399 if(separator == synfig::String::npos) return;
1402 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1404 current = separator+1;
1408 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1409 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1410 x=x*screen_w/SCALE_FACTOR;
1411 y=y*screen_h/SCALE_FACTOR;
1412 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1413 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1414 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1415 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1417 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1418 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1420 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1421 canvasview->move(x,y);
1422 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1423 canvasview->present();
1425 current = separator+1;
1428 if (shown_non_root && !seen_root)
1429 instance->find_canvas_view(instance->get_canvas())->hide();
1433 App::add_recent_file(const etl::handle<Instance> instance)
1435 int screen_w(Gdk::screen_width());
1436 int screen_h(Gdk::screen_height());
1438 std::string canvas_window_size;
1440 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1441 Instance::CanvasViewList::const_iterator iter;
1443 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1445 if( !((*iter)->is_visible()) )
1448 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1449 int x_pos, y_pos, x_size, y_size;
1450 (*iter)->get_position(x_pos,y_pos);
1451 (*iter)->get_size(x_size,y_size);
1453 canvas_window_size += strprintf("%s %d %d %d %d\t",
1454 canvas->get_relative_id(canvas->get_root()).c_str(),
1455 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1456 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1459 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1464 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1466 std::string filename(file_name);
1468 assert(!filename.empty());
1470 if(filename.empty())
1473 // Toss out any "hidden" files
1474 if(basename(filename)[0]=='.')
1477 // If we aren't an absolute path, turn ourselves into one
1478 if(!is_absolute_path(filename))
1479 filename=absolute_path(filename);
1481 std::string old_window_size;
1483 list<string>::iterator iter;
1484 list<string>::iterator iter_wsize;
1485 // Check to see if the file is already on the list.
1486 // If it is, then remove it from the list
1487 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1490 recent_files.erase(iter);
1491 old_window_size = *iter_wsize;
1492 recent_files_window_size.erase(iter_wsize);
1497 // Push the filename to the front of the list
1498 recent_files.push_front(filename);
1499 if(window_size.empty())
1500 recent_files_window_size.push_front(old_window_size);
1502 recent_files_window_size.push_front(window_size);
1504 // Clean out the files at the end of the list.
1505 while(recent_files.size()>(unsigned)get_max_recent_files())
1507 recent_files.pop_back();
1508 recent_files_window_size.pop_back();
1511 signal_recent_files_changed_();
1516 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1519 App::get_time_format()
1521 return _App_time_format;
1525 App::set_time_format(synfig::Time::Format x)
1532 App::save_settings()
1537 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1538 setlocale(LC_NUMERIC, "C");
1540 std::string filename=get_config_file("accelrc");
1541 Gtk::AccelMap::save(filename);
1544 std::string filename=get_config_file("recentfiles");
1546 std::ofstream file(filename.c_str());
1550 synfig::warning("Unable to save %s",filename.c_str());
1554 list<string>::reverse_iterator iter;
1556 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1560 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1562 std::ofstream file(filename.c_str());
1566 synfig::warning("Unable to save %s",filename.c_str());
1570 list<string>::reverse_iterator iter;
1572 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1576 std::string filename=get_config_file("settings");
1577 synfigapp::Main::settings().save_to_file(filename);
1578 setlocale(LC_NUMERIC,old_locale);
1582 synfig::warning("Caught exception when attempting to save settings.");
1587 App::load_settings()
1592 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1593 setlocale(LC_NUMERIC, "C");
1595 std::string filename=get_config_file("accelrc");
1596 Gtk::AccelMap::load(filename);
1599 bool window_size_broken = false;
1601 std::string filename=get_config_file("recentfiles");
1602 std::string filename_window_size=filename+std::string("_window_size");
1604 std::ifstream file(filename.c_str());
1605 std::ifstream file_window_size(filename_window_size.c_str());
1607 if(!file_window_size)
1608 window_size_broken = true;
1612 std::string recent_file;
1613 std::string recent_file_window_size;
1614 getline(file,recent_file);
1615 if(!window_size_broken)
1616 getline(file_window_size,recent_file_window_size);
1617 if(!recent_file.empty())
1619 if(!window_size_broken && !file_window_size)
1620 window_size_broken = true;
1621 if(!window_size_broken)
1622 add_recent_file(recent_file,recent_file_window_size);
1624 add_recent_file(recent_file);
1627 if(!window_size_broken && file_window_size)
1628 window_size_broken = true;
1630 if(window_size_broken)
1632 recent_files_window_size.clear();
1633 recent_files_window_size.resize(recent_files.size());
1636 std::string filename=get_config_file("settings");
1637 if(!synfigapp::Main::settings().load_from_file(filename))
1639 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1640 //if(!synfigapp::Main::settings().load_from_file(filename))
1642 gamma.set_gamma(1.0/2.2);
1643 reset_initial_window_configuration();
1646 setlocale(LC_NUMERIC,old_locale);
1650 synfig::warning("Caught exception when attempting to load settings.");
1655 App::reset_initial_window_configuration()
1657 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1658 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1659 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1660 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1661 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1662 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1663 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1664 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1665 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1666 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1667 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1668 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1669 #ifdef SINGLE_THREADED
1670 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1672 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1673 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1677 App::shutdown_request(GdkEventAny*)
1681 //return !shutdown_in_progress;
1687 if(shutdown_in_progress)return;
1690 get_ui_interface()->task(_("Quit Request"));
1693 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1697 std::list<etl::handle<Instance> >::iterator iter;
1698 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1700 if(!(*iter)->safe_close())
1704 if((*iter)->synfigapp::Instance::get_action_count())
1706 handle<synfigapp::UIInterface> uim;
1707 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1709 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1710 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1712 case synfigapp::UIInterface::RESPONSE_NO:
1714 case synfigapp::UIInterface::RESPONSE_YES:
1717 case synfigapp::UIInterface::RESPONSE_CANCEL:
1726 if((*iter)->synfigapp::Instance::is_modified())
1728 handle<synfigapp::UIInterface> uim;
1729 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1731 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() );
1732 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1734 case synfigapp::UIInterface::RESPONSE_NO:
1736 case synfigapp::UIInterface::RESPONSE_YES:
1737 (*iter)->dialog_cvs_commit();
1739 case synfigapp::UIInterface::RESPONSE_CANCEL:
1748 // This next line causes things to crash for some reason
1752 shutdown_in_progress=true;
1754 instance_list.clear();
1756 while(studio::App::events_pending())studio::App::iteration(false);
1759 auto_recover->normal_shutdown();
1761 get_ui_interface()->task(_("Quit Request sent"));
1767 dialog_setup->refresh();
1768 dialog_setup->show();
1771 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1772 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1775 //#define USE_WIN32_FILE_DIALOGS 1
1778 #ifdef USE_WIN32_FILE_DIALOGS
1779 static OPENFILENAME ofn={};
1783 #include <gdk/gdkwin32.h>
1787 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1789 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1791 #ifdef USE_WIN32_FILE_DIALOGS
1792 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1794 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1795 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1796 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1798 ofn.lStructSize=sizeof(OPENFILENAME);
1799 ofn.hwndOwner = hWnd;
1800 ofn.hInstance = hInstance;
1801 ofn.lpstrFilter = szFilter;
1802 // ofn.lpstrCustomFilter=NULL;
1803 // ofn.nMaxCustFilter=0;
1804 // ofn.nFilterIndex=0;
1805 // ofn.lpstrFile=NULL;
1806 ofn.nMaxFile=MAX_PATH;
1807 // ofn.lpstrFileTitle=NULL;
1808 // ofn.lpstrInitialDir=NULL;
1809 // ofn.lpstrTitle=NULL;
1810 ofn.Flags=OFN_HIDEREADONLY;
1811 // ofn.nFileOffset=0;
1812 // ofn.nFileExtension=0;
1813 ofn.lpstrDefExt=TEXT("sif");
1814 // ofn.lCustData = 0l;
1816 // ofn.lpTemplateName=NULL;
1818 CHAR szFilename[MAX_PATH];
1820 strcpy(szFilename,filename.c_str());
1821 strcpy(szTitle,title.c_str());
1823 ofn.lpstrFile=szFilename;
1824 ofn.lpstrFileTitle=szTitle;
1826 if(GetOpenFileName(&ofn))
1828 filename=szFilename;
1834 synfig::String prev_path;
1836 if(!_preferences.get_value(preference, prev_path))
1839 prev_path = absolute_path(prev_path);
1841 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1843 dialog->set_current_folder(prev_path);
1844 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1845 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1847 if (filename.empty())
1848 dialog->set_filename(prev_path);
1849 else if (is_absolute_path(filename))
1850 dialog->set_filename(filename);
1852 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1854 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1855 filename = dialog->get_filename();
1856 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1857 _preferences.set_value(preference, dirname(filename));
1871 GtkWidget *fileselection;
1872 fileselection = gtk_file_selection_new(title.c_str());
1875 if(basename(filename)==filename)
1877 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1880 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1882 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1884 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1885 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1887 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1888 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1890 gtk_widget_show(fileselection);
1898 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1899 _preferences.set_value(preference,dirname(filename));
1903 gtk_widget_destroy(fileselection);
1906 gtk_widget_destroy(fileselection);
1913 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1915 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1917 #if USE_WIN32_FILE_DIALOGS
1918 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1920 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1921 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1922 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1924 ofn.lStructSize=sizeof(OPENFILENAME);
1925 ofn.hwndOwner = hWnd;
1926 ofn.hInstance = hInstance;
1927 ofn.lpstrFilter = szFilter;
1928 // ofn.lpstrCustomFilter=NULL;
1929 // ofn.nMaxCustFilter=0;
1930 // ofn.nFilterIndex=0;
1931 // ofn.lpstrFile=NULL;
1932 ofn.nMaxFile=MAX_PATH;
1933 // ofn.lpstrFileTitle=NULL;
1934 // ofn.lpstrInitialDir=NULL;
1935 // ofn.lpstrTitle=NULL;
1936 ofn.Flags=OFN_OVERWRITEPROMPT;
1937 // ofn.nFileOffset=0;
1938 // ofn.nFileExtension=0;
1939 ofn.lpstrDefExt=TEXT("sif");
1940 // ofn.lCustData = 0l;
1942 // ofn.lpTemplateName=NULL;
1944 CHAR szFilename[MAX_PATH];
1946 strcpy(szFilename,filename.c_str());
1947 strcpy(szTitle,title.c_str());
1949 ofn.lpstrFile=szFilename;
1950 ofn.lpstrFileTitle=szTitle;
1952 if(GetSaveFileName(&ofn))
1954 filename=szFilename;
1955 _preferences.set_value(preference,dirname(filename));
1960 synfig::String prev_path;
1962 if(!_preferences.get_value(preference, prev_path))
1965 prev_path = absolute_path(prev_path);
1967 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1969 dialog->set_current_folder(prev_path);
1970 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1971 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1973 Widget_Enum *file_type_enum = 0;
1974 if (preference == ANIMATION_DIR_PREFERENCE)
1976 file_type_enum = manage(new Widget_Enum());
1977 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
1978 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
1979 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
1980 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
1981 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
1982 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
1984 Gtk::HBox *hbox = manage(new Gtk::HBox);
1985 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
1986 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
1989 dialog->set_extra_widget(*hbox);
1992 if (filename.empty())
1993 dialog->set_filename(prev_path);
1996 std::string full_path;
1997 if (is_absolute_path(filename))
1998 full_path = filename;
2000 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2002 // select the file if it exists
2003 dialog->set_filename(full_path);
2005 // if the file doesn't exist, put its name into the filename box
2007 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2008 dialog->set_current_name(basename(filename));
2011 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2012 if (preference == ANIMATION_DIR_PREFERENCE)
2013 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2014 filename = dialog->get_filename();
2015 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2016 _preferences.set_value(preference, dirname(filename));
2027 App::dialog_error_blocking(const std::string &title, const std::string &message)
2029 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2030 dialog.set_title(title);
2036 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2038 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2039 dialog.set_title(title);
2045 App::dialog_yes_no(const std::string &title, const std::string &message)
2050 true // use_separator
2052 Gtk::Label label(message);
2055 dialog.get_vbox()->pack_start(label);
2056 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2057 dialog.add_button(Gtk::StockID("gtk-no"),0);
2059 return dialog.run();
2063 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2068 true // use_separator
2070 Gtk::Label label(message);
2073 dialog.get_vbox()->pack_start(label);
2074 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2075 dialog.add_button(Gtk::StockID("gtk-no"),0);
2076 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2078 return dialog.run();
2082 App::dialog_not_implemented()
2084 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2085 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2090 try_open_url(const std::string &url)
2093 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2095 std::vector<std::string> command_line;
2096 std::vector<std::string> browsers;
2097 browsers.reserve(23);
2099 // Browser wrapper scripts
2100 #ifdef USE_OPEN_FOR_URLS
2101 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2103 browsers.push_back("xdg-open"); // XDG wrapper
2104 browsers.push_back("sensible-browser"); // Debian wrapper
2105 browsers.push_back("gnome-open"); // GNOME wrapper
2106 browsers.push_back("kfmclient"); // KDE wrapper
2107 browsers.push_back("exo-open"); // XFCE wrapper
2109 // Alternatives system
2110 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2111 browsers.push_back("x-www-browser"); // Debian GUI alternative
2113 // Individual browsers
2114 browsers.push_back("firefox");
2115 browsers.push_back("epiphany-browser");
2116 browsers.push_back("epiphany");
2117 browsers.push_back("konqueror");
2118 browsers.push_back("iceweasel");
2119 browsers.push_back("mozilla");
2120 browsers.push_back("netscape");
2121 browsers.push_back("icecat");
2122 browsers.push_back("galeon");
2123 browsers.push_back("midori");
2124 browsers.push_back("safari");
2125 browsers.push_back("opera");
2126 browsers.push_back("amaya");
2127 browsers.push_back("netsurf");
2128 browsers.push_back("dillo");
2130 // Try the user-specified browser first
2131 command_line.push_back(App::browser_command);
2132 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2133 command_line.push_back(url);
2135 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2136 catch( Glib::SpawnError& exception ){
2138 while ( !browsers.empty() )
2140 // Skip the browser if we already tried it
2141 if( browsers[0] == App::browser_command )
2144 // Construct the command line
2145 command_line.clear();
2146 command_line.push_back(browsers[0]);
2147 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2148 command_line.push_back(url);
2150 // Remove the browser from the list
2151 browsers.erase(browsers.begin());
2153 // Try to spawn the browser
2154 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2155 // Failed, move on to the next one
2156 catch(Glib::SpawnError& exception){ continue; }
2157 return true; // No exception means we succeeded!
2168 if (!try_open_url("http://synfig.org/Documentation"))
2170 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2171 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2172 dialog.set_title(_("Help"));
2178 App::open_url(const std::string &url)
2180 if(!try_open_url(url))
2182 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2183 dialog.set_secondary_text(url);
2184 dialog.set_title(_("No browser found"));
2190 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2195 true); // use_separator
2197 Gtk::Label label(message);
2199 dialog.get_vbox()->pack_start(label);
2202 entry.set_text(text);
2204 entry.set_activates_default(true);
2206 dialog.get_vbox()->pack_start(entry);
2208 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2209 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2210 dialog.set_default_response(Gtk::RESPONSE_OK);
2212 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2215 if(dialog.run()!=Gtk::RESPONSE_OK)
2218 text=entry.get_text();
2224 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2229 true); // use_separator
2231 Gtk::Label label(message);
2233 dialog.get_vbox()->pack_start(label);
2235 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2236 text_buffer->set_text(text);
2237 Gtk::TextView text_view(text_buffer);
2240 dialog.get_vbox()->pack_start(text_view);
2242 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2243 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2244 dialog.set_default_response(Gtk::RESPONSE_OK);
2246 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2249 if(dialog.run()!=Gtk::RESPONSE_OK)
2252 text=text_buffer->get_text();
2258 App::open(std::string filename)
2260 return open_as(filename,filename);
2263 // this is called from autorecover.cpp:
2264 // App::open_as(get_shadow_file_name(filename),filename)
2265 // other than that, 'filename' and 'as' are the same
2267 App::open_as(std::string filename,std::string as)
2270 char long_name[1024];
2271 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2272 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2273 // don't use it if that's the case
2274 if (long_name[0] != '\0')
2280 OneMoment one_moment;
2282 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
2283 if(canvas && get_instance(canvas))
2285 get_instance(canvas)->find_canvas_view(canvas)->present();
2286 info("%s is already open", filename.c_str());
2287 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2292 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2294 if (as.find(DEFAULT_FILENAME_PREFIX) != 0)
2295 add_recent_file(as);
2297 handle<Instance> instance(Instance::create(canvas));
2300 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2302 set_recent_file_window_size(instance);
2306 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)")))
2307 instance->dialog_cvs_update();
2312 dialog_error_blocking(_("Error"), x);
2317 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2328 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2330 String file_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2331 canvas->set_name(file_name);
2332 file_name += ".sifz";
2334 canvas->rend_desc().set_frame_rate(24.0);
2335 canvas->rend_desc().set_time_start(0.0);
2336 canvas->rend_desc().set_time_end(5.0);
2337 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2338 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2339 canvas->rend_desc().set_tl(Vector(-4,2.25));
2340 canvas->rend_desc().set_br(Vector(4,-2.25));
2341 canvas->rend_desc().set_w(480);
2342 canvas->rend_desc().set_h(270);
2343 canvas->rend_desc().set_antialias(1);
2344 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2345 canvas->set_file_name(file_name);
2347 handle<Instance> instance = Instance::create(canvas);
2349 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2350 instance->find_canvas_view(canvas)->canvas_properties.present();
2354 App::dialog_open(string filename)
2356 if (filename.empty())
2359 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2361 // If the filename still has wildcards, then we should
2362 // continue looking for the file we want
2363 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2369 get_ui_interface()->error(_("Unable to open file"));
2374 App::set_selected_instance(etl::loose_handle<Instance> instance)
2376 /* if(get_selected_instance()==instance)
2378 selected_instance=instance;
2379 signal_instance_selected()(instance);
2385 selected_instance=instance;
2386 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2390 instance->focus(instance->get_canvas());
2393 set_selected_canvas_view(0);
2395 signal_instance_selected()(instance);
2399 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2401 selected_canvas_view=canvas_view;
2402 signal_canvas_view_focus()(selected_canvas_view);
2405 selected_instance=canvas_view->get_instance();
2406 signal_instance_selected()(canvas_view->get_instance());
2409 if(get_selected_canvas_view()==canvas_view)
2411 signal_canvas_view_focus()(selected_canvas_view);
2412 signal_instance_selected()(canvas_view->get_instance());
2415 selected_canvas_view=canvas_view;
2416 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2417 set_selected_instance(canvas_view->get_instance());
2418 signal_canvas_view_focus()(selected_canvas_view);
2422 etl::loose_handle<Instance>
2423 App::get_instance(etl::handle<synfig::Canvas> canvas)
2425 if(!canvas) return 0;
2426 canvas=canvas->get_root();
2428 std::list<etl::handle<Instance> >::iterator iter;
2429 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2431 if((*iter)->get_canvas()==canvas)
2447 if(selected_instance)
2448 selected_instance->undo();
2454 if(selected_instance)
2455 selected_instance->redo();
2459 studio::App::get_base_path()
2461 return app_base_path_;