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-ducks", _("Unselect All Ducks"));
674 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
675 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
676 DEFINE_ACTION("properties", _("Properties"));
678 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
679 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
680 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
681 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
682 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
683 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
684 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
685 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
686 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
687 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
688 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
689 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
690 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
691 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
692 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
693 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
694 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
695 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
696 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
697 DEFINE_ACTION("play", _("Play"));
698 // DEFINE_ACTION("pause", _("Pause"));
699 DEFINE_ACTION("stop", _("Stop"));
700 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
701 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
702 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
703 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
704 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
705 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
706 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
707 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
708 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
709 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
710 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
711 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
712 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
713 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
714 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
715 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
716 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
717 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
718 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
719 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
720 DEFINE_ACTION("seek-end", _("Seek to End"));
722 DEFINE_ACTION("action-group_add", _("Add group"));
724 DEFINE_ACTION("canvas-new", _("New Canvas"));
726 DEFINE_ACTION("amount-inc", _("Increase Amount"));
727 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
732 // Set up synfigapp actions
734 synfigapp::Action::Book::iterator iter;
736 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
738 Gtk::StockID stock_id;
740 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
742 //Gtk::Image* image(manage(new Gtk::Image()));
743 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
744 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
745 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
746 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
747 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
748 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
749 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
750 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
751 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
752 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
754 actions_action_group->add(Gtk::Action::create(
755 "action-"+iter->second.name,
757 iter->second.local_name,iter->second.local_name
765 Glib::ustring ui_info =
767 " <popup name='menu-toolbox' action='menu-toolbox'>"
768 " <menu action='menu-file'>"
771 " <popup name='menu-main' action='menu-main'>"
772 " <menu action='menu-file'>"
773 " <menuitem action='new' />"
774 " <menuitem action='open' />"
775 " <menuitem action='save' />"
776 " <menuitem action='save-as' />"
777 " <menuitem action='revert' />"
778 " <separator name='bleh01'/>"
779 " <menuitem action='cvs-add' />"
780 " <menuitem action='cvs-update' />"
781 " <menuitem action='cvs-commit' />"
782 " <menuitem action='cvs-revert' />"
783 " <separator name='bleh02'/>"
784 " <menuitem action='import' />"
785 " <separator name='bleh03'/>"
786 " <menuitem action='render' />"
787 " <menuitem action='preview' />"
788 " <menuitem action='sound' />"
789 " <separator name='bleh04'/>"
790 " <menuitem action='options' />"
791 " <menuitem action='close' />"
792 " <menuitem action='close-document' />"
793 " <menuitem action='quit' />"
795 " <menu action='menu-edit'>"
796 " <menuitem action='undo'/>"
797 " <menuitem action='redo'/>"
798 " <separator name='bleh05'/>"
799 " <menuitem action='cut'/>"
800 " <menuitem action='copy'/>"
801 " <menuitem action='paste'/>"
802 " <separator name='bleh06'/>"
803 " <menuitem action='select-all-layers'/>"
804 " <menuitem action='unselect-all-layers'/>"
805 " <menuitem action='select-all-ducks'/>"
806 " <menuitem action='unselect-all-ducks'/>"
807 " <separator name='bleh07'/>"
808 " <menuitem action='properties'/>"
810 " <menu action='menu-view'>"
811 " <menu action='menu-duck-mask'>"
812 " <menuitem action='mask-position-ducks' />"
813 " <menuitem action='mask-vertex-ducks' />"
814 " <menuitem action='mask-tangent-ducks' />"
815 " <menuitem action='mask-radius-ducks' />"
816 " <menuitem action='mask-width-ducks' />"
817 " <menuitem action='mask-angle-ducks' />"
819 " <menu action='menu-preview-quality'>"
820 " <menuitem action='quality-00' />"
821 " <menuitem action='quality-01' />"
822 " <menuitem action='quality-02' />"
823 " <menuitem action='quality-03' />"
824 " <menuitem action='quality-04' />"
825 " <menuitem action='quality-05' />"
826 " <menuitem action='quality-06' />"
827 " <menuitem action='quality-07' />"
828 " <menuitem action='quality-08' />"
829 " <menuitem action='quality-09' />"
830 " <menuitem action='quality-10' />"
832 " <menu action='menu-lowres-pixel'>"
833 " <menuitem action='decrease-low-res-pixel-size'/>"
834 " <menuitem action='increase-low-res-pixel-size'/>"
835 " <separator name='pixel-size-separator'/>"
838 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
839 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
843 " <separator name='bleh08'/>"
844 " <menuitem action='play'/>"
845 //" <menuitem action='pause'/>"
846 " <menuitem action='stop'/>"
847 " <menuitem action='dialog-flipbook'/>"
848 " <separator name='bleh09'/>"
849 " <menuitem action='toggle-grid-show'/>"
850 " <menuitem action='toggle-grid-snap'/>"
851 " <menuitem action='toggle-guide-show'/>"
852 " <menuitem action='toggle-low-res'/>"
853 " <menuitem action='toggle-onion-skin'/>"
854 " <separator name='bleh10'/>"
855 " <menuitem action='canvas-zoom-in'/>"
856 " <menuitem action='canvas-zoom-out'/>"
857 " <menuitem action='canvas-zoom-fit'/>"
858 " <menuitem action='canvas-zoom-100'/>"
859 " <separator name='bleh11'/>"
860 " <menuitem action='time-zoom-in'/>"
861 " <menuitem action='time-zoom-out'/>"
862 " <separator name='bleh12'/>"
863 " <menuitem action='jump-next-keyframe'/>"
864 " <menuitem action='jump-prev-keyframe'/>"
865 " <menuitem action='seek-next-frame'/>"
866 " <menuitem action='seek-prev-frame'/>"
867 " <menuitem action='seek-next-second'/>"
868 " <menuitem action='seek-prev-second'/>"
869 " <menuitem action='seek-begin'/>"
870 " <menuitem action='seek-end'/>"
872 " <menu action='menu-canvas'>"
873 " <menuitem action='canvas-new'/>"
875 " <menu name='menu-state' action='menu-state'>"
877 " <menu action='menu-group'>"
878 " <menuitem action='action-group_add'/>"
880 " <menu action='menu-layer'>"
881 //" <menuitem action='cut'/>"
882 //" <menuitem action='copy'/>"
883 //" <menuitem action='paste'/>"
884 //" <separator name='bleh06'/>"
885 " <menu action='menu-layer-new'></menu>"
886 " <menuitem action='amount-inc'/>"
887 " <menuitem action='amount-dec'/>"
889 " <menu action='menu-keyframe'>"
890 " <menuitem action='keyframe-properties'/>"
897 " <menubar name='MenuBar'>"
898 " <menu action='MenuFile'>"
899 " <menuitem action='New'/>"
900 " <menuitem action='Open'/>"
902 " <menuitem action='Quit'/>"
904 " <menu action='MenuEdit'>"
905 " <menuitem action='Cut'/>"
906 " <menuitem action='Copy'/>"
907 " <menuitem action='Paste'/>"
910 " <toolbar name='ToolBar'>"
911 " <toolitem action='Open'/>"
912 " <toolitem action='Quit'/>"
918 actions_action_group->set_sensitive(false);
919 App::ui_manager()->set_add_tearoffs(true);
920 App::ui_manager()->insert_action_group(menus_action_group,1);
921 App::ui_manager()->insert_action_group(actions_action_group,1);
922 App::ui_manager()->add_ui_from_string(ui_info);
924 //App::ui_manager()->get_accel_group()->unlock();
926 catch(const Glib::Error& ex)
928 synfig::error("building menus and toolbars failed: " + ex.what());
931 // Add default keyboard accelerators
932 #define ACCEL(path,accel) \
934 Gtk::AccelKey accel_key(accel,path); \
935 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
938 #define ACCEL2(accel) \
940 Gtk::AccelKey accel_key(accel); \
941 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
944 ACCEL("<Actions>//select-all-ducks","<Control>a");
945 ACCEL("<Actions>//unselect-all-ducks","<Control>d");
946 ACCEL("<Actions>//select-all-layers","<Control><Shift>a");
947 ACCEL("<Actions>//unselect-all-layers","<Control><Shift>d");
948 ACCEL("<Actions>//render","F9");
949 ACCEL("<Actions>//preview","F11");
950 ACCEL("<Actions>//properties","F8");
951 ACCEL("<Actions>//options","F12");
952 ACCEL("<Actions>//import","<control>i");
953 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
954 ACCEL("<Actions>//toggle-grid-show","<Control>g");
955 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
956 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
957 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
958 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
959 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
960 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
961 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
962 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
964 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
965 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
967 ACCEL("<Actions>//quality-01","<Control>1");
968 ACCEL("<Actions>//quality-02","<Control>2");
969 ACCEL("<Actions>//quality-03","<Control>3");
970 ACCEL("<Actions>//quality-04","<Control>4");
971 ACCEL("<Actions>//quality-05","<Control>5");
972 ACCEL("<Actions>//quality-06","<Control>6");
973 ACCEL("<Actions>//quality-07","<Control>7");
974 ACCEL("<Actions>//quality-08","<Control>8");
975 ACCEL("<Actions>//quality-09","<Control>9");
976 ACCEL("<Actions>//quality-10","<Control>0");
977 ACCEL("<Actions>//undo","<Control>z");
978 ACCEL("<Actions>//redo","<Control>r");
979 ACCEL("<Actions>//action-layer_remove","Delete");
981 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
982 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
983 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
984 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
985 ACCEL("<Actions>//time-zoom-in","+");
986 ACCEL("<Actions>//time-zoom-out","_");
988 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
989 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
991 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
992 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
994 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
995 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
996 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
997 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
998 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
999 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
1000 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
1001 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
1002 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
1003 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
1004 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
1005 ACCEL("<Actions>//play", "<Control>p");
1006 ACCEL("<Actions>//seek-begin","Home");
1007 ACCEL("<Actions>//seek-end","End");
1009 ACCEL("<Actions>//state-normal", "<Mod1>a");
1010 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1011 ACCEL("<Actions>//state-scale", "<Mod1>s");
1012 ACCEL("<Actions>//state-rotate", "<Mod1>t");
1013 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1015 ACCEL("<Actions>//state-circle", "<Mod1>c");
1016 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1017 ACCEL("<Actions>//state-star", "<Mod1>q");
1018 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1019 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1021 ACCEL("<Actions>//state-bline", "<Mod1>b");
1022 ACCEL("<Actions>//state-text", "<Mod1>x");
1023 ACCEL("<Actions>//state-fill", "<Mod1>f");
1024 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1025 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1027 ACCEL("<Actions>//state-draw", "<Mod1>d");
1028 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1029 ACCEL("<Actions>//state-width", "<Mod1>w");
1031 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1037 #define mkdir(x,y) mkdir(x)
1040 /* === M E T H O D S ======================================================= */
1042 App::App(int *argc, char ***argv):
1043 Gtk::Main(argc,argv),
1044 IconController(etl::dirname((*argv)[0]))
1046 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1049 ui_interface_=new GlobalUIInterface();
1053 // don't call thread_init() if threads are already initialized
1054 // on some machines bonobo_init() initialized threads before we get here
1055 if (!g_thread_supported())
1056 Glib::thread_init();
1058 distance_system=Distance::SYSTEM_UNITS;
1060 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1063 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1067 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1073 if(!SYNFIG_CHECK_VERSION())
1075 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1076 dialog_error_blocking("Synfig Studio",
1077 "This copy of Synfig Studio was compiled against a\n"
1078 "different version of libsynfig than what is currently\n"
1079 "installed. Synfig Studio will now abort. Try downloading\n"
1080 "the latest version from the Synfig website at\n"
1081 "http://synfig.org/Download"
1085 Glib::set_application_name(_("Synfig Studio"));
1087 Splash splash_screen;
1088 splash_screen.show();
1090 shutdown_in_progress=false;
1091 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1092 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1094 // Initialize the Synfig library
1095 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1098 get_ui_interface()->error(_("Failed to initialize synfig!"));
1102 // add the preferences to the settings
1103 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1107 studio_init_cb.task(_("Init UI Manager..."));
1108 App::ui_manager_=studio::UIManager::create();
1111 studio_init_cb.task(_("Init Dock Manager..."));
1112 dock_manager=new studio::DockManager();
1114 studio_init_cb.task(_("Init State Manager..."));
1115 state_manager=new StateManager();
1117 studio_init_cb.task(_("Init Toolbox..."));
1118 toolbox=new studio::Toolbox();
1120 studio_init_cb.task(_("Init About Dialog..."));
1121 about=new studio::About();
1123 studio_init_cb.task(_("Init Tool Options..."));
1124 dialog_tool_options=new studio::Dialog_ToolOptions();
1125 dock_manager->register_dockable(*dialog_tool_options);
1127 studio_init_cb.task(_("Init History..."));
1128 dock_history=new studio::Dock_History();
1129 dock_manager->register_dockable(*dock_history);
1131 studio_init_cb.task(_("Init Canvases..."));
1132 dock_canvases=new studio::Dock_Canvases();
1133 dock_manager->register_dockable(*dock_canvases);
1135 studio_init_cb.task(_("Init Keyframes..."));
1136 dock_keyframes=new studio::Dock_Keyframes();
1137 dock_manager->register_dockable(*dock_keyframes);
1139 studio_init_cb.task(_("Init Layers..."));
1140 dock_layers=new studio::Dock_Layers();
1141 dock_manager->register_dockable(*dock_layers);
1143 studio_init_cb.task(_("Init Params..."));
1144 dock_params=new studio::Dock_Params();
1145 dock_manager->register_dockable(*dock_params);
1147 studio_init_cb.task(_("Init MetaData..."));
1148 dock_meta_data=new studio::Dock_MetaData();
1149 dock_manager->register_dockable(*dock_meta_data);
1151 studio_init_cb.task(_("Init Children..."));
1152 dock_children=new studio::Dock_Children();
1153 dock_manager->register_dockable(*dock_children);
1155 studio_init_cb.task(_("Init Info..."));
1156 dock_info = new studio::Dock_Info();
1157 dock_manager->register_dockable(*dock_info);
1159 studio_init_cb.task(_("Init Navigator..."));
1160 dock_navigator = new studio::Dock_Navigator();
1161 dock_manager->register_dockable(*dock_navigator);
1163 studio_init_cb.task(_("Init Timetrack..."));
1164 dock_timetrack = new studio::Dock_Timetrack();
1165 dock_manager->register_dockable(*dock_timetrack);
1167 studio_init_cb.task(_("Init Curve Editor..."));
1168 dock_curves = new studio::Dock_Curves();
1169 dock_manager->register_dockable(*dock_curves);
1171 studio_init_cb.task(_("Init Layer Groups..."));
1172 dock_layer_groups = new studio::Dock_LayerGroups();
1173 dock_manager->register_dockable(*dock_layer_groups);
1176 studio_init_cb.task(_("Init Color Dialog..."));
1177 dialog_color=new studio::Dialog_Color();
1179 studio_init_cb.task(_("Init Gradient Dialog..."));
1180 dialog_gradient=new studio::Dialog_Gradient();
1182 studio_init_cb.task(_("Init DeviceTracker..."));
1183 device_tracker=new studio::DeviceTracker();
1185 studio_init_cb.task(_("Init Tools..."));
1188 state_manager->add_state(&state_normal);
1189 state_manager->add_state(&state_smooth_move);
1190 state_manager->add_state(&state_scale);
1191 state_manager->add_state(&state_rotate);
1192 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1195 state_manager->add_state(&state_circle);
1196 state_manager->add_state(&state_rectangle);
1197 state_manager->add_state(&state_star);
1198 state_manager->add_state(&state_gradient);
1199 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1202 state_manager->add_state(&state_bline);
1203 state_manager->add_state(&state_text);
1204 state_manager->add_state(&state_fill);
1205 state_manager->add_state(&state_eyedrop);
1206 state_manager->add_state(&state_zoom);
1208 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1209 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1211 // Disabled by default - it doesn't work properly?
1212 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1214 studio_init_cb.task(_("Init ModPalette..."));
1215 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1217 studio_init_cb.task(_("Init Setup Dialog..."));
1218 dialog_setup=new studio::Dialog_Setup();
1220 studio_init_cb.task(_("Init Input Dialog..."));
1221 dialog_input=new Gtk::InputDialog();
1222 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1223 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1225 studio_init_cb.task(_("Init auto recovery..."));
1226 auto_recover=new AutoRecover();
1228 studio_init_cb.amount_complete(9250,10000);
1229 studio_init_cb.task(_("Loading Settings..."));
1231 studio_init_cb.task(_("Checking auto-recover..."));
1233 studio_init_cb.amount_complete(9900,10000);
1235 bool opened_any = false;
1236 if(auto_recover->recovery_needed())
1238 splash_screen.hide();
1239 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1240 _("Synfig Studio seems to have crashed\n"
1241 "before you could save all your files.\n"
1242 "Would you like to re-open those files\n"
1243 "and recover your unsaved changes?")) ==
1244 synfigapp::UIInterface::RESPONSE_YES)
1246 int number_recovered;
1247 if(!auto_recover->recover(number_recovered))
1248 if (number_recovered)
1249 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1251 get_ui_interface()->error(_("Unable to recover from previous crash"));
1253 get_ui_interface()->error(
1254 _("Synfig Studio has attempted to recover\n"
1255 "from a previous crash. The files that it has\n"
1256 "recovered are NOT YET SAVED. It would be a good\n"
1257 "idea to review them and save them now."));
1259 if (number_recovered)
1262 splash_screen.show();
1265 // Look for any files given on the command line,
1266 // and load them if found.
1267 for(;*argc>=1;(*argc)--)
1268 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1270 studio_init_cb.task(_("Loading files..."));
1271 splash_screen.hide();
1272 open((*argv)[*argc]);
1274 splash_screen.show();
1277 // if no file was specified to be opened, create a new document to help new users get started more easily
1278 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1281 studio_init_cb.task(_("Done."));
1282 studio_init_cb.amount_complete(10000,10000);
1288 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1292 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1296 StateManager* App::get_state_manager() { return state_manager; }
1300 shutdown_in_progress=true;
1304 synfigapp::Main::settings().remove_domain("pref");
1306 selected_instance=0;
1308 // Unload all of the modules
1309 for(;!module_list_.empty();module_list_.pop_back())
1312 delete state_manager;
1316 delete auto_recover;
1322 // studio::App::iteration(false);
1326 // studio::App::iteration(false);
1328 // studio::App::iteration(false);
1330 delete dialog_setup;
1332 delete dialog_gradient;
1334 delete dialog_color;
1336 delete dialog_input;
1338 delete dock_manager;
1340 instance_list.clear();
1342 // studio::App::iteration(false);
1346 App::get_user_app_directory()
1348 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1350 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1352 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1357 App::get_config_file(const synfig::String& file)
1359 return Glib::build_filename(get_user_app_directory(),file);
1362 #define SCALE_FACTOR (1280)
1363 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1365 App::set_recent_file_window_size(etl::handle<Instance> instance)
1367 int screen_w(Gdk::screen_width());
1368 int screen_h(Gdk::screen_height());
1370 const std::string &canvas_window_size = *recent_files_window_size.begin();
1372 if(canvas_window_size.empty())
1375 synfig::String::size_type current=0;
1376 bool seen_root(false), shown_non_root(false);
1378 while(current != synfig::String::npos)
1380 // find end of first field (canvas) or return
1381 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1382 if(separator == synfig::String::npos) break;
1385 synfig::Canvas::Handle canvas;
1387 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current));
1389 catch(Exception::IDNotFound) {
1390 // can't find the canvas; skip to the next canvas or return
1391 separator = canvas_window_size.find_first_of('\t', current);
1392 if(separator == synfig::String::npos) return;
1393 current = separator+1;
1397 if (canvas->is_root())
1400 shown_non_root = true;
1402 // check that we have the tab character the ends this canvas' data or return
1403 current = separator+1;
1404 separator = canvas_window_size.find_first_of('\t', current);
1405 if(separator == synfig::String::npos) return;
1408 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1410 current = separator+1;
1414 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1415 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1416 x=x*screen_w/SCALE_FACTOR;
1417 y=y*screen_h/SCALE_FACTOR;
1418 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1419 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1420 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1421 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1423 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1424 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1426 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1427 canvasview->move(x,y);
1428 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1429 canvasview->present();
1431 current = separator+1;
1434 if (shown_non_root && !seen_root)
1435 instance->find_canvas_view(instance->get_canvas())->hide();
1439 App::add_recent_file(const etl::handle<Instance> instance)
1441 int screen_w(Gdk::screen_width());
1442 int screen_h(Gdk::screen_height());
1444 std::string canvas_window_size;
1446 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1447 Instance::CanvasViewList::const_iterator iter;
1449 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1451 if( !((*iter)->is_visible()) )
1454 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1455 int x_pos, y_pos, x_size, y_size;
1456 (*iter)->get_position(x_pos,y_pos);
1457 (*iter)->get_size(x_size,y_size);
1459 canvas_window_size += strprintf("%s %d %d %d %d\t",
1460 canvas->get_relative_id(canvas->get_root()).c_str(),
1461 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1462 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1465 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1470 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1472 std::string filename(file_name);
1474 assert(!filename.empty());
1476 if(filename.empty())
1479 // Toss out any "hidden" files
1480 if(basename(filename)[0]=='.')
1483 // If we aren't an absolute path, turn ourselves into one
1484 if(!is_absolute_path(filename))
1485 filename=absolute_path(filename);
1487 std::string old_window_size;
1489 list<string>::iterator iter;
1490 list<string>::iterator iter_wsize;
1491 // Check to see if the file is already on the list.
1492 // If it is, then remove it from the list
1493 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1496 recent_files.erase(iter);
1497 old_window_size = *iter_wsize;
1498 recent_files_window_size.erase(iter_wsize);
1503 // Push the filename to the front of the list
1504 recent_files.push_front(filename);
1505 if(window_size.empty())
1506 recent_files_window_size.push_front(old_window_size);
1508 recent_files_window_size.push_front(window_size);
1510 // Clean out the files at the end of the list.
1511 while(recent_files.size()>(unsigned)get_max_recent_files())
1513 recent_files.pop_back();
1514 recent_files_window_size.pop_back();
1517 signal_recent_files_changed_();
1522 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1525 App::get_time_format()
1527 return _App_time_format;
1531 App::set_time_format(synfig::Time::Format x)
1538 App::save_settings()
1543 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1544 setlocale(LC_NUMERIC, "C");
1546 std::string filename=get_config_file("accelrc");
1547 Gtk::AccelMap::save(filename);
1550 std::string filename=get_config_file("recentfiles");
1552 std::ofstream file(filename.c_str());
1556 synfig::warning("Unable to save %s",filename.c_str());
1560 list<string>::reverse_iterator iter;
1562 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1566 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1568 std::ofstream file(filename.c_str());
1572 synfig::warning("Unable to save %s",filename.c_str());
1576 list<string>::reverse_iterator iter;
1578 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1582 std::string filename=get_config_file("settings");
1583 synfigapp::Main::settings().save_to_file(filename);
1584 setlocale(LC_NUMERIC,old_locale);
1588 synfig::warning("Caught exception when attempting to save settings.");
1593 App::load_settings()
1598 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1599 setlocale(LC_NUMERIC, "C");
1601 std::string filename=get_config_file("accelrc");
1602 Gtk::AccelMap::load(filename);
1605 bool window_size_broken = false;
1607 std::string filename=get_config_file("recentfiles");
1608 std::string filename_window_size=filename+std::string("_window_size");
1610 std::ifstream file(filename.c_str());
1611 std::ifstream file_window_size(filename_window_size.c_str());
1613 if(!file_window_size)
1614 window_size_broken = true;
1618 std::string recent_file;
1619 std::string recent_file_window_size;
1620 getline(file,recent_file);
1621 if(!window_size_broken)
1622 getline(file_window_size,recent_file_window_size);
1623 if(!recent_file.empty())
1625 if(!window_size_broken && !file_window_size)
1626 window_size_broken = true;
1627 if (std::ifstream(recent_file.c_str()))
1629 if(!window_size_broken)
1630 add_recent_file(recent_file,recent_file_window_size);
1632 add_recent_file(recent_file);
1636 if(!window_size_broken && file_window_size)
1637 window_size_broken = true;
1639 if(window_size_broken)
1641 recent_files_window_size.clear();
1642 recent_files_window_size.resize(recent_files.size());
1645 std::string filename=get_config_file("settings");
1646 if(!synfigapp::Main::settings().load_from_file(filename))
1648 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1649 //if(!synfigapp::Main::settings().load_from_file(filename))
1651 gamma.set_gamma(1.0/2.2);
1652 reset_initial_window_configuration();
1655 setlocale(LC_NUMERIC,old_locale);
1659 synfig::warning("Caught exception when attempting to load settings.");
1664 App::reset_initial_window_configuration()
1666 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1667 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1668 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1669 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1670 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1671 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1672 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1673 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1674 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1675 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1676 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1677 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1678 #ifdef SINGLE_THREADED
1679 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1681 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1682 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1686 App::shutdown_request(GdkEventAny*)
1690 //return !shutdown_in_progress;
1696 if(shutdown_in_progress)return;
1699 get_ui_interface()->task(_("Quit Request"));
1702 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1706 std::list<etl::handle<Instance> >::iterator iter;
1707 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1709 if(!(*iter)->safe_close())
1713 if((*iter)->synfigapp::Instance::get_action_count())
1715 handle<synfigapp::UIInterface> uim;
1716 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1718 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1719 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1721 case synfigapp::UIInterface::RESPONSE_NO:
1723 case synfigapp::UIInterface::RESPONSE_YES:
1726 case synfigapp::UIInterface::RESPONSE_CANCEL:
1735 if((*iter)->synfigapp::Instance::is_modified())
1737 handle<synfigapp::UIInterface> uim;
1738 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1740 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() );
1741 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1743 case synfigapp::UIInterface::RESPONSE_NO:
1745 case synfigapp::UIInterface::RESPONSE_YES:
1746 (*iter)->dialog_cvs_commit();
1748 case synfigapp::UIInterface::RESPONSE_CANCEL:
1757 // This next line causes things to crash for some reason
1761 shutdown_in_progress=true;
1763 instance_list.clear();
1765 while(studio::App::events_pending())studio::App::iteration(false);
1768 auto_recover->normal_shutdown();
1770 get_ui_interface()->task(_("Quit Request sent"));
1776 dialog_setup->refresh();
1777 dialog_setup->show();
1780 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1781 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1784 //#define USE_WIN32_FILE_DIALOGS 1
1787 #ifdef USE_WIN32_FILE_DIALOGS
1788 static OPENFILENAME ofn={};
1792 #include <gdk/gdkwin32.h>
1796 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1798 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1800 #ifdef USE_WIN32_FILE_DIALOGS
1801 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1803 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1804 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1805 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1807 ofn.lStructSize=sizeof(OPENFILENAME);
1808 ofn.hwndOwner = hWnd;
1809 ofn.hInstance = hInstance;
1810 ofn.lpstrFilter = szFilter;
1811 // ofn.lpstrCustomFilter=NULL;
1812 // ofn.nMaxCustFilter=0;
1813 // ofn.nFilterIndex=0;
1814 // ofn.lpstrFile=NULL;
1815 ofn.nMaxFile=MAX_PATH;
1816 // ofn.lpstrFileTitle=NULL;
1817 // ofn.lpstrInitialDir=NULL;
1818 // ofn.lpstrTitle=NULL;
1819 ofn.Flags=OFN_HIDEREADONLY;
1820 // ofn.nFileOffset=0;
1821 // ofn.nFileExtension=0;
1822 ofn.lpstrDefExt=TEXT("sif");
1823 // ofn.lCustData = 0l;
1825 // ofn.lpTemplateName=NULL;
1827 CHAR szFilename[MAX_PATH];
1829 strcpy(szFilename,filename.c_str());
1830 strcpy(szTitle,title.c_str());
1832 ofn.lpstrFile=szFilename;
1833 ofn.lpstrFileTitle=szTitle;
1835 if(GetOpenFileName(&ofn))
1837 filename=szFilename;
1843 synfig::String prev_path;
1845 if(!_preferences.get_value(preference, prev_path))
1848 prev_path = absolute_path(prev_path);
1850 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1852 dialog->set_current_folder(prev_path);
1853 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1854 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1856 if (filename.empty())
1857 dialog->set_filename(prev_path);
1858 else if (is_absolute_path(filename))
1859 dialog->set_filename(filename);
1861 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1863 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1864 filename = dialog->get_filename();
1865 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1866 _preferences.set_value(preference, dirname(filename));
1880 GtkWidget *fileselection;
1881 fileselection = gtk_file_selection_new(title.c_str());
1884 if(basename(filename)==filename)
1886 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1889 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1891 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1893 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1894 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1896 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1897 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1899 gtk_widget_show(fileselection);
1907 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1908 _preferences.set_value(preference,dirname(filename));
1912 gtk_widget_destroy(fileselection);
1915 gtk_widget_destroy(fileselection);
1922 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1924 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1926 #if USE_WIN32_FILE_DIALOGS
1927 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1929 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1930 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1931 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1933 ofn.lStructSize=sizeof(OPENFILENAME);
1934 ofn.hwndOwner = hWnd;
1935 ofn.hInstance = hInstance;
1936 ofn.lpstrFilter = szFilter;
1937 // ofn.lpstrCustomFilter=NULL;
1938 // ofn.nMaxCustFilter=0;
1939 // ofn.nFilterIndex=0;
1940 // ofn.lpstrFile=NULL;
1941 ofn.nMaxFile=MAX_PATH;
1942 // ofn.lpstrFileTitle=NULL;
1943 // ofn.lpstrInitialDir=NULL;
1944 // ofn.lpstrTitle=NULL;
1945 ofn.Flags=OFN_OVERWRITEPROMPT;
1946 // ofn.nFileOffset=0;
1947 // ofn.nFileExtension=0;
1948 ofn.lpstrDefExt=TEXT("sif");
1949 // ofn.lCustData = 0l;
1951 // ofn.lpTemplateName=NULL;
1953 CHAR szFilename[MAX_PATH];
1955 strcpy(szFilename,filename.c_str());
1956 strcpy(szTitle,title.c_str());
1958 ofn.lpstrFile=szFilename;
1959 ofn.lpstrFileTitle=szTitle;
1961 if(GetSaveFileName(&ofn))
1963 filename=szFilename;
1964 _preferences.set_value(preference,dirname(filename));
1969 synfig::String prev_path;
1971 if(!_preferences.get_value(preference, prev_path))
1974 prev_path = absolute_path(prev_path);
1976 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1978 dialog->set_current_folder(prev_path);
1979 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1980 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1982 Widget_Enum *file_type_enum = 0;
1983 if (preference == ANIMATION_DIR_PREFERENCE)
1985 file_type_enum = manage(new Widget_Enum());
1986 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
1987 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
1988 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
1989 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
1990 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
1991 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
1993 Gtk::HBox *hbox = manage(new Gtk::HBox);
1994 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
1995 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
1998 dialog->set_extra_widget(*hbox);
2001 if (filename.empty())
2002 dialog->set_filename(prev_path);
2005 std::string full_path;
2006 if (is_absolute_path(filename))
2007 full_path = filename;
2009 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2011 // select the file if it exists
2012 dialog->set_filename(full_path);
2014 // if the file doesn't exist, put its name into the filename box
2016 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2017 dialog->set_current_name(basename(filename));
2020 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2021 if (preference == ANIMATION_DIR_PREFERENCE)
2022 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2023 filename = dialog->get_filename();
2024 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2025 _preferences.set_value(preference, dirname(filename));
2036 App::dialog_error_blocking(const std::string &title, const std::string &message)
2038 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2039 dialog.set_title(title);
2045 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2047 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2048 dialog.set_title(title);
2054 App::dialog_yes_no(const std::string &title, const std::string &message)
2059 true // use_separator
2061 Gtk::Label label(message);
2064 dialog.get_vbox()->pack_start(label);
2065 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2066 dialog.add_button(Gtk::StockID("gtk-no"),0);
2068 return dialog.run();
2072 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2077 true // use_separator
2079 Gtk::Label label(message);
2082 dialog.get_vbox()->pack_start(label);
2083 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2084 dialog.add_button(Gtk::StockID("gtk-no"),0);
2085 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2087 return dialog.run();
2091 App::dialog_not_implemented()
2093 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2094 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2099 try_open_url(const std::string &url)
2102 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2104 std::vector<std::string> command_line;
2105 std::vector<std::string> browsers;
2106 browsers.reserve(23);
2108 // Browser wrapper scripts
2109 #ifdef USE_OPEN_FOR_URLS
2110 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2112 browsers.push_back("xdg-open"); // XDG wrapper
2113 browsers.push_back("sensible-browser"); // Debian wrapper
2114 browsers.push_back("gnome-open"); // GNOME wrapper
2115 browsers.push_back("kfmclient"); // KDE wrapper
2116 browsers.push_back("exo-open"); // XFCE wrapper
2118 // Alternatives system
2119 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2120 browsers.push_back("x-www-browser"); // Debian GUI alternative
2122 // Individual browsers
2123 browsers.push_back("firefox");
2124 browsers.push_back("epiphany-browser");
2125 browsers.push_back("epiphany");
2126 browsers.push_back("konqueror");
2127 browsers.push_back("iceweasel");
2128 browsers.push_back("mozilla");
2129 browsers.push_back("netscape");
2130 browsers.push_back("icecat");
2131 browsers.push_back("galeon");
2132 browsers.push_back("midori");
2133 browsers.push_back("safari");
2134 browsers.push_back("opera");
2135 browsers.push_back("amaya");
2136 browsers.push_back("netsurf");
2137 browsers.push_back("dillo");
2139 // Try the user-specified browser first
2140 command_line.push_back(App::browser_command);
2141 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2142 command_line.push_back(url);
2144 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2145 catch( Glib::SpawnError& exception ){
2147 while ( !browsers.empty() )
2149 // Skip the browser if we already tried it
2150 if( browsers[0] == App::browser_command )
2153 // Construct the command line
2154 command_line.clear();
2155 command_line.push_back(browsers[0]);
2156 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2157 command_line.push_back(url);
2159 // Remove the browser from the list
2160 browsers.erase(browsers.begin());
2162 // Try to spawn the browser
2163 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2164 // Failed, move on to the next one
2165 catch(Glib::SpawnError& exception){ continue; }
2166 return true; // No exception means we succeeded!
2177 if (!try_open_url("http://synfig.org/Documentation"))
2179 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2180 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2181 dialog.set_title(_("Help"));
2187 App::open_url(const std::string &url)
2189 if(!try_open_url(url))
2191 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2192 dialog.set_secondary_text(url);
2193 dialog.set_title(_("No browser found"));
2199 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2204 true); // use_separator
2206 Gtk::Label label(message);
2208 dialog.get_vbox()->pack_start(label);
2211 entry.set_text(text);
2213 entry.set_activates_default(true);
2215 dialog.get_vbox()->pack_start(entry);
2217 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2218 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2219 dialog.set_default_response(Gtk::RESPONSE_OK);
2221 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2224 if(dialog.run()!=Gtk::RESPONSE_OK)
2227 text=entry.get_text();
2233 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2238 true); // use_separator
2240 Gtk::Label label(message);
2242 dialog.get_vbox()->pack_start(label);
2244 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2245 text_buffer->set_text(text);
2246 Gtk::TextView text_view(text_buffer);
2249 dialog.get_vbox()->pack_start(text_view);
2251 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2252 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2253 dialog.set_default_response(Gtk::RESPONSE_OK);
2255 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2258 if(dialog.run()!=Gtk::RESPONSE_OK)
2261 text=text_buffer->get_text();
2267 App::open(std::string filename)
2269 return open_as(filename,filename);
2272 // this is called from autorecover.cpp:
2273 // App::open_as(get_shadow_file_name(filename),filename)
2274 // other than that, 'filename' and 'as' are the same
2276 App::open_as(std::string filename,std::string as)
2279 char long_name[1024];
2280 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2281 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2282 // don't use it if that's the case
2283 if (long_name[0] != '\0')
2289 OneMoment one_moment;
2291 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
2292 if(canvas && get_instance(canvas))
2294 get_instance(canvas)->find_canvas_view(canvas)->present();
2295 info("%s is already open", filename.c_str());
2296 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2301 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2303 if (as.find(DEFAULT_FILENAME_PREFIX) != 0)
2304 add_recent_file(as);
2306 handle<Instance> instance(Instance::create(canvas));
2309 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2311 set_recent_file_window_size(instance);
2315 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)")))
2316 instance->dialog_cvs_update();
2321 dialog_error_blocking(_("Error"), x);
2326 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2337 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2339 String file_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2340 canvas->set_name(file_name);
2341 file_name += ".sifz";
2343 canvas->rend_desc().set_frame_rate(24.0);
2344 canvas->rend_desc().set_time_start(0.0);
2345 canvas->rend_desc().set_time_end(5.0);
2346 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2347 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2348 canvas->rend_desc().set_tl(Vector(-4,2.25));
2349 canvas->rend_desc().set_br(Vector(4,-2.25));
2350 canvas->rend_desc().set_w(480);
2351 canvas->rend_desc().set_h(270);
2352 canvas->rend_desc().set_antialias(1);
2353 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2354 canvas->set_file_name(file_name);
2356 handle<Instance> instance = Instance::create(canvas);
2358 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2359 instance->find_canvas_view(canvas)->canvas_properties.present();
2363 App::dialog_open(string filename)
2365 if (filename.empty())
2368 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2370 // If the filename still has wildcards, then we should
2371 // continue looking for the file we want
2372 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2378 get_ui_interface()->error(_("Unable to open file"));
2383 App::set_selected_instance(etl::loose_handle<Instance> instance)
2385 /* if(get_selected_instance()==instance)
2387 selected_instance=instance;
2388 signal_instance_selected()(instance);
2394 selected_instance=instance;
2395 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2399 instance->focus(instance->get_canvas());
2402 set_selected_canvas_view(0);
2404 signal_instance_selected()(instance);
2408 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2410 selected_canvas_view=canvas_view;
2411 signal_canvas_view_focus()(selected_canvas_view);
2414 selected_instance=canvas_view->get_instance();
2415 signal_instance_selected()(canvas_view->get_instance());
2418 if(get_selected_canvas_view()==canvas_view)
2420 signal_canvas_view_focus()(selected_canvas_view);
2421 signal_instance_selected()(canvas_view->get_instance());
2424 selected_canvas_view=canvas_view;
2425 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2426 set_selected_instance(canvas_view->get_instance());
2427 signal_canvas_view_focus()(selected_canvas_view);
2431 etl::loose_handle<Instance>
2432 App::get_instance(etl::handle<synfig::Canvas> canvas)
2434 if(!canvas) return 0;
2435 canvas=canvas->get_root();
2437 std::list<etl::handle<Instance> >::iterator iter;
2438 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2440 if((*iter)->get_canvas()==canvas)
2456 if(selected_instance)
2457 selected_instance->undo();
2463 if(selected_instance)
2464 selected_instance->redo();
2468 studio::App::get_base_path()
2470 return app_base_path_;