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>
60 #include <gdkmm/general.h>
62 #include <synfig/loadcanvas.h>
63 #include <synfig/savecanvas.h>
69 #include "canvasview.h"
70 #include "dialog_setup.h"
71 #include "dialog_gradient.h"
72 #include "dialog_color.h"
75 #include "onemoment.h"
77 #include "dockmanager.h"
79 #include "state_eyedrop.h"
80 #include "state_normal.h"
81 #include "state_draw.h"
82 #include "state_fill.h"
83 #include "state_bline.h"
84 #include "state_polygon.h"
85 #include "state_sketch.h"
86 #include "state_gradient.h"
87 #include "state_circle.h"
88 #include "state_rectangle.h"
89 #include "state_smoothmove.h"
90 #include "state_scale.h"
91 #include "state_width.h"
92 #include "state_rotate.h"
93 #include "state_zoom.h"
95 #include "devicetracker.h"
96 #include "dialog_tooloptions.h"
97 #include "widget_enum.h"
99 #include "autorecover.h"
101 #include <synfigapp/settings.h>
102 #include "dock_history.h"
103 #include "dock_canvases.h"
104 #include "dock_keyframes.h"
105 #include "dock_layers.h"
106 #include "dock_params.h"
107 #include "dock_metadata.h"
108 #include "dock_children.h"
109 #include "dock_info.h"
110 #include "dock_navigator.h"
111 #include "dock_layergroups.h"
112 #include "dock_timetrack.h"
113 #include "dock_curves.h"
115 #include "mod_palette/mod_palette.h"
116 #include "mod_mirror/mod_mirror.h"
118 #include <sys/stat.h>
124 #include "statemanager.h"
130 #include <gtkmm/accelmap.h>
131 #include <gtkmm/filechooser.h>
132 #include <gtkmm/filechooserdialog.h>
138 /* === U S I N G =========================================================== */
142 using namespace synfig;
143 using namespace studio;
145 /* === M A C R O S ========================================================= */
147 #ifndef SYNFIG_USER_APP_DIR
149 #define SYNFIG_USER_APP_DIR "Library/Synfig"
150 #elif defined(_WIN32)
151 #define SYNFIG_USER_APP_DIR "Synfig"
153 #define SYNFIG_USER_APP_DIR ".synfig"
158 #define DPM2DPI(x) (float(x)/39.3700787402f)
159 #define DPI2DPM(x) (float(x)*39.3700787402f)
165 # define IMAGE_DIR "share\\pixmaps"
170 # define IMAGE_DIR "/usr/local/share/pixmaps"
174 # define IMAGE_EXT "tif"
177 #include <synfigapp/main.h>
179 /* === S I G N A L S ======================================================= */
181 static sigc::signal<void> signal_present_all_;
183 App::signal_present_all() { return signal_present_all_; }
185 static sigc::signal<void> signal_recent_files_changed_;
187 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
189 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
190 sigc::signal<void,etl::loose_handle<CanvasView> >&
191 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
193 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
194 sigc::signal<void,etl::handle<Instance> >&
195 App::signal_instance_selected() { return signal_instance_selected_; }
197 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
198 sigc::signal<void,etl::handle<Instance> >&
199 App::signal_instance_created() { return signal_instance_created_; }
201 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
202 sigc::signal<void,etl::handle<Instance> >&
203 App::signal_instance_deleted() { return signal_instance_deleted_; }
205 /* === G L O B A L S ======================================================= */
207 static std::list<std::string> recent_files;
208 const std::list<std::string>& App::get_recent_files() { return recent_files; }
210 static std::list<std::string> recent_files_window_size;
212 int App::Busy::count;
213 bool App::shutdown_in_progress;
215 synfig::Gamma App::gamma;
217 Glib::RefPtr<studio::UIManager> App::ui_manager_;
219 synfig::Distance::System App::distance_system;
221 studio::Dialog_Setup* App::dialog_setup;
223 etl::handle< studio::ModPalette > mod_palette_;
224 //studio::Dialog_Palette* App::dialog_palette;
226 std::list<etl::handle<Instance> > App::instance_list;
228 static etl::handle<synfigapp::UIInterface> ui_interface_;
229 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
231 etl::handle<Instance> App::selected_instance;
232 etl::handle<CanvasView> App::selected_canvas_view;
234 studio::About *studio::App::about=NULL;
236 studio::Toolbox *studio::App::toolbox=NULL;
238 studio::AutoRecover *studio::App::auto_recover=NULL;
240 studio::IPC *ipc=NULL;
242 studio::DockManager* studio::App::dock_manager=0;
244 studio::DeviceTracker* studio::App::device_tracker=0;
246 studio::Dialog_Gradient* studio::App::dialog_gradient;
248 studio::Dialog_Color* studio::App::dialog_color;
250 Gtk::InputDialog* studio::App::dialog_input;
252 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
254 studio::Dock_History* dock_history;
255 studio::Dock_Canvases* dock_canvases;
256 studio::Dock_Keyframes* dock_keyframes;
257 studio::Dock_Layers* dock_layers;
258 studio::Dock_Params* dock_params;
259 studio::Dock_MetaData* dock_meta_data;
260 studio::Dock_Children* dock_children;
261 studio::Dock_Info* dock_info;
262 studio::Dock_LayerGroups* dock_layer_groups;
263 studio::Dock_Navigator* dock_navigator;
264 studio::Dock_Timetrack* dock_timetrack;
265 studio::Dock_Curves* dock_curves;
267 std::list< etl::handle< studio::Module > > module_list_;
269 bool studio::App::use_colorspace_gamma=true;
270 #ifdef SINGLE_THREADED
271 bool studio::App::single_threaded=false;
273 bool studio::App::restrict_radius_ducks=false;
274 #ifdef USE_OPEN_FOR_URLS
275 String studio::App::browser_command("open"); // MacOS only
277 String studio::App::browser_command("xdg-open"); // Linux XDG standard
280 static int max_recent_files_=25;
281 int studio::App::get_max_recent_files() { return max_recent_files_; }
282 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
284 static synfig::String app_base_path_;
289 really_delete_widget(Gtk::Widget *widget)
291 // synfig::info("really delete %p", (void*)widget);
296 // nasty workaround - when we've finished with a popup menu, we want to delete it
297 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
298 // so schedule the real delete to happen in 50ms, giving the action a chance to run
300 delete_widget(Gtk::Widget *widget)
302 // synfig::info("delete %p", (void*)widget);
303 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
306 }; // END of namespace studio
307 studio::StateManager* state_manager;
312 class GlobalUIInterface : public synfigapp::UIInterface
316 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
321 true // use_separator
323 Gtk::Label label(message);
326 dialog.get_vbox()->pack_start(label);
327 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
328 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
330 dialog.set_default_response(dflt);
332 return (Response)dialog.run();
334 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
339 true // use_separator
341 Gtk::Label label(message);
344 dialog.get_vbox()->pack_start(label);
345 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
346 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
347 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
349 dialog.set_default_response(dflt);
351 return (Response)dialog.run();
353 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
358 true // use_separator
360 Gtk::Label label(message);
363 dialog.get_vbox()->pack_start(label);
364 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
365 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
367 dialog.set_default_response(dflt);
369 return (Response)dialog.run();
373 task(const std::string &task)
375 std::cerr<<task<<std::endl;
376 while(studio::App::events_pending())studio::App::iteration(false);
381 error(const std::string &err)
383 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
390 warning(const std::string &err)
392 std::cerr<<"warning: "<<err<<std::endl;
393 while(studio::App::events_pending())studio::App::iteration(false);
398 amount_complete(int /*current*/, int /*total*/)
400 while(studio::App::events_pending())studio::App::iteration(false);
405 /* === P R O C E D U R E S ================================================= */
409 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
411 action_group_list.push_back(action_group);
412 Gtk::UIManager::insert_action_group(action_group, pos);
416 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
418 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
419 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
420 if(*iter==action_group)
422 action_group_list.erase(iter);
423 Gtk::UIManager::remove_action_group(action_group);
426 synfig::error("Unable to find action group");
430 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
432 ui_manager->insert_action_group(group,0);
434 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
435 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
437 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
439 if(*iter && (*iter)->get_name()!="menus")
441 synfig::info("Removing action group "+(*iter)->get_name());
442 ui_manager->remove_action_group(*iter);
445 ui_manager->insert_action_group(group,0);
447 for(;!prev_groups.empty();prev_groups.pop_front())
449 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
450 ui_manager->insert_action_group(prev_groups.front(),1);
454 class Preferences : public synfigapp::Settings
457 virtual bool get_value(const synfig::String& key, synfig::String& value)const
461 value=strprintf("%f %f %f %f",
462 App::gamma.get_gamma_r(),
463 App::gamma.get_gamma_g(),
464 App::gamma.get_gamma_b(),
465 App::gamma.get_black_level()
469 if(key=="time_format")
471 value=strprintf("%i",App::get_time_format());
474 if(key=="file_history.size")
476 value=strprintf("%i",App::get_max_recent_files());
479 if(key=="use_colorspace_gamma")
481 value=strprintf("%i",(int)App::use_colorspace_gamma);
484 if(key=="distance_system")
486 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
489 #ifdef SINGLE_THREADED
490 if(key=="single_threaded")
492 value=strprintf("%i",(int)App::single_threaded);
496 if(key=="auto_recover_backup_interval")
498 value=strprintf("%i",App::auto_recover->get_timeout());
501 if(key=="restrict_radius_ducks")
503 value=strprintf("%i",(int)App::restrict_radius_ducks);
506 if(key=="browser_command")
508 value=App::browser_command;
512 return synfigapp::Settings::get_value(key,value);
515 virtual bool set_value(const synfig::String& key,const synfig::String& value)
521 strscanf(value,"%f %f %f %f",
528 App::gamma.set_all(r,g,b,blk);
532 if(key=="time_format")
534 int i(atoi(value.c_str()));
535 App::set_time_format(static_cast<synfig::Time::Format>(i));
538 if(key=="auto_recover_backup_interval")
540 int i(atoi(value.c_str()));
541 App::auto_recover->set_timeout(i);
544 if(key=="file_history.size")
546 int i(atoi(value.c_str()));
547 App::set_max_recent_files(i);
550 if(key=="use_colorspace_gamma")
552 int i(atoi(value.c_str()));
553 App::use_colorspace_gamma=i;
556 if(key=="distance_system")
558 App::distance_system=Distance::ident_system(value);;
561 #ifdef SINGLE_THREADED
562 if(key=="single_threaded")
564 int i(atoi(value.c_str()));
565 App::single_threaded=i;
569 if(key=="restrict_radius_ducks")
571 int i(atoi(value.c_str()));
572 App::restrict_radius_ducks=i;
575 if(key=="browser_command")
577 App::browser_command=value;
581 return synfigapp::Settings::set_value(key,value);
584 virtual KeyList get_key_list()const
586 KeyList ret(synfigapp::Settings::get_key_list());
587 ret.push_back("gamma");
588 ret.push_back("time_format");
589 ret.push_back("distance_system");
590 ret.push_back("file_history.size");
591 ret.push_back("use_colorspace_gamma");
592 #ifdef SINGLE_THREADED
593 ret.push_back("single_threaded");
595 ret.push_back("auto_recover_backup_interval");
596 ret.push_back("restrict_radius_ducks");
597 ret.push_back("browser_command");
602 static ::Preferences _preferences;
607 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
609 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
611 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
613 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
614 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
615 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
616 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
617 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
618 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
619 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
620 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
621 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
622 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
623 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
624 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
625 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
627 // Add the synfigapp actions...
628 synfigapp::Action::Book::iterator iter;
629 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
631 actions_action_group->add(Gtk::Action::create(
632 "action-"+iter->second.name,
633 get_action_stock_id(iter->second),
634 iter->second.local_name,iter->second.local_name
638 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
639 #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); }
640 #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); }
642 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
643 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
644 DEFINE_ACTION("new", Gtk::Stock::NEW);
645 DEFINE_ACTION("open", Gtk::Stock::OPEN);
646 DEFINE_ACTION("save", Gtk::Stock::SAVE);
647 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
648 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
649 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
650 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
651 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
652 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
653 DEFINE_ACTION("import", _("Import"));
654 DEFINE_ACTION("render", _("Render"));
655 DEFINE_ACTION("preview", _("Preview"));
656 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
657 DEFINE_ACTION("sound", _("Sound File"));
658 DEFINE_ACTION("options", _("Options"));
659 DEFINE_ACTION("close", _("Close View"));
660 DEFINE_ACTION("close-document", _("Close Document"));
661 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
664 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
665 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
666 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
667 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
668 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
669 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
670 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
671 DEFINE_ACTION("properties", _("Properties"));
673 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
674 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
675 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
676 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
677 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
678 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
679 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
680 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
681 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
682 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
683 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
684 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
685 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
686 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
687 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
688 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
689 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
690 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
691 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
692 DEFINE_ACTION("play", _("Play"));
693 // DEFINE_ACTION("pause", _("Pause"));
694 DEFINE_ACTION("stop", _("Stop"));
695 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
696 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
697 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
698 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
699 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
700 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
701 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
702 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
703 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
704 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
705 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
706 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
707 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
708 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
709 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
710 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
711 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
712 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
713 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
714 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
715 DEFINE_ACTION("seek-end", _("Seek to End"));
717 DEFINE_ACTION("action-group_add", _("Add group"));
719 DEFINE_ACTION("canvas-new", _("New Canvas"));
721 DEFINE_ACTION("amount-inc", _("Increase Amount"));
722 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
727 // Set up synfigapp actions
729 synfigapp::Action::Book::iterator iter;
731 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
733 Gtk::StockID stock_id;
735 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
737 //Gtk::Image* image(manage(new Gtk::Image()));
738 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
739 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
740 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
741 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
742 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
743 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
744 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
745 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
746 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
747 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
749 actions_action_group->add(Gtk::Action::create(
750 "action-"+iter->second.name,
752 iter->second.local_name,iter->second.local_name
760 Glib::ustring ui_info =
762 " <popup name='menu-toolbox' action='menu-toolbox'>"
763 " <menu action='menu-file'>"
766 " <popup name='menu-main' action='menu-main'>"
767 " <menu action='menu-file'>"
768 " <menuitem action='new' />"
769 " <menuitem action='open' />"
770 " <menuitem action='save' />"
771 " <menuitem action='save-as' />"
772 " <menuitem action='revert' />"
773 " <separator name='bleh01'/>"
774 " <menuitem action='cvs-add' />"
775 " <menuitem action='cvs-update' />"
776 " <menuitem action='cvs-commit' />"
777 " <menuitem action='cvs-revert' />"
778 " <separator name='bleh02'/>"
779 " <menuitem action='import' />"
780 " <separator name='bleh03'/>"
781 " <menuitem action='render' />"
782 " <menuitem action='preview' />"
783 " <menuitem action='sound' />"
784 " <separator name='bleh04'/>"
785 " <menuitem action='options' />"
786 " <menuitem action='close' />"
787 " <menuitem action='close-document' />"
788 " <menuitem action='quit' />"
790 " <menu action='menu-edit'>"
791 " <menuitem action='undo'/>"
792 " <menuitem action='redo'/>"
793 " <separator name='bleh05'/>"
794 " <menuitem action='cut'/>"
795 " <menuitem action='copy'/>"
796 " <menuitem action='paste'/>"
797 " <separator name='bleh06'/>"
798 " <menuitem action='select-all-ducks'/>"
799 " <menuitem action='unselect-all-layers'/>"
800 " <separator name='bleh07'/>"
801 " <menuitem action='properties'/>"
803 " <menu action='menu-view'>"
804 " <menu action='menu-duck-mask'>"
805 " <menuitem action='mask-position-ducks' />"
806 " <menuitem action='mask-vertex-ducks' />"
807 " <menuitem action='mask-tangent-ducks' />"
808 " <menuitem action='mask-radius-ducks' />"
809 " <menuitem action='mask-width-ducks' />"
810 " <menuitem action='mask-angle-ducks' />"
812 " <menu action='menu-preview-quality'>"
813 " <menuitem action='quality-00' />"
814 " <menuitem action='quality-01' />"
815 " <menuitem action='quality-02' />"
816 " <menuitem action='quality-03' />"
817 " <menuitem action='quality-04' />"
818 " <menuitem action='quality-05' />"
819 " <menuitem action='quality-06' />"
820 " <menuitem action='quality-07' />"
821 " <menuitem action='quality-08' />"
822 " <menuitem action='quality-09' />"
823 " <menuitem action='quality-10' />"
825 " <menu action='menu-lowres-pixel'>"
826 " <menuitem action='decrease-low-res-pixel-size'/>"
827 " <menuitem action='increase-low-res-pixel-size'/>"
828 " <separator name='pixel-size-separator'/>"
831 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
832 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
836 " <separator name='bleh08'/>"
837 " <menuitem action='play'/>"
838 //" <menuitem action='pause'/>"
839 " <menuitem action='stop'/>"
840 " <menuitem action='dialog-flipbook'/>"
841 " <separator name='bleh09'/>"
842 " <menuitem action='toggle-grid-show'/>"
843 " <menuitem action='toggle-grid-snap'/>"
844 " <menuitem action='toggle-guide-show'/>"
845 " <menuitem action='toggle-low-res'/>"
846 " <menuitem action='toggle-onion-skin'/>"
847 " <separator name='bleh10'/>"
848 " <menuitem action='canvas-zoom-in'/>"
849 " <menuitem action='canvas-zoom-out'/>"
850 " <menuitem action='canvas-zoom-fit'/>"
851 " <menuitem action='canvas-zoom-100'/>"
852 " <separator name='bleh11'/>"
853 " <menuitem action='time-zoom-in'/>"
854 " <menuitem action='time-zoom-out'/>"
855 " <separator name='bleh12'/>"
856 " <menuitem action='jump-next-keyframe'/>"
857 " <menuitem action='jump-prev-keyframe'/>"
858 " <menuitem action='seek-next-frame'/>"
859 " <menuitem action='seek-prev-frame'/>"
860 " <menuitem action='seek-next-second'/>"
861 " <menuitem action='seek-prev-second'/>"
862 " <menuitem action='seek-begin'/>"
863 " <menuitem action='seek-end'/>"
865 " <menu action='menu-canvas'>"
866 " <menuitem action='canvas-new'/>"
868 " <menu name='menu-state' action='menu-state'>"
870 " <menu action='menu-group'>"
871 " <menuitem action='action-group_add'/>"
873 " <menu action='menu-layer'>"
874 //" <menuitem action='cut'/>"
875 //" <menuitem action='copy'/>"
876 //" <menuitem action='paste'/>"
877 //" <separator name='bleh06'/>"
878 " <menu action='menu-layer-new'></menu>"
879 " <menuitem action='amount-inc'/>"
880 " <menuitem action='amount-dec'/>"
882 " <menu action='menu-keyframe'>"
883 " <menuitem action='keyframe-properties'/>"
890 " <menubar name='MenuBar'>"
891 " <menu action='MenuFile'>"
892 " <menuitem action='New'/>"
893 " <menuitem action='Open'/>"
895 " <menuitem action='Quit'/>"
897 " <menu action='MenuEdit'>"
898 " <menuitem action='Cut'/>"
899 " <menuitem action='Copy'/>"
900 " <menuitem action='Paste'/>"
903 " <toolbar name='ToolBar'>"
904 " <toolitem action='Open'/>"
905 " <toolitem action='Quit'/>"
911 actions_action_group->set_sensitive(false);
912 App::ui_manager()->set_add_tearoffs(true);
913 App::ui_manager()->insert_action_group(menus_action_group,1);
914 App::ui_manager()->insert_action_group(actions_action_group,1);
915 App::ui_manager()->add_ui_from_string(ui_info);
917 //App::ui_manager()->get_accel_group()->unlock();
919 catch(const Glib::Error& ex)
921 synfig::error("building menus and toolbars failed: " + ex.what());
924 // Add default keyboard accelerators
925 #define ACCEL(path,accel) \
927 Gtk::AccelKey accel_key(accel,path); \
928 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
931 #define ACCEL2(accel) \
933 Gtk::AccelKey accel_key(accel); \
934 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
937 ACCEL("<Actions>//select-all-ducks","<Control>a");
938 ACCEL("<Actions>//unselect-all-layers","<Control>d");
939 ACCEL("<Actions>//render","F9");
940 ACCEL("<Actions>//preview","F11");
941 ACCEL("<Actions>//properties","F8");
942 ACCEL("<Actions>//options","F12");
943 ACCEL("<Actions>//import","<control>i");
944 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
945 ACCEL("<Actions>//toggle-grid-show","<Control>g");
946 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
947 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
948 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
949 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
950 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
951 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
952 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
953 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
955 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
956 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
958 ACCEL("<Actions>//quality-01","<Control>1");
959 ACCEL("<Actions>//quality-02","<Control>2");
960 ACCEL("<Actions>//quality-03","<Control>3");
961 ACCEL("<Actions>//quality-04","<Control>4");
962 ACCEL("<Actions>//quality-05","<Control>5");
963 ACCEL("<Actions>//quality-06","<Control>6");
964 ACCEL("<Actions>//quality-07","<Control>7");
965 ACCEL("<Actions>//quality-08","<Control>8");
966 ACCEL("<Actions>//quality-09","<Control>9");
967 ACCEL("<Actions>//quality-10","<Control>0");
968 ACCEL("<Actions>//undo","<Control>z");
969 ACCEL("<Actions>//redo","<Control>r");
970 ACCEL("<Actions>//action-layer_remove","Delete");
972 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
973 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
974 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
975 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
976 ACCEL("<Actions>//time-zoom-in","+");
977 ACCEL("<Actions>//time-zoom-out","_");
979 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
980 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
982 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
983 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
985 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
986 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
987 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
988 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
989 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
990 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
991 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
992 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
993 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
994 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
995 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
996 ACCEL("<Actions>//play", "<Control>p");
997 ACCEL("<Actions>//seek-begin","Home");
998 ACCEL("<Actions>//seek-end","End");
1000 ACCEL("<Actions>//state-normal", "<Mod1>a");
1001 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1002 ACCEL("<Actions>//state-scale", "<Mod1>d");
1003 ACCEL("<Actions>//state-rotate", "<Mod1>s");
1005 ACCEL("<Actions>//state-bline", "<Mod1>b");
1006 ACCEL("<Actions>//state-circle", "<Mod1>c");
1007 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1008 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1010 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1011 ACCEL("<Actions>//state-fill", "<Mod1>f");
1012 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1013 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1015 ACCEL("<Actions>//state-draw", "<Mod1>w");
1016 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1017 ACCEL("<Actions>//state-width", "<Mod1>t");
1018 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1020 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1026 #define mkdir(x,y) mkdir(x)
1029 /* === M E T H O D S ======================================================= */
1031 App::App(int *argc, char ***argv):
1032 Gtk::Main(argc,argv),
1033 IconController(etl::dirname((*argv)[0]))
1035 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1038 ui_interface_=new GlobalUIInterface();
1042 // don't call thread_init() if threads are already initialized
1043 // on some machines bonobo_init() initialized threads before we get here
1044 if (!g_thread_supported())
1045 Glib::thread_init();
1047 distance_system=Distance::SYSTEM_UNITS;
1049 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1052 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1056 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1062 if(!SYNFIG_CHECK_VERSION())
1064 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1065 dialog_error_blocking("Synfig Studio",
1066 "This copy of Synfig Studio was compiled against a\n"
1067 "different version of libsynfig than what is currently\n"
1068 "installed. Synfig Studio will now abort. Try downloading\n"
1069 "the latest version from the Synfig website at\n"
1070 "http://synfig.org/Download"
1074 Glib::set_application_name(_("Synfig Studio"));
1076 Splash splash_screen;
1077 splash_screen.show();
1079 shutdown_in_progress=false;
1080 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1081 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1083 // Initialize the Synfig library
1084 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1087 get_ui_interface()->error(_("Failed to initialize synfig!"));
1091 // add the preferences to the settings
1092 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1096 studio_init_cb.task(_("Init UI Manager..."));
1097 App::ui_manager_=studio::UIManager::create();
1100 studio_init_cb.task(_("Init Dock Manager..."));
1101 dock_manager=new studio::DockManager();
1103 studio_init_cb.task(_("Init State Manager..."));
1104 state_manager=new StateManager();
1106 studio_init_cb.task(_("Init Toolbox..."));
1107 toolbox=new studio::Toolbox();
1109 studio_init_cb.task(_("Init About Dialog..."));
1110 about=new studio::About();
1112 studio_init_cb.task(_("Init Tool Options..."));
1113 dialog_tool_options=new studio::Dialog_ToolOptions();
1114 dock_manager->register_dockable(*dialog_tool_options);
1116 studio_init_cb.task(_("Init History..."));
1117 dock_history=new studio::Dock_History();
1118 dock_manager->register_dockable(*dock_history);
1120 studio_init_cb.task(_("Init Canvases..."));
1121 dock_canvases=new studio::Dock_Canvases();
1122 dock_manager->register_dockable(*dock_canvases);
1124 studio_init_cb.task(_("Init Keyframes..."));
1125 dock_keyframes=new studio::Dock_Keyframes();
1126 dock_manager->register_dockable(*dock_keyframes);
1128 studio_init_cb.task(_("Init Layers..."));
1129 dock_layers=new studio::Dock_Layers();
1130 dock_manager->register_dockable(*dock_layers);
1132 studio_init_cb.task(_("Init Params..."));
1133 dock_params=new studio::Dock_Params();
1134 dock_manager->register_dockable(*dock_params);
1136 studio_init_cb.task(_("Init MetaData..."));
1137 dock_meta_data=new studio::Dock_MetaData();
1138 dock_manager->register_dockable(*dock_meta_data);
1140 studio_init_cb.task(_("Init Children..."));
1141 dock_children=new studio::Dock_Children();
1142 dock_manager->register_dockable(*dock_children);
1144 studio_init_cb.task(_("Init Info..."));
1145 dock_info = new studio::Dock_Info();
1146 dock_manager->register_dockable(*dock_info);
1148 studio_init_cb.task(_("Init Navigator..."));
1149 dock_navigator = new studio::Dock_Navigator();
1150 dock_manager->register_dockable(*dock_navigator);
1152 studio_init_cb.task(_("Init Timetrack..."));
1153 dock_timetrack = new studio::Dock_Timetrack();
1154 dock_manager->register_dockable(*dock_timetrack);
1156 studio_init_cb.task(_("Init Curve Editor..."));
1157 dock_curves = new studio::Dock_Curves();
1158 dock_manager->register_dockable(*dock_curves);
1160 studio_init_cb.task(_("Init Layer Groups..."));
1161 dock_layer_groups = new studio::Dock_LayerGroups();
1162 dock_manager->register_dockable(*dock_layer_groups);
1165 studio_init_cb.task(_("Init Color Dialog..."));
1166 dialog_color=new studio::Dialog_Color();
1168 studio_init_cb.task(_("Init Gradient Dialog..."));
1169 dialog_gradient=new studio::Dialog_Gradient();
1171 studio_init_cb.task(_("Init DeviceTracker..."));
1172 device_tracker=new studio::DeviceTracker();
1174 studio_init_cb.task(_("Init Tools..."));
1177 state_manager->add_state(&state_normal);
1178 state_manager->add_state(&state_smooth_move);
1179 state_manager->add_state(&state_scale);
1180 state_manager->add_state(&state_rotate);
1181 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1184 state_manager->add_state(&state_bline);
1185 state_manager->add_state(&state_circle);
1186 state_manager->add_state(&state_rectangle);
1187 state_manager->add_state(&state_gradient);
1188 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1191 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1192 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1193 state_manager->add_state(&state_fill);
1194 state_manager->add_state(&state_eyedrop);
1195 state_manager->add_state(&state_zoom);
1197 // Disabled by default - it doesn't work properly?
1198 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1200 studio_init_cb.task(_("Init ModPalette..."));
1201 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1203 studio_init_cb.task(_("Init Setup Dialog..."));
1204 dialog_setup=new studio::Dialog_Setup();
1206 studio_init_cb.task(_("Init Input Dialog..."));
1207 dialog_input=new Gtk::InputDialog();
1208 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1209 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1211 studio_init_cb.task(_("Init auto recovery..."));
1212 auto_recover=new AutoRecover();
1214 studio_init_cb.amount_complete(9250,10000);
1215 studio_init_cb.task(_("Loading Settings..."));
1217 studio_init_cb.task(_("Checking auto-recover..."));
1219 studio_init_cb.amount_complete(9900,10000);
1221 bool opened_any = false;
1222 if(auto_recover->recovery_needed())
1224 splash_screen.hide();
1225 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1226 _("Synfig Studio seems to have crashed\n"
1227 "before you could save all your files.\n"
1228 "Would you like to re-open those files\n"
1229 "and recover your unsaved changes?")) ==
1230 synfigapp::UIInterface::RESPONSE_YES)
1232 int number_recovered;
1233 if(!auto_recover->recover(number_recovered))
1234 if (number_recovered)
1235 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1237 get_ui_interface()->error(_("Unable to recover from previous crash"));
1239 get_ui_interface()->error(
1240 _("Synfig Studio has attempted to recover\n"
1241 "from a previous crash. The files that it has\n"
1242 "recovered are NOT YET SAVED. It would be a good\n"
1243 "idea to review them and save them now."));
1245 if (number_recovered)
1248 splash_screen.show();
1251 // Look for any files given on the command line,
1252 // and load them if found.
1253 for(;*argc>=1;(*argc)--)
1254 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1256 studio_init_cb.task(_("Loading files..."));
1257 splash_screen.hide();
1258 open((*argv)[*argc]);
1260 splash_screen.show();
1263 // if no file was specified to be opened, create a new document to help new users get started more easily
1264 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1267 studio_init_cb.task(_("Done."));
1268 studio_init_cb.amount_complete(10000,10000);
1274 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1278 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1282 StateManager* App::get_state_manager() { return state_manager; }
1286 shutdown_in_progress=true;
1290 synfigapp::Main::settings().remove_domain("pref");
1292 selected_instance=0;
1294 // Unload all of the modules
1295 for(;!module_list_.empty();module_list_.pop_back())
1298 delete state_manager;
1302 delete auto_recover;
1308 // studio::App::iteration(false);
1312 // studio::App::iteration(false);
1314 // studio::App::iteration(false);
1316 delete dialog_setup;
1318 delete dialog_gradient;
1320 delete dialog_color;
1322 delete dialog_input;
1324 delete dock_manager;
1326 instance_list.clear();
1328 // studio::App::iteration(false);
1332 App::get_user_app_directory()
1334 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1336 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1338 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1343 App::get_config_file(const synfig::String& file)
1345 return Glib::build_filename(get_user_app_directory(),file);
1348 #define SCALE_FACTOR (1280)
1349 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1351 App::set_recent_file_window_size(etl::handle<Instance> instance)
1353 int screen_w(Gdk::screen_width());
1354 int screen_h(Gdk::screen_height());
1356 const std::string &canvas_window_size = *recent_files_window_size.begin();
1358 if(canvas_window_size.empty())
1361 synfig::String::size_type current=0;
1362 bool seen_root(false), shown_non_root(false);
1364 while(current != synfig::String::npos)
1366 // find end of first field (canvas) or return
1367 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1368 if(separator == synfig::String::npos) break;
1371 synfig::Canvas::Handle canvas;
1373 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current));
1375 catch(Exception::IDNotFound) {
1376 // can't find the canvas; skip to the next canvas or return
1377 separator = canvas_window_size.find_first_of('\t', current);
1378 if(separator == synfig::String::npos) return;
1379 current = separator+1;
1383 if (canvas->is_root())
1386 shown_non_root = true;
1388 // check that we have the tab character the ends this canvas' data or return
1389 current = separator+1;
1390 separator = canvas_window_size.find_first_of('\t', current);
1391 if(separator == synfig::String::npos) return;
1394 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1396 current = separator+1;
1400 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1401 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1402 x=x*screen_w/SCALE_FACTOR;
1403 y=y*screen_h/SCALE_FACTOR;
1404 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1405 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1406 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1407 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1409 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1410 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1412 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1413 canvasview->move(x,y);
1414 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1415 canvasview->present();
1417 current = separator+1;
1420 if (shown_non_root && !seen_root)
1421 instance->find_canvas_view(instance->get_canvas())->hide();
1425 App::add_recent_file(const etl::handle<Instance> instance)
1427 int screen_w(Gdk::screen_width());
1428 int screen_h(Gdk::screen_height());
1430 std::string canvas_window_size;
1432 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1433 Instance::CanvasViewList::const_iterator iter;
1435 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1437 if( !((*iter)->is_visible()) )
1440 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1441 int x_pos, y_pos, x_size, y_size;
1442 (*iter)->get_position(x_pos,y_pos);
1443 (*iter)->get_size(x_size,y_size);
1445 canvas_window_size += strprintf("%s %d %d %d %d\t",
1446 canvas->get_relative_id(canvas->get_root()).c_str(),
1447 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1448 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1451 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1456 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1458 std::string filename(file_name);
1460 assert(!filename.empty());
1462 if(filename.empty())
1465 // Toss out any "hidden" files
1466 if(basename(filename)[0]=='.')
1469 // If we aren't an absolute path, turn ourselves into one
1470 if(!is_absolute_path(filename))
1471 filename=absolute_path(filename);
1473 std::string old_window_size;
1475 list<string>::iterator iter;
1476 list<string>::iterator iter_wsize;
1477 // Check to see if the file is already on the list.
1478 // If it is, then remove it from the list
1479 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1482 recent_files.erase(iter);
1483 old_window_size = *iter_wsize;
1484 recent_files_window_size.erase(iter_wsize);
1489 // Push the filename to the front of the list
1490 recent_files.push_front(filename);
1491 if(window_size.empty())
1492 recent_files_window_size.push_front(old_window_size);
1494 recent_files_window_size.push_front(window_size);
1496 // Clean out the files at the end of the list.
1497 while(recent_files.size()>(unsigned)get_max_recent_files())
1499 recent_files.pop_back();
1500 recent_files_window_size.pop_back();
1503 signal_recent_files_changed_();
1508 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1511 App::get_time_format()
1513 return _App_time_format;
1517 App::set_time_format(synfig::Time::Format x)
1524 App::save_settings()
1529 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1530 setlocale(LC_NUMERIC, "C");
1532 std::string filename=get_config_file("accelrc");
1533 Gtk::AccelMap::save(filename);
1536 std::string filename=get_config_file("recentfiles");
1538 std::ofstream file(filename.c_str());
1542 synfig::warning("Unable to save %s",filename.c_str());
1546 list<string>::reverse_iterator iter;
1548 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1552 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1554 std::ofstream file(filename.c_str());
1558 synfig::warning("Unable to save %s",filename.c_str());
1562 list<string>::reverse_iterator iter;
1564 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1568 std::string filename=get_config_file("settings");
1569 synfigapp::Main::settings().save_to_file(filename);
1570 setlocale(LC_NUMERIC,old_locale);
1574 synfig::warning("Caught exception when attempting to save settings.");
1579 App::load_settings()
1584 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1585 setlocale(LC_NUMERIC, "C");
1587 std::string filename=get_config_file("accelrc");
1588 Gtk::AccelMap::load(filename);
1591 bool window_size_broken = false;
1593 std::string filename=get_config_file("recentfiles");
1594 std::string filename_window_size=filename+std::string("_window_size");
1596 std::ifstream file(filename.c_str());
1597 std::ifstream file_window_size(filename_window_size.c_str());
1599 if(!file_window_size)
1600 window_size_broken = true;
1604 std::string recent_file;
1605 std::string recent_file_window_size;
1606 getline(file,recent_file);
1607 if(!window_size_broken)
1608 getline(file_window_size,recent_file_window_size);
1609 if(!recent_file.empty())
1611 if(!window_size_broken && !file_window_size)
1612 window_size_broken = true;
1613 if(!window_size_broken)
1614 add_recent_file(recent_file,recent_file_window_size);
1616 add_recent_file(recent_file);
1619 if(!window_size_broken && file_window_size)
1620 window_size_broken = true;
1622 if(window_size_broken)
1624 recent_files_window_size.clear();
1625 recent_files_window_size.resize(recent_files.size());
1628 std::string filename=get_config_file("settings");
1629 if(!synfigapp::Main::settings().load_from_file(filename))
1631 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1632 //if(!synfigapp::Main::settings().load_from_file(filename))
1634 gamma.set_gamma(1.0/2.2);
1635 reset_initial_window_configuration();
1638 setlocale(LC_NUMERIC,old_locale);
1642 synfig::warning("Caught exception when attempting to load settings.");
1647 App::reset_initial_window_configuration()
1649 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1650 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1651 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1652 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1653 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1654 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1655 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1656 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1657 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1658 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1659 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1660 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1661 #ifdef SINGLE_THREADED
1662 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1664 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1665 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1669 App::shutdown_request(GdkEventAny*)
1673 //return !shutdown_in_progress;
1679 if(shutdown_in_progress)return;
1682 get_ui_interface()->task(_("Quit Request"));
1685 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1689 std::list<etl::handle<Instance> >::iterator iter;
1690 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1692 if(!(*iter)->safe_close())
1696 if((*iter)->synfigapp::Instance::get_action_count())
1698 handle<synfigapp::UIInterface> uim;
1699 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1701 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1702 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1704 case synfigapp::UIInterface::RESPONSE_NO:
1706 case synfigapp::UIInterface::RESPONSE_YES:
1709 case synfigapp::UIInterface::RESPONSE_CANCEL:
1718 if((*iter)->synfigapp::Instance::is_modified())
1720 handle<synfigapp::UIInterface> uim;
1721 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1723 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() );
1724 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1726 case synfigapp::UIInterface::RESPONSE_NO:
1728 case synfigapp::UIInterface::RESPONSE_YES:
1729 (*iter)->dialog_cvs_commit();
1731 case synfigapp::UIInterface::RESPONSE_CANCEL:
1740 // This next line causes things to crash for some reason
1744 shutdown_in_progress=true;
1746 instance_list.clear();
1748 while(studio::App::events_pending())studio::App::iteration(false);
1751 auto_recover->normal_shutdown();
1753 get_ui_interface()->task(_("Quit Request sent"));
1759 dialog_setup->refresh();
1760 dialog_setup->show();
1763 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1764 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1767 //#define USE_WIN32_FILE_DIALOGS 1
1770 #ifdef USE_WIN32_FILE_DIALOGS
1771 static OPENFILENAME ofn={};
1775 #include <gdk/gdkwin32.h>
1779 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1781 info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1783 #ifdef USE_WIN32_FILE_DIALOGS
1784 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1786 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1787 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1788 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1790 ofn.lStructSize=sizeof(OPENFILENAME);
1791 ofn.hwndOwner = hWnd;
1792 ofn.hInstance = hInstance;
1793 ofn.lpstrFilter = szFilter;
1794 // ofn.lpstrCustomFilter=NULL;
1795 // ofn.nMaxCustFilter=0;
1796 // ofn.nFilterIndex=0;
1797 // ofn.lpstrFile=NULL;
1798 ofn.nMaxFile=MAX_PATH;
1799 // ofn.lpstrFileTitle=NULL;
1800 // ofn.lpstrInitialDir=NULL;
1801 // ofn.lpstrTitle=NULL;
1802 ofn.Flags=OFN_HIDEREADONLY;
1803 // ofn.nFileOffset=0;
1804 // ofn.nFileExtension=0;
1805 ofn.lpstrDefExt=TEXT("sif");
1806 // ofn.lCustData = 0l;
1808 // ofn.lpTemplateName=NULL;
1810 CHAR szFilename[MAX_PATH];
1812 strcpy(szFilename,filename.c_str());
1813 strcpy(szTitle,title.c_str());
1815 ofn.lpstrFile=szFilename;
1816 ofn.lpstrFileTitle=szTitle;
1818 if(GetOpenFileName(&ofn))
1820 filename=szFilename;
1826 synfig::String prev_path;
1828 if(!_preferences.get_value(preference, prev_path))
1831 prev_path = absolute_path(prev_path);
1833 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1835 dialog->set_current_folder(prev_path);
1836 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1837 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1839 if (filename.empty())
1840 dialog->set_filename(prev_path);
1841 else if (is_absolute_path(filename))
1842 dialog->set_filename(filename);
1844 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1846 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1847 filename = dialog->get_filename();
1848 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1849 _preferences.set_value(preference, dirname(filename));
1863 GtkWidget *fileselection;
1864 fileselection = gtk_file_selection_new(title.c_str());
1867 if(basename(filename)==filename)
1869 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1872 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1874 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1876 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1877 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1879 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1880 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1882 gtk_widget_show(fileselection);
1890 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1891 _preferences.set_value(preference,dirname(filename));
1895 gtk_widget_destroy(fileselection);
1898 gtk_widget_destroy(fileselection);
1905 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1907 info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1909 #if USE_WIN32_FILE_DIALOGS
1910 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1912 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1913 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1914 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1916 ofn.lStructSize=sizeof(OPENFILENAME);
1917 ofn.hwndOwner = hWnd;
1918 ofn.hInstance = hInstance;
1919 ofn.lpstrFilter = szFilter;
1920 // ofn.lpstrCustomFilter=NULL;
1921 // ofn.nMaxCustFilter=0;
1922 // ofn.nFilterIndex=0;
1923 // ofn.lpstrFile=NULL;
1924 ofn.nMaxFile=MAX_PATH;
1925 // ofn.lpstrFileTitle=NULL;
1926 // ofn.lpstrInitialDir=NULL;
1927 // ofn.lpstrTitle=NULL;
1928 ofn.Flags=OFN_OVERWRITEPROMPT;
1929 // ofn.nFileOffset=0;
1930 // ofn.nFileExtension=0;
1931 ofn.lpstrDefExt=TEXT("sif");
1932 // ofn.lCustData = 0l;
1934 // ofn.lpTemplateName=NULL;
1936 CHAR szFilename[MAX_PATH];
1938 strcpy(szFilename,filename.c_str());
1939 strcpy(szTitle,title.c_str());
1941 ofn.lpstrFile=szFilename;
1942 ofn.lpstrFileTitle=szTitle;
1944 if(GetSaveFileName(&ofn))
1946 filename=szFilename;
1947 _preferences.set_value(preference,dirname(filename));
1952 synfig::String prev_path;
1954 if(!_preferences.get_value(preference, prev_path))
1957 prev_path = absolute_path(prev_path);
1959 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1961 dialog->set_current_folder(prev_path);
1962 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1963 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1965 Widget_Enum *file_type_enum = 0;
1966 if (preference == ANIMATION_DIR_PREFERENCE)
1968 file_type_enum = manage(new Widget_Enum());
1969 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
1970 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
1971 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
1972 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
1973 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
1974 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
1976 Gtk::HBox *hbox = manage(new Gtk::HBox);
1977 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
1978 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
1981 dialog->set_extra_widget(*hbox);
1984 if (filename.empty())
1985 dialog->set_filename(prev_path);
1988 std::string full_path;
1989 if (is_absolute_path(filename))
1990 full_path = filename;
1992 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1994 // select the file if it exists
1995 dialog->set_filename(full_path);
1997 // if the file doesn't exist, put its name into the filename box
1999 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2000 dialog->set_current_name(basename(filename));
2003 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2004 if (preference == ANIMATION_DIR_PREFERENCE)
2005 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2006 filename = dialog->get_filename();
2007 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2008 _preferences.set_value(preference, dirname(filename));
2019 App::dialog_error_blocking(const std::string &title, const std::string &message)
2021 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2022 dialog.set_title(title);
2028 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2030 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2031 dialog.set_title(title);
2037 App::dialog_yes_no(const std::string &title, const std::string &message)
2042 true // use_separator
2044 Gtk::Label label(message);
2047 dialog.get_vbox()->pack_start(label);
2048 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2049 dialog.add_button(Gtk::StockID("gtk-no"),0);
2051 return dialog.run();
2055 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2060 true // use_separator
2062 Gtk::Label label(message);
2065 dialog.get_vbox()->pack_start(label);
2066 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2067 dialog.add_button(Gtk::StockID("gtk-no"),0);
2068 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2070 return dialog.run();
2074 App::dialog_not_implemented()
2076 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2077 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2082 try_open_url(const std::string &url)
2085 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2087 std::vector<std::string> command_line;
2088 std::vector<std::string> browsers;
2089 browsers.reserve(23);
2091 // Browser wrapper scripts
2092 #ifdef USE_OPEN_FOR_URLS
2093 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2095 browsers.push_back("xdg-open"); // XDG wrapper
2096 browsers.push_back("sensible-browser"); // Debian wrapper
2097 browsers.push_back("gnome-open"); // GNOME wrapper
2098 browsers.push_back("kfmclient"); // KDE wrapper
2099 browsers.push_back("exo-open"); // XFCE wrapper
2101 // Alternatives system
2102 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2103 browsers.push_back("x-www-browser"); // Debian GUI alternative
2105 // Individual browsers
2106 browsers.push_back("firefox");
2107 browsers.push_back("epiphany-browser");
2108 browsers.push_back("epiphany");
2109 browsers.push_back("konqueror");
2110 browsers.push_back("iceweasel");
2111 browsers.push_back("mozilla");
2112 browsers.push_back("netscape");
2113 browsers.push_back("icecat");
2114 browsers.push_back("galeon");
2115 browsers.push_back("midori");
2116 browsers.push_back("safari");
2117 browsers.push_back("opera");
2118 browsers.push_back("amaya");
2119 browsers.push_back("netsurf");
2120 browsers.push_back("dillo");
2122 // Try the user-specified browser first
2123 command_line.push_back(App::browser_command);
2124 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2125 command_line.push_back(url);
2127 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2128 catch( Glib::SpawnError& exception ){
2130 while ( !browsers.empty() )
2132 // Skip the browser if we already tried it
2133 if( browsers[0] == App::browser_command )
2136 // Construct the command line
2137 command_line.clear();
2138 command_line.push_back(browsers[0]);
2139 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2140 command_line.push_back(url);
2142 // Remove the browser from the list
2143 browsers.erase(browsers.begin());
2145 // Try to spawn the browser
2146 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2147 // Failed, move on to the next one
2148 catch(Glib::SpawnError& exception){ continue; }
2149 return true; // No exception means we succeeded!
2160 if (!try_open_url("http://synfig.org/Documentation"))
2162 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2163 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2164 dialog.set_title(_("Help"));
2170 App::open_url(const std::string &url)
2172 if(!try_open_url(url))
2174 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2175 dialog.set_secondary_text(url);
2176 dialog.set_title(_("No browser found"));
2182 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2187 true // use_separator
2189 Gtk::Label label(message);
2191 dialog.get_vbox()->pack_start(label);
2194 entry.set_text(text);
2196 entry.set_activates_default(true);
2197 dialog.get_vbox()->pack_start(entry);
2199 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2200 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2201 dialog.set_default_response(Gtk::RESPONSE_OK);
2202 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2205 if(dialog.run()!=Gtk::RESPONSE_OK)
2208 text=entry.get_text();
2217 App::open(std::string filename)
2219 return open_as(filename,filename);
2222 // this is called from autorecover.cpp:
2223 // App::open_as(get_shadow_file_name(filename),filename)
2224 // other than that, 'filename' and 'as' are the same
2226 App::open_as(std::string filename,std::string as)
2229 char long_name[1024];
2230 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2231 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2232 // don't use it if that's the case
2233 if (long_name[0] != '\0')
2239 OneMoment one_moment;
2241 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
2242 if(canvas && get_instance(canvas))
2244 get_instance(canvas)->find_canvas_view(canvas)->present();
2245 info("%s is already open", filename.c_str());
2246 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2251 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2253 if (as.find(DEFAULT_FILENAME_PREFIX) != 0)
2254 add_recent_file(as);
2256 handle<Instance> instance(Instance::create(canvas));
2259 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2261 set_recent_file_window_size(instance);
2265 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)")))
2266 instance->dialog_cvs_update();
2271 dialog_error_blocking(_("Error"), x);
2276 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2287 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2289 String file_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2290 canvas->set_name(file_name);
2291 file_name += ".sifz";
2293 canvas->rend_desc().set_frame_rate(24.0);
2294 canvas->rend_desc().set_time_start(0.0);
2295 canvas->rend_desc().set_time_end(5.0);
2296 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2297 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2298 canvas->rend_desc().set_tl(Vector(-4,2.25));
2299 canvas->rend_desc().set_br(Vector(4,-2.25));
2300 canvas->rend_desc().set_w(480);
2301 canvas->rend_desc().set_h(270);
2302 canvas->rend_desc().set_antialias(1);
2303 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2304 canvas->set_file_name(file_name);
2306 handle<Instance> instance = Instance::create(canvas);
2308 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2309 instance->find_canvas_view(canvas)->canvas_properties.present();
2313 App::dialog_open(string filename)
2315 if (filename.empty())
2318 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2320 // If the filename still has wildcards, then we should
2321 // continue looking for the file we want
2322 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2328 get_ui_interface()->error(_("Unable to open file"));
2333 App::set_selected_instance(etl::loose_handle<Instance> instance)
2335 /* if(get_selected_instance()==instance)
2337 selected_instance=instance;
2338 signal_instance_selected()(instance);
2344 selected_instance=instance;
2345 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2349 instance->focus(instance->get_canvas());
2352 set_selected_canvas_view(0);
2354 signal_instance_selected()(instance);
2358 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2360 selected_canvas_view=canvas_view;
2361 signal_canvas_view_focus()(selected_canvas_view);
2364 selected_instance=canvas_view->get_instance();
2365 signal_instance_selected()(canvas_view->get_instance());
2368 if(get_selected_canvas_view()==canvas_view)
2370 signal_canvas_view_focus()(selected_canvas_view);
2371 signal_instance_selected()(canvas_view->get_instance());
2374 selected_canvas_view=canvas_view;
2375 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2376 set_selected_instance(canvas_view->get_instance());
2377 signal_canvas_view_focus()(selected_canvas_view);
2381 etl::loose_handle<Instance>
2382 App::get_instance(etl::handle<synfig::Canvas> canvas)
2384 if(!canvas) return 0;
2385 canvas=canvas->get_root();
2387 std::list<etl::handle<Instance> >::iterator iter;
2388 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2390 if((*iter)->get_canvas()==canvas)
2406 if(selected_instance)
2407 selected_instance->undo();
2413 if(selected_instance)
2414 selected_instance->redo();
2418 studio::App::get_base_path()
2420 return app_base_path_;