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(!window_size_broken)
1628 add_recent_file(recent_file,recent_file_window_size);
1630 add_recent_file(recent_file);
1633 if(!window_size_broken && file_window_size)
1634 window_size_broken = true;
1636 if(window_size_broken)
1638 recent_files_window_size.clear();
1639 recent_files_window_size.resize(recent_files.size());
1642 std::string filename=get_config_file("settings");
1643 if(!synfigapp::Main::settings().load_from_file(filename))
1645 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1646 //if(!synfigapp::Main::settings().load_from_file(filename))
1648 gamma.set_gamma(1.0/2.2);
1649 reset_initial_window_configuration();
1652 setlocale(LC_NUMERIC,old_locale);
1656 synfig::warning("Caught exception when attempting to load settings.");
1661 App::reset_initial_window_configuration()
1663 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1664 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1665 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1666 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1667 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1668 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1669 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1670 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1671 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1672 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1673 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1674 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1675 #ifdef SINGLE_THREADED
1676 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1678 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1679 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1683 App::shutdown_request(GdkEventAny*)
1687 //return !shutdown_in_progress;
1693 if(shutdown_in_progress)return;
1696 get_ui_interface()->task(_("Quit Request"));
1699 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1703 std::list<etl::handle<Instance> >::iterator iter;
1704 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1706 if(!(*iter)->safe_close())
1710 if((*iter)->synfigapp::Instance::get_action_count())
1712 handle<synfigapp::UIInterface> uim;
1713 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1715 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1716 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1718 case synfigapp::UIInterface::RESPONSE_NO:
1720 case synfigapp::UIInterface::RESPONSE_YES:
1723 case synfigapp::UIInterface::RESPONSE_CANCEL:
1732 if((*iter)->synfigapp::Instance::is_modified())
1734 handle<synfigapp::UIInterface> uim;
1735 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1737 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() );
1738 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1740 case synfigapp::UIInterface::RESPONSE_NO:
1742 case synfigapp::UIInterface::RESPONSE_YES:
1743 (*iter)->dialog_cvs_commit();
1745 case synfigapp::UIInterface::RESPONSE_CANCEL:
1754 // This next line causes things to crash for some reason
1758 shutdown_in_progress=true;
1760 instance_list.clear();
1762 while(studio::App::events_pending())studio::App::iteration(false);
1765 auto_recover->normal_shutdown();
1767 get_ui_interface()->task(_("Quit Request sent"));
1773 dialog_setup->refresh();
1774 dialog_setup->show();
1777 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1778 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1781 //#define USE_WIN32_FILE_DIALOGS 1
1784 #ifdef USE_WIN32_FILE_DIALOGS
1785 static OPENFILENAME ofn={};
1789 #include <gdk/gdkwin32.h>
1793 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1795 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1797 #ifdef USE_WIN32_FILE_DIALOGS
1798 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1800 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1801 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1802 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1804 ofn.lStructSize=sizeof(OPENFILENAME);
1805 ofn.hwndOwner = hWnd;
1806 ofn.hInstance = hInstance;
1807 ofn.lpstrFilter = szFilter;
1808 // ofn.lpstrCustomFilter=NULL;
1809 // ofn.nMaxCustFilter=0;
1810 // ofn.nFilterIndex=0;
1811 // ofn.lpstrFile=NULL;
1812 ofn.nMaxFile=MAX_PATH;
1813 // ofn.lpstrFileTitle=NULL;
1814 // ofn.lpstrInitialDir=NULL;
1815 // ofn.lpstrTitle=NULL;
1816 ofn.Flags=OFN_HIDEREADONLY;
1817 // ofn.nFileOffset=0;
1818 // ofn.nFileExtension=0;
1819 ofn.lpstrDefExt=TEXT("sif");
1820 // ofn.lCustData = 0l;
1822 // ofn.lpTemplateName=NULL;
1824 CHAR szFilename[MAX_PATH];
1826 strcpy(szFilename,filename.c_str());
1827 strcpy(szTitle,title.c_str());
1829 ofn.lpstrFile=szFilename;
1830 ofn.lpstrFileTitle=szTitle;
1832 if(GetOpenFileName(&ofn))
1834 filename=szFilename;
1840 synfig::String prev_path;
1842 if(!_preferences.get_value(preference, prev_path))
1845 prev_path = absolute_path(prev_path);
1847 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1849 dialog->set_current_folder(prev_path);
1850 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1851 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1853 if (filename.empty())
1854 dialog->set_filename(prev_path);
1855 else if (is_absolute_path(filename))
1856 dialog->set_filename(filename);
1858 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1860 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1861 filename = dialog->get_filename();
1862 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1863 _preferences.set_value(preference, dirname(filename));
1877 GtkWidget *fileselection;
1878 fileselection = gtk_file_selection_new(title.c_str());
1881 if(basename(filename)==filename)
1883 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1886 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1888 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1890 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1891 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1893 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1894 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1896 gtk_widget_show(fileselection);
1904 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1905 _preferences.set_value(preference,dirname(filename));
1909 gtk_widget_destroy(fileselection);
1912 gtk_widget_destroy(fileselection);
1919 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1921 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1923 #if USE_WIN32_FILE_DIALOGS
1924 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1926 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1927 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1928 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1930 ofn.lStructSize=sizeof(OPENFILENAME);
1931 ofn.hwndOwner = hWnd;
1932 ofn.hInstance = hInstance;
1933 ofn.lpstrFilter = szFilter;
1934 // ofn.lpstrCustomFilter=NULL;
1935 // ofn.nMaxCustFilter=0;
1936 // ofn.nFilterIndex=0;
1937 // ofn.lpstrFile=NULL;
1938 ofn.nMaxFile=MAX_PATH;
1939 // ofn.lpstrFileTitle=NULL;
1940 // ofn.lpstrInitialDir=NULL;
1941 // ofn.lpstrTitle=NULL;
1942 ofn.Flags=OFN_OVERWRITEPROMPT;
1943 // ofn.nFileOffset=0;
1944 // ofn.nFileExtension=0;
1945 ofn.lpstrDefExt=TEXT("sif");
1946 // ofn.lCustData = 0l;
1948 // ofn.lpTemplateName=NULL;
1950 CHAR szFilename[MAX_PATH];
1952 strcpy(szFilename,filename.c_str());
1953 strcpy(szTitle,title.c_str());
1955 ofn.lpstrFile=szFilename;
1956 ofn.lpstrFileTitle=szTitle;
1958 if(GetSaveFileName(&ofn))
1960 filename=szFilename;
1961 _preferences.set_value(preference,dirname(filename));
1966 synfig::String prev_path;
1968 if(!_preferences.get_value(preference, prev_path))
1971 prev_path = absolute_path(prev_path);
1973 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1975 dialog->set_current_folder(prev_path);
1976 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1977 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1979 Widget_Enum *file_type_enum = 0;
1980 if (preference == ANIMATION_DIR_PREFERENCE)
1982 file_type_enum = manage(new Widget_Enum());
1983 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
1984 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
1985 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
1986 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
1987 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
1988 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
1990 Gtk::HBox *hbox = manage(new Gtk::HBox);
1991 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
1992 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
1995 dialog->set_extra_widget(*hbox);
1998 if (filename.empty())
1999 dialog->set_filename(prev_path);
2002 std::string full_path;
2003 if (is_absolute_path(filename))
2004 full_path = filename;
2006 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2008 // select the file if it exists
2009 dialog->set_filename(full_path);
2011 // if the file doesn't exist, put its name into the filename box
2013 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2014 dialog->set_current_name(basename(filename));
2017 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2018 if (preference == ANIMATION_DIR_PREFERENCE)
2019 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2020 filename = dialog->get_filename();
2021 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2022 _preferences.set_value(preference, dirname(filename));
2033 App::dialog_error_blocking(const std::string &title, const std::string &message)
2035 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2036 dialog.set_title(title);
2042 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2044 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2045 dialog.set_title(title);
2051 App::dialog_yes_no(const std::string &title, const std::string &message)
2056 true // use_separator
2058 Gtk::Label label(message);
2061 dialog.get_vbox()->pack_start(label);
2062 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2063 dialog.add_button(Gtk::StockID("gtk-no"),0);
2065 return dialog.run();
2069 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2074 true // use_separator
2076 Gtk::Label label(message);
2079 dialog.get_vbox()->pack_start(label);
2080 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2081 dialog.add_button(Gtk::StockID("gtk-no"),0);
2082 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2084 return dialog.run();
2088 App::dialog_not_implemented()
2090 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2091 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2096 try_open_url(const std::string &url)
2099 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2101 std::vector<std::string> command_line;
2102 std::vector<std::string> browsers;
2103 browsers.reserve(23);
2105 // Browser wrapper scripts
2106 #ifdef USE_OPEN_FOR_URLS
2107 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2109 browsers.push_back("xdg-open"); // XDG wrapper
2110 browsers.push_back("sensible-browser"); // Debian wrapper
2111 browsers.push_back("gnome-open"); // GNOME wrapper
2112 browsers.push_back("kfmclient"); // KDE wrapper
2113 browsers.push_back("exo-open"); // XFCE wrapper
2115 // Alternatives system
2116 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2117 browsers.push_back("x-www-browser"); // Debian GUI alternative
2119 // Individual browsers
2120 browsers.push_back("firefox");
2121 browsers.push_back("epiphany-browser");
2122 browsers.push_back("epiphany");
2123 browsers.push_back("konqueror");
2124 browsers.push_back("iceweasel");
2125 browsers.push_back("mozilla");
2126 browsers.push_back("netscape");
2127 browsers.push_back("icecat");
2128 browsers.push_back("galeon");
2129 browsers.push_back("midori");
2130 browsers.push_back("safari");
2131 browsers.push_back("opera");
2132 browsers.push_back("amaya");
2133 browsers.push_back("netsurf");
2134 browsers.push_back("dillo");
2136 // Try the user-specified browser first
2137 command_line.push_back(App::browser_command);
2138 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2139 command_line.push_back(url);
2141 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2142 catch( Glib::SpawnError& exception ){
2144 while ( !browsers.empty() )
2146 // Skip the browser if we already tried it
2147 if( browsers[0] == App::browser_command )
2150 // Construct the command line
2151 command_line.clear();
2152 command_line.push_back(browsers[0]);
2153 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2154 command_line.push_back(url);
2156 // Remove the browser from the list
2157 browsers.erase(browsers.begin());
2159 // Try to spawn the browser
2160 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2161 // Failed, move on to the next one
2162 catch(Glib::SpawnError& exception){ continue; }
2163 return true; // No exception means we succeeded!
2174 if (!try_open_url("http://synfig.org/Documentation"))
2176 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2177 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2178 dialog.set_title(_("Help"));
2184 App::open_url(const std::string &url)
2186 if(!try_open_url(url))
2188 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2189 dialog.set_secondary_text(url);
2190 dialog.set_title(_("No browser found"));
2196 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2201 true); // use_separator
2203 Gtk::Label label(message);
2205 dialog.get_vbox()->pack_start(label);
2208 entry.set_text(text);
2210 entry.set_activates_default(true);
2212 dialog.get_vbox()->pack_start(entry);
2214 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2215 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2216 dialog.set_default_response(Gtk::RESPONSE_OK);
2218 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2221 if(dialog.run()!=Gtk::RESPONSE_OK)
2224 text=entry.get_text();
2230 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2235 true); // use_separator
2237 Gtk::Label label(message);
2239 dialog.get_vbox()->pack_start(label);
2241 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2242 text_buffer->set_text(text);
2243 Gtk::TextView text_view(text_buffer);
2246 dialog.get_vbox()->pack_start(text_view);
2248 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2249 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2250 dialog.set_default_response(Gtk::RESPONSE_OK);
2252 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2255 if(dialog.run()!=Gtk::RESPONSE_OK)
2258 text=text_buffer->get_text();
2264 App::open(std::string filename)
2266 return open_as(filename,filename);
2269 // this is called from autorecover.cpp:
2270 // App::open_as(get_shadow_file_name(filename),filename)
2271 // other than that, 'filename' and 'as' are the same
2273 App::open_as(std::string filename,std::string as)
2276 char long_name[1024];
2277 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2278 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2279 // don't use it if that's the case
2280 if (long_name[0] != '\0')
2286 OneMoment one_moment;
2288 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
2289 if(canvas && get_instance(canvas))
2291 get_instance(canvas)->find_canvas_view(canvas)->present();
2292 info("%s is already open", filename.c_str());
2293 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2298 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2300 if (as.find(DEFAULT_FILENAME_PREFIX) != 0)
2301 add_recent_file(as);
2303 handle<Instance> instance(Instance::create(canvas));
2306 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2308 set_recent_file_window_size(instance);
2312 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)")))
2313 instance->dialog_cvs_update();
2318 dialog_error_blocking(_("Error"), x);
2323 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2334 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2336 String file_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2337 canvas->set_name(file_name);
2338 file_name += ".sifz";
2340 canvas->rend_desc().set_frame_rate(24.0);
2341 canvas->rend_desc().set_time_start(0.0);
2342 canvas->rend_desc().set_time_end(5.0);
2343 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2344 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2345 canvas->rend_desc().set_tl(Vector(-4,2.25));
2346 canvas->rend_desc().set_br(Vector(4,-2.25));
2347 canvas->rend_desc().set_w(480);
2348 canvas->rend_desc().set_h(270);
2349 canvas->rend_desc().set_antialias(1);
2350 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2351 canvas->set_file_name(file_name);
2353 handle<Instance> instance = Instance::create(canvas);
2355 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2356 instance->find_canvas_view(canvas)->canvas_properties.present();
2360 App::dialog_open(string filename)
2362 if (filename.empty())
2365 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2367 // If the filename still has wildcards, then we should
2368 // continue looking for the file we want
2369 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2375 get_ui_interface()->error(_("Unable to open file"));
2380 App::set_selected_instance(etl::loose_handle<Instance> instance)
2382 /* if(get_selected_instance()==instance)
2384 selected_instance=instance;
2385 signal_instance_selected()(instance);
2391 selected_instance=instance;
2392 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2396 instance->focus(instance->get_canvas());
2399 set_selected_canvas_view(0);
2401 signal_instance_selected()(instance);
2405 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2407 selected_canvas_view=canvas_view;
2408 signal_canvas_view_focus()(selected_canvas_view);
2411 selected_instance=canvas_view->get_instance();
2412 signal_instance_selected()(canvas_view->get_instance());
2415 if(get_selected_canvas_view()==canvas_view)
2417 signal_canvas_view_focus()(selected_canvas_view);
2418 signal_instance_selected()(canvas_view->get_instance());
2421 selected_canvas_view=canvas_view;
2422 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2423 set_selected_instance(canvas_view->get_instance());
2424 signal_canvas_view_focus()(selected_canvas_view);
2428 etl::loose_handle<Instance>
2429 App::get_instance(etl::handle<synfig::Canvas> canvas)
2431 if(!canvas) return 0;
2432 canvas=canvas->get_root();
2434 std::list<etl::handle<Instance> >::iterator iter;
2435 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2437 if((*iter)->get_canvas()==canvas)
2453 if(selected_instance)
2454 selected_instance->undo();
2460 if(selected_instance)
2461 selected_instance->redo();
2465 studio::App::get_base_path()
2467 return app_base_path_;