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_width.h"
93 #include "state_rotate.h"
94 #include "state_zoom.h"
96 #include "devicetracker.h"
97 #include "dialog_tooloptions.h"
98 #include "widget_enum.h"
100 #include "autorecover.h"
102 #include <synfigapp/settings.h>
103 #include "dock_history.h"
104 #include "dock_canvases.h"
105 #include "dock_keyframes.h"
106 #include "dock_layers.h"
107 #include "dock_params.h"
108 #include "dock_metadata.h"
109 #include "dock_children.h"
110 #include "dock_info.h"
111 #include "dock_navigator.h"
112 #include "dock_layergroups.h"
113 #include "dock_timetrack.h"
114 #include "dock_curves.h"
116 #include "mod_palette/mod_palette.h"
117 #include "mod_mirror/mod_mirror.h"
119 #include <sys/stat.h>
125 #include "statemanager.h"
131 #include <gtkmm/accelmap.h>
132 #include <gtkmm/filechooser.h>
133 #include <gtkmm/filechooserdialog.h>
139 /* === U S I N G =========================================================== */
143 using namespace synfig;
144 using namespace studio;
146 /* === M A C R O S ========================================================= */
148 #ifndef SYNFIG_USER_APP_DIR
150 #define SYNFIG_USER_APP_DIR "Library/Synfig"
151 #elif defined(_WIN32)
152 #define SYNFIG_USER_APP_DIR "Synfig"
154 #define SYNFIG_USER_APP_DIR ".synfig"
159 #define DPM2DPI(x) (float(x)/39.3700787402f)
160 #define DPI2DPM(x) (float(x)*39.3700787402f)
166 # define IMAGE_DIR "share\\pixmaps"
171 # define IMAGE_DIR "/usr/local/share/pixmaps"
175 # define IMAGE_EXT "tif"
178 #include <synfigapp/main.h>
180 /* === S I G N A L S ======================================================= */
182 static sigc::signal<void> signal_present_all_;
184 App::signal_present_all() { return signal_present_all_; }
186 static sigc::signal<void> signal_recent_files_changed_;
188 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
190 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
191 sigc::signal<void,etl::loose_handle<CanvasView> >&
192 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
194 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
195 sigc::signal<void,etl::handle<Instance> >&
196 App::signal_instance_selected() { return signal_instance_selected_; }
198 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
199 sigc::signal<void,etl::handle<Instance> >&
200 App::signal_instance_created() { return signal_instance_created_; }
202 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
203 sigc::signal<void,etl::handle<Instance> >&
204 App::signal_instance_deleted() { return signal_instance_deleted_; }
206 /* === G L O B A L S ======================================================= */
208 static std::list<std::string> recent_files;
209 const std::list<std::string>& App::get_recent_files() { return recent_files; }
211 static std::list<std::string> recent_files_window_size;
213 int App::Busy::count;
214 bool App::shutdown_in_progress;
216 synfig::Gamma App::gamma;
218 Glib::RefPtr<studio::UIManager> App::ui_manager_;
220 synfig::Distance::System App::distance_system;
222 studio::Dialog_Setup* App::dialog_setup;
224 etl::handle< studio::ModPalette > mod_palette_;
225 //studio::Dialog_Palette* App::dialog_palette;
227 std::list<etl::handle<Instance> > App::instance_list;
229 static etl::handle<synfigapp::UIInterface> ui_interface_;
230 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
232 etl::handle<Instance> App::selected_instance;
233 etl::handle<CanvasView> App::selected_canvas_view;
235 studio::About *studio::App::about=NULL;
237 studio::Toolbox *studio::App::toolbox=NULL;
239 studio::AutoRecover *studio::App::auto_recover=NULL;
241 studio::IPC *ipc=NULL;
243 studio::DockManager* studio::App::dock_manager=0;
245 studio::DeviceTracker* studio::App::device_tracker=0;
247 studio::Dialog_Gradient* studio::App::dialog_gradient;
249 studio::Dialog_Color* studio::App::dialog_color;
251 Gtk::InputDialog* studio::App::dialog_input;
253 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
255 studio::Dock_History* dock_history;
256 studio::Dock_Canvases* dock_canvases;
257 studio::Dock_Keyframes* dock_keyframes;
258 studio::Dock_Layers* dock_layers;
259 studio::Dock_Params* dock_params;
260 studio::Dock_MetaData* dock_meta_data;
261 studio::Dock_Children* dock_children;
262 studio::Dock_Info* dock_info;
263 studio::Dock_LayerGroups* dock_layer_groups;
264 studio::Dock_Navigator* dock_navigator;
265 studio::Dock_Timetrack* dock_timetrack;
266 studio::Dock_Curves* dock_curves;
268 std::list< etl::handle< studio::Module > > module_list_;
270 bool studio::App::use_colorspace_gamma=true;
271 #ifdef SINGLE_THREADED
272 bool studio::App::single_threaded=false;
274 bool studio::App::restrict_radius_ducks=false;
275 #ifdef USE_OPEN_FOR_URLS
276 String studio::App::browser_command("open"); // MacOS only
278 String studio::App::browser_command("xdg-open"); // Linux XDG standard
281 static int max_recent_files_=25;
282 int studio::App::get_max_recent_files() { return max_recent_files_; }
283 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
285 static synfig::String app_base_path_;
290 really_delete_widget(Gtk::Widget *widget)
292 // synfig::info("really delete %p", (void*)widget);
297 // nasty workaround - when we've finished with a popup menu, we want to delete it
298 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
299 // so schedule the real delete to happen in 50ms, giving the action a chance to run
301 delete_widget(Gtk::Widget *widget)
303 // synfig::info("delete %p", (void*)widget);
304 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
307 }; // END of namespace studio
308 studio::StateManager* state_manager;
313 class GlobalUIInterface : public synfigapp::UIInterface
317 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
322 true // use_separator
324 Gtk::Label label(message);
327 dialog.get_vbox()->pack_start(label);
328 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
329 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
331 dialog.set_default_response(dflt);
333 return (Response)dialog.run();
335 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
340 true // use_separator
342 Gtk::Label label(message);
345 dialog.get_vbox()->pack_start(label);
346 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
347 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
348 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
350 dialog.set_default_response(dflt);
352 return (Response)dialog.run();
354 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
359 true // use_separator
361 Gtk::Label label(message);
364 dialog.get_vbox()->pack_start(label);
365 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
366 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
368 dialog.set_default_response(dflt);
370 return (Response)dialog.run();
374 task(const std::string &task)
376 std::cerr<<task<<std::endl;
377 while(studio::App::events_pending())studio::App::iteration(false);
382 error(const std::string &err)
384 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
391 warning(const std::string &err)
393 std::cerr<<"warning: "<<err<<std::endl;
394 while(studio::App::events_pending())studio::App::iteration(false);
399 amount_complete(int /*current*/, int /*total*/)
401 while(studio::App::events_pending())studio::App::iteration(false);
406 /* === P R O C E D U R E S ================================================= */
410 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
412 action_group_list.push_back(action_group);
413 Gtk::UIManager::insert_action_group(action_group, pos);
417 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
419 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
420 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
421 if(*iter==action_group)
423 action_group_list.erase(iter);
424 Gtk::UIManager::remove_action_group(action_group);
427 synfig::error("Unable to find action group");
431 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
433 ui_manager->insert_action_group(group,0);
435 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
436 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
438 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
440 if(*iter && (*iter)->get_name()!="menus")
442 synfig::info("Removing action group "+(*iter)->get_name());
443 ui_manager->remove_action_group(*iter);
446 ui_manager->insert_action_group(group,0);
448 for(;!prev_groups.empty();prev_groups.pop_front())
450 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
451 ui_manager->insert_action_group(prev_groups.front(),1);
455 class Preferences : public synfigapp::Settings
458 virtual bool get_value(const synfig::String& key, synfig::String& value)const
462 value=strprintf("%f %f %f %f",
463 App::gamma.get_gamma_r(),
464 App::gamma.get_gamma_g(),
465 App::gamma.get_gamma_b(),
466 App::gamma.get_black_level()
470 if(key=="time_format")
472 value=strprintf("%i",App::get_time_format());
475 if(key=="file_history.size")
477 value=strprintf("%i",App::get_max_recent_files());
480 if(key=="use_colorspace_gamma")
482 value=strprintf("%i",(int)App::use_colorspace_gamma);
485 if(key=="distance_system")
487 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
490 #ifdef SINGLE_THREADED
491 if(key=="single_threaded")
493 value=strprintf("%i",(int)App::single_threaded);
497 if(key=="auto_recover_backup_interval")
499 value=strprintf("%i",App::auto_recover->get_timeout());
502 if(key=="restrict_radius_ducks")
504 value=strprintf("%i",(int)App::restrict_radius_ducks);
507 if(key=="browser_command")
509 value=App::browser_command;
513 return synfigapp::Settings::get_value(key,value);
516 virtual bool set_value(const synfig::String& key,const synfig::String& value)
522 strscanf(value,"%f %f %f %f",
529 App::gamma.set_all(r,g,b,blk);
533 if(key=="time_format")
535 int i(atoi(value.c_str()));
536 App::set_time_format(static_cast<synfig::Time::Format>(i));
539 if(key=="auto_recover_backup_interval")
541 int i(atoi(value.c_str()));
542 App::auto_recover->set_timeout(i);
545 if(key=="file_history.size")
547 int i(atoi(value.c_str()));
548 App::set_max_recent_files(i);
551 if(key=="use_colorspace_gamma")
553 int i(atoi(value.c_str()));
554 App::use_colorspace_gamma=i;
557 if(key=="distance_system")
559 App::distance_system=Distance::ident_system(value);;
562 #ifdef SINGLE_THREADED
563 if(key=="single_threaded")
565 int i(atoi(value.c_str()));
566 App::single_threaded=i;
570 if(key=="restrict_radius_ducks")
572 int i(atoi(value.c_str()));
573 App::restrict_radius_ducks=i;
576 if(key=="browser_command")
578 App::browser_command=value;
582 return synfigapp::Settings::set_value(key,value);
585 virtual KeyList get_key_list()const
587 KeyList ret(synfigapp::Settings::get_key_list());
588 ret.push_back("gamma");
589 ret.push_back("time_format");
590 ret.push_back("distance_system");
591 ret.push_back("file_history.size");
592 ret.push_back("use_colorspace_gamma");
593 #ifdef SINGLE_THREADED
594 ret.push_back("single_threaded");
596 ret.push_back("auto_recover_backup_interval");
597 ret.push_back("restrict_radius_ducks");
598 ret.push_back("browser_command");
603 static ::Preferences _preferences;
608 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
610 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
612 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
614 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
615 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
616 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
617 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
618 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
619 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
620 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
621 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
622 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
623 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
624 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
625 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
626 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
628 // Add the synfigapp actions...
629 synfigapp::Action::Book::iterator iter;
630 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
632 actions_action_group->add(Gtk::Action::create(
633 "action-"+iter->second.name,
634 get_action_stock_id(iter->second),
635 iter->second.local_name,iter->second.local_name
639 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
640 #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); }
641 #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); }
643 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
644 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
645 DEFINE_ACTION("new", Gtk::Stock::NEW);
646 DEFINE_ACTION("open", Gtk::Stock::OPEN);
647 DEFINE_ACTION("save", Gtk::Stock::SAVE);
648 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
649 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
650 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
651 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
652 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
653 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
654 DEFINE_ACTION("import", _("Import"));
655 DEFINE_ACTION("render", _("Render"));
656 DEFINE_ACTION("preview", _("Preview"));
657 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
658 DEFINE_ACTION("sound", _("Sound File"));
659 DEFINE_ACTION("options", _("Options"));
660 DEFINE_ACTION("close", _("Close View"));
661 DEFINE_ACTION("close-document", _("Close Document"));
662 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
665 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
666 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
667 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
668 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
669 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
670 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
671 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
672 DEFINE_ACTION("properties", _("Properties"));
674 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
675 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
676 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
677 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
678 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
679 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
680 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
681 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
682 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
683 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
684 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
685 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
686 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
687 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
688 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
689 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
690 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
691 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
692 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
693 DEFINE_ACTION("play", _("Play"));
694 // DEFINE_ACTION("pause", _("Pause"));
695 DEFINE_ACTION("stop", _("Stop"));
696 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
697 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
698 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
699 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
700 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
701 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
702 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
703 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
704 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
705 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
706 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
707 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
708 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
709 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
710 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
711 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
712 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
713 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
714 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
715 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
716 DEFINE_ACTION("seek-end", _("Seek to End"));
718 DEFINE_ACTION("action-group_add", _("Add group"));
720 DEFINE_ACTION("canvas-new", _("New Canvas"));
722 DEFINE_ACTION("amount-inc", _("Increase Amount"));
723 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
728 // Set up synfigapp actions
730 synfigapp::Action::Book::iterator iter;
732 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
734 Gtk::StockID stock_id;
736 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
738 //Gtk::Image* image(manage(new Gtk::Image()));
739 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
740 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
741 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
742 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
743 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
744 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
745 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
746 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
747 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
748 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
750 actions_action_group->add(Gtk::Action::create(
751 "action-"+iter->second.name,
753 iter->second.local_name,iter->second.local_name
761 Glib::ustring ui_info =
763 " <popup name='menu-toolbox' action='menu-toolbox'>"
764 " <menu action='menu-file'>"
767 " <popup name='menu-main' action='menu-main'>"
768 " <menu action='menu-file'>"
769 " <menuitem action='new' />"
770 " <menuitem action='open' />"
771 " <menuitem action='save' />"
772 " <menuitem action='save-as' />"
773 " <menuitem action='revert' />"
774 " <separator name='bleh01'/>"
775 " <menuitem action='cvs-add' />"
776 " <menuitem action='cvs-update' />"
777 " <menuitem action='cvs-commit' />"
778 " <menuitem action='cvs-revert' />"
779 " <separator name='bleh02'/>"
780 " <menuitem action='import' />"
781 " <separator name='bleh03'/>"
782 " <menuitem action='render' />"
783 " <menuitem action='preview' />"
784 " <menuitem action='sound' />"
785 " <separator name='bleh04'/>"
786 " <menuitem action='options' />"
787 " <menuitem action='close' />"
788 " <menuitem action='close-document' />"
789 " <menuitem action='quit' />"
791 " <menu action='menu-edit'>"
792 " <menuitem action='undo'/>"
793 " <menuitem action='redo'/>"
794 " <separator name='bleh05'/>"
795 " <menuitem action='cut'/>"
796 " <menuitem action='copy'/>"
797 " <menuitem action='paste'/>"
798 " <separator name='bleh06'/>"
799 " <menuitem action='select-all-ducks'/>"
800 " <menuitem action='unselect-all-layers'/>"
801 " <separator name='bleh07'/>"
802 " <menuitem action='properties'/>"
804 " <menu action='menu-view'>"
805 " <menu action='menu-duck-mask'>"
806 " <menuitem action='mask-position-ducks' />"
807 " <menuitem action='mask-vertex-ducks' />"
808 " <menuitem action='mask-tangent-ducks' />"
809 " <menuitem action='mask-radius-ducks' />"
810 " <menuitem action='mask-width-ducks' />"
811 " <menuitem action='mask-angle-ducks' />"
813 " <menu action='menu-preview-quality'>"
814 " <menuitem action='quality-00' />"
815 " <menuitem action='quality-01' />"
816 " <menuitem action='quality-02' />"
817 " <menuitem action='quality-03' />"
818 " <menuitem action='quality-04' />"
819 " <menuitem action='quality-05' />"
820 " <menuitem action='quality-06' />"
821 " <menuitem action='quality-07' />"
822 " <menuitem action='quality-08' />"
823 " <menuitem action='quality-09' />"
824 " <menuitem action='quality-10' />"
826 " <menu action='menu-lowres-pixel'>"
827 " <menuitem action='decrease-low-res-pixel-size'/>"
828 " <menuitem action='increase-low-res-pixel-size'/>"
829 " <separator name='pixel-size-separator'/>"
832 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
833 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
837 " <separator name='bleh08'/>"
838 " <menuitem action='play'/>"
839 //" <menuitem action='pause'/>"
840 " <menuitem action='stop'/>"
841 " <menuitem action='dialog-flipbook'/>"
842 " <separator name='bleh09'/>"
843 " <menuitem action='toggle-grid-show'/>"
844 " <menuitem action='toggle-grid-snap'/>"
845 " <menuitem action='toggle-guide-show'/>"
846 " <menuitem action='toggle-low-res'/>"
847 " <menuitem action='toggle-onion-skin'/>"
848 " <separator name='bleh10'/>"
849 " <menuitem action='canvas-zoom-in'/>"
850 " <menuitem action='canvas-zoom-out'/>"
851 " <menuitem action='canvas-zoom-fit'/>"
852 " <menuitem action='canvas-zoom-100'/>"
853 " <separator name='bleh11'/>"
854 " <menuitem action='time-zoom-in'/>"
855 " <menuitem action='time-zoom-out'/>"
856 " <separator name='bleh12'/>"
857 " <menuitem action='jump-next-keyframe'/>"
858 " <menuitem action='jump-prev-keyframe'/>"
859 " <menuitem action='seek-next-frame'/>"
860 " <menuitem action='seek-prev-frame'/>"
861 " <menuitem action='seek-next-second'/>"
862 " <menuitem action='seek-prev-second'/>"
863 " <menuitem action='seek-begin'/>"
864 " <menuitem action='seek-end'/>"
866 " <menu action='menu-canvas'>"
867 " <menuitem action='canvas-new'/>"
869 " <menu name='menu-state' action='menu-state'>"
871 " <menu action='menu-group'>"
872 " <menuitem action='action-group_add'/>"
874 " <menu action='menu-layer'>"
875 //" <menuitem action='cut'/>"
876 //" <menuitem action='copy'/>"
877 //" <menuitem action='paste'/>"
878 //" <separator name='bleh06'/>"
879 " <menu action='menu-layer-new'></menu>"
880 " <menuitem action='amount-inc'/>"
881 " <menuitem action='amount-dec'/>"
883 " <menu action='menu-keyframe'>"
884 " <menuitem action='keyframe-properties'/>"
891 " <menubar name='MenuBar'>"
892 " <menu action='MenuFile'>"
893 " <menuitem action='New'/>"
894 " <menuitem action='Open'/>"
896 " <menuitem action='Quit'/>"
898 " <menu action='MenuEdit'>"
899 " <menuitem action='Cut'/>"
900 " <menuitem action='Copy'/>"
901 " <menuitem action='Paste'/>"
904 " <toolbar name='ToolBar'>"
905 " <toolitem action='Open'/>"
906 " <toolitem action='Quit'/>"
912 actions_action_group->set_sensitive(false);
913 App::ui_manager()->set_add_tearoffs(true);
914 App::ui_manager()->insert_action_group(menus_action_group,1);
915 App::ui_manager()->insert_action_group(actions_action_group,1);
916 App::ui_manager()->add_ui_from_string(ui_info);
918 //App::ui_manager()->get_accel_group()->unlock();
920 catch(const Glib::Error& ex)
922 synfig::error("building menus and toolbars failed: " + ex.what());
925 // Add default keyboard accelerators
926 #define ACCEL(path,accel) \
928 Gtk::AccelKey accel_key(accel,path); \
929 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
932 #define ACCEL2(accel) \
934 Gtk::AccelKey accel_key(accel); \
935 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
938 ACCEL("<Actions>//select-all-ducks","<Control>a");
939 ACCEL("<Actions>//unselect-all-layers","<Control>d");
940 ACCEL("<Actions>//render","F9");
941 ACCEL("<Actions>//preview","F11");
942 ACCEL("<Actions>//properties","F8");
943 ACCEL("<Actions>//options","F12");
944 ACCEL("<Actions>//import","<control>i");
945 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
946 ACCEL("<Actions>//toggle-grid-show","<Control>g");
947 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
948 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
949 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
950 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
951 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
952 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
953 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
954 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
956 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
957 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
959 ACCEL("<Actions>//quality-01","<Control>1");
960 ACCEL("<Actions>//quality-02","<Control>2");
961 ACCEL("<Actions>//quality-03","<Control>3");
962 ACCEL("<Actions>//quality-04","<Control>4");
963 ACCEL("<Actions>//quality-05","<Control>5");
964 ACCEL("<Actions>//quality-06","<Control>6");
965 ACCEL("<Actions>//quality-07","<Control>7");
966 ACCEL("<Actions>//quality-08","<Control>8");
967 ACCEL("<Actions>//quality-09","<Control>9");
968 ACCEL("<Actions>//quality-10","<Control>0");
969 ACCEL("<Actions>//undo","<Control>z");
970 ACCEL("<Actions>//redo","<Control>r");
971 ACCEL("<Actions>//action-layer_remove","Delete");
973 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
974 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
975 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
976 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
977 ACCEL("<Actions>//time-zoom-in","+");
978 ACCEL("<Actions>//time-zoom-out","_");
980 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
981 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
983 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
984 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
986 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
987 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
988 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
989 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
990 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
991 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
992 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
993 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
994 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
995 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
996 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
997 ACCEL("<Actions>//play", "<Control>p");
998 ACCEL("<Actions>//seek-begin","Home");
999 ACCEL("<Actions>//seek-end","End");
1001 ACCEL("<Actions>//state-normal", "<Mod1>a");
1002 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1003 ACCEL("<Actions>//state-scale", "<Mod1>d");
1004 ACCEL("<Actions>//state-rotate", "<Mod1>s");
1006 ACCEL("<Actions>//state-bline", "<Mod1>b");
1007 ACCEL("<Actions>//state-circle", "<Mod1>c");
1008 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1009 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1011 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1012 ACCEL("<Actions>//state-fill", "<Mod1>f");
1013 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1014 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1016 ACCEL("<Actions>//state-draw", "<Mod1>w");
1017 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1018 ACCEL("<Actions>//state-width", "<Mod1>t");
1019 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1021 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1027 #define mkdir(x,y) mkdir(x)
1030 /* === M E T H O D S ======================================================= */
1032 App::App(int *argc, char ***argv):
1033 Gtk::Main(argc,argv),
1034 IconController(etl::dirname((*argv)[0]))
1036 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1039 ui_interface_=new GlobalUIInterface();
1043 // don't call thread_init() if threads are already initialized
1044 // on some machines bonobo_init() initialized threads before we get here
1045 if (!g_thread_supported())
1046 Glib::thread_init();
1048 distance_system=Distance::SYSTEM_UNITS;
1050 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1053 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1057 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1063 if(!SYNFIG_CHECK_VERSION())
1065 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1066 dialog_error_blocking("Synfig Studio",
1067 "This copy of Synfig Studio was compiled against a\n"
1068 "different version of libsynfig than what is currently\n"
1069 "installed. Synfig Studio will now abort. Try downloading\n"
1070 "the latest version from the Synfig website at\n"
1071 "http://synfig.org/Download"
1075 Glib::set_application_name(_("Synfig Studio"));
1077 Splash splash_screen;
1078 splash_screen.show();
1080 shutdown_in_progress=false;
1081 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1082 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1084 // Initialize the Synfig library
1085 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1088 get_ui_interface()->error(_("Failed to initialize synfig!"));
1092 // add the preferences to the settings
1093 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1097 studio_init_cb.task(_("Init UI Manager..."));
1098 App::ui_manager_=studio::UIManager::create();
1101 studio_init_cb.task(_("Init Dock Manager..."));
1102 dock_manager=new studio::DockManager();
1104 studio_init_cb.task(_("Init State Manager..."));
1105 state_manager=new StateManager();
1107 studio_init_cb.task(_("Init Toolbox..."));
1108 toolbox=new studio::Toolbox();
1110 studio_init_cb.task(_("Init About Dialog..."));
1111 about=new studio::About();
1113 studio_init_cb.task(_("Init Tool Options..."));
1114 dialog_tool_options=new studio::Dialog_ToolOptions();
1115 dock_manager->register_dockable(*dialog_tool_options);
1117 studio_init_cb.task(_("Init History..."));
1118 dock_history=new studio::Dock_History();
1119 dock_manager->register_dockable(*dock_history);
1121 studio_init_cb.task(_("Init Canvases..."));
1122 dock_canvases=new studio::Dock_Canvases();
1123 dock_manager->register_dockable(*dock_canvases);
1125 studio_init_cb.task(_("Init Keyframes..."));
1126 dock_keyframes=new studio::Dock_Keyframes();
1127 dock_manager->register_dockable(*dock_keyframes);
1129 studio_init_cb.task(_("Init Layers..."));
1130 dock_layers=new studio::Dock_Layers();
1131 dock_manager->register_dockable(*dock_layers);
1133 studio_init_cb.task(_("Init Params..."));
1134 dock_params=new studio::Dock_Params();
1135 dock_manager->register_dockable(*dock_params);
1137 studio_init_cb.task(_("Init MetaData..."));
1138 dock_meta_data=new studio::Dock_MetaData();
1139 dock_manager->register_dockable(*dock_meta_data);
1141 studio_init_cb.task(_("Init Children..."));
1142 dock_children=new studio::Dock_Children();
1143 dock_manager->register_dockable(*dock_children);
1145 studio_init_cb.task(_("Init Info..."));
1146 dock_info = new studio::Dock_Info();
1147 dock_manager->register_dockable(*dock_info);
1149 studio_init_cb.task(_("Init Navigator..."));
1150 dock_navigator = new studio::Dock_Navigator();
1151 dock_manager->register_dockable(*dock_navigator);
1153 studio_init_cb.task(_("Init Timetrack..."));
1154 dock_timetrack = new studio::Dock_Timetrack();
1155 dock_manager->register_dockable(*dock_timetrack);
1157 studio_init_cb.task(_("Init Curve Editor..."));
1158 dock_curves = new studio::Dock_Curves();
1159 dock_manager->register_dockable(*dock_curves);
1161 studio_init_cb.task(_("Init Layer Groups..."));
1162 dock_layer_groups = new studio::Dock_LayerGroups();
1163 dock_manager->register_dockable(*dock_layer_groups);
1166 studio_init_cb.task(_("Init Color Dialog..."));
1167 dialog_color=new studio::Dialog_Color();
1169 studio_init_cb.task(_("Init Gradient Dialog..."));
1170 dialog_gradient=new studio::Dialog_Gradient();
1172 studio_init_cb.task(_("Init DeviceTracker..."));
1173 device_tracker=new studio::DeviceTracker();
1175 studio_init_cb.task(_("Init Tools..."));
1178 state_manager->add_state(&state_normal);
1179 state_manager->add_state(&state_smooth_move);
1180 state_manager->add_state(&state_scale);
1181 state_manager->add_state(&state_rotate);
1182 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1185 state_manager->add_state(&state_bline);
1186 state_manager->add_state(&state_circle);
1187 state_manager->add_state(&state_rectangle);
1188 state_manager->add_state(&state_gradient);
1189 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1192 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1193 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1194 state_manager->add_state(&state_fill);
1195 state_manager->add_state(&state_eyedrop);
1196 state_manager->add_state(&state_zoom);
1198 // Disabled by default - it doesn't work properly?
1199 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1201 studio_init_cb.task(_("Init ModPalette..."));
1202 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1204 studio_init_cb.task(_("Init Setup Dialog..."));
1205 dialog_setup=new studio::Dialog_Setup();
1207 studio_init_cb.task(_("Init Input Dialog..."));
1208 dialog_input=new Gtk::InputDialog();
1209 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1210 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1212 studio_init_cb.task(_("Init auto recovery..."));
1213 auto_recover=new AutoRecover();
1215 studio_init_cb.amount_complete(9250,10000);
1216 studio_init_cb.task(_("Loading Settings..."));
1218 studio_init_cb.task(_("Checking auto-recover..."));
1220 studio_init_cb.amount_complete(9900,10000);
1222 bool opened_any = false;
1223 if(auto_recover->recovery_needed())
1225 splash_screen.hide();
1226 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1227 _("Synfig Studio seems to have crashed\n"
1228 "before you could save all your files.\n"
1229 "Would you like to re-open those files\n"
1230 "and recover your unsaved changes?")) ==
1231 synfigapp::UIInterface::RESPONSE_YES)
1233 int number_recovered;
1234 if(!auto_recover->recover(number_recovered))
1235 if (number_recovered)
1236 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1238 get_ui_interface()->error(_("Unable to recover from previous crash"));
1240 get_ui_interface()->error(
1241 _("Synfig Studio has attempted to recover\n"
1242 "from a previous crash. The files that it has\n"
1243 "recovered are NOT YET SAVED. It would be a good\n"
1244 "idea to review them and save them now."));
1246 if (number_recovered)
1249 splash_screen.show();
1252 // Look for any files given on the command line,
1253 // and load them if found.
1254 for(;*argc>=1;(*argc)--)
1255 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1257 studio_init_cb.task(_("Loading files..."));
1258 splash_screen.hide();
1259 open((*argv)[*argc]);
1261 splash_screen.show();
1264 // if no file was specified to be opened, create a new document to help new users get started more easily
1265 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1268 studio_init_cb.task(_("Done."));
1269 studio_init_cb.amount_complete(10000,10000);
1275 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1279 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1283 StateManager* App::get_state_manager() { return state_manager; }
1287 shutdown_in_progress=true;
1291 synfigapp::Main::settings().remove_domain("pref");
1293 selected_instance=0;
1295 // Unload all of the modules
1296 for(;!module_list_.empty();module_list_.pop_back())
1299 delete state_manager;
1303 delete auto_recover;
1309 // studio::App::iteration(false);
1313 // studio::App::iteration(false);
1315 // studio::App::iteration(false);
1317 delete dialog_setup;
1319 delete dialog_gradient;
1321 delete dialog_color;
1323 delete dialog_input;
1325 delete dock_manager;
1327 instance_list.clear();
1329 // studio::App::iteration(false);
1333 App::get_user_app_directory()
1335 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1337 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1339 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1344 App::get_config_file(const synfig::String& file)
1346 return Glib::build_filename(get_user_app_directory(),file);
1349 #define SCALE_FACTOR (1280)
1350 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1352 App::set_recent_file_window_size(etl::handle<Instance> instance)
1354 int screen_w(Gdk::screen_width());
1355 int screen_h(Gdk::screen_height());
1357 const std::string &canvas_window_size = *recent_files_window_size.begin();
1359 if(canvas_window_size.empty())
1362 synfig::String::size_type current=0;
1363 bool seen_root(false), shown_non_root(false);
1365 while(current != synfig::String::npos)
1367 // find end of first field (canvas) or return
1368 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1369 if(separator == synfig::String::npos) break;
1372 synfig::Canvas::Handle canvas;
1374 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current));
1376 catch(Exception::IDNotFound) {
1377 // can't find the canvas; skip to the next canvas or return
1378 separator = canvas_window_size.find_first_of('\t', current);
1379 if(separator == synfig::String::npos) return;
1380 current = separator+1;
1384 if (canvas->is_root())
1387 shown_non_root = true;
1389 // check that we have the tab character the ends this canvas' data or return
1390 current = separator+1;
1391 separator = canvas_window_size.find_first_of('\t', current);
1392 if(separator == synfig::String::npos) return;
1395 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1397 current = separator+1;
1401 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1402 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1403 x=x*screen_w/SCALE_FACTOR;
1404 y=y*screen_h/SCALE_FACTOR;
1405 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1406 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1407 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1408 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1410 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1411 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1413 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1414 canvasview->move(x,y);
1415 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1416 canvasview->present();
1418 current = separator+1;
1421 if (shown_non_root && !seen_root)
1422 instance->find_canvas_view(instance->get_canvas())->hide();
1426 App::add_recent_file(const etl::handle<Instance> instance)
1428 int screen_w(Gdk::screen_width());
1429 int screen_h(Gdk::screen_height());
1431 std::string canvas_window_size;
1433 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1434 Instance::CanvasViewList::const_iterator iter;
1436 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1438 if( !((*iter)->is_visible()) )
1441 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1442 int x_pos, y_pos, x_size, y_size;
1443 (*iter)->get_position(x_pos,y_pos);
1444 (*iter)->get_size(x_size,y_size);
1446 canvas_window_size += strprintf("%s %d %d %d %d\t",
1447 canvas->get_relative_id(canvas->get_root()).c_str(),
1448 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1449 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1452 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1457 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1459 std::string filename(file_name);
1461 assert(!filename.empty());
1463 if(filename.empty())
1466 // Toss out any "hidden" files
1467 if(basename(filename)[0]=='.')
1470 // If we aren't an absolute path, turn ourselves into one
1471 if(!is_absolute_path(filename))
1472 filename=absolute_path(filename);
1474 std::string old_window_size;
1476 list<string>::iterator iter;
1477 list<string>::iterator iter_wsize;
1478 // Check to see if the file is already on the list.
1479 // If it is, then remove it from the list
1480 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1483 recent_files.erase(iter);
1484 old_window_size = *iter_wsize;
1485 recent_files_window_size.erase(iter_wsize);
1490 // Push the filename to the front of the list
1491 recent_files.push_front(filename);
1492 if(window_size.empty())
1493 recent_files_window_size.push_front(old_window_size);
1495 recent_files_window_size.push_front(window_size);
1497 // Clean out the files at the end of the list.
1498 while(recent_files.size()>(unsigned)get_max_recent_files())
1500 recent_files.pop_back();
1501 recent_files_window_size.pop_back();
1504 signal_recent_files_changed_();
1509 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1512 App::get_time_format()
1514 return _App_time_format;
1518 App::set_time_format(synfig::Time::Format x)
1525 App::save_settings()
1530 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1531 setlocale(LC_NUMERIC, "C");
1533 std::string filename=get_config_file("accelrc");
1534 Gtk::AccelMap::save(filename);
1537 std::string filename=get_config_file("recentfiles");
1539 std::ofstream file(filename.c_str());
1543 synfig::warning("Unable to save %s",filename.c_str());
1547 list<string>::reverse_iterator iter;
1549 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1553 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1555 std::ofstream file(filename.c_str());
1559 synfig::warning("Unable to save %s",filename.c_str());
1563 list<string>::reverse_iterator iter;
1565 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1569 std::string filename=get_config_file("settings");
1570 synfigapp::Main::settings().save_to_file(filename);
1571 setlocale(LC_NUMERIC,old_locale);
1575 synfig::warning("Caught exception when attempting to save settings.");
1580 App::load_settings()
1585 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1586 setlocale(LC_NUMERIC, "C");
1588 std::string filename=get_config_file("accelrc");
1589 Gtk::AccelMap::load(filename);
1592 bool window_size_broken = false;
1594 std::string filename=get_config_file("recentfiles");
1595 std::string filename_window_size=filename+std::string("_window_size");
1597 std::ifstream file(filename.c_str());
1598 std::ifstream file_window_size(filename_window_size.c_str());
1600 if(!file_window_size)
1601 window_size_broken = true;
1605 std::string recent_file;
1606 std::string recent_file_window_size;
1607 getline(file,recent_file);
1608 if(!window_size_broken)
1609 getline(file_window_size,recent_file_window_size);
1610 if(!recent_file.empty())
1612 if(!window_size_broken && !file_window_size)
1613 window_size_broken = true;
1614 if(!window_size_broken)
1615 add_recent_file(recent_file,recent_file_window_size);
1617 add_recent_file(recent_file);
1620 if(!window_size_broken && file_window_size)
1621 window_size_broken = true;
1623 if(window_size_broken)
1625 recent_files_window_size.clear();
1626 recent_files_window_size.resize(recent_files.size());
1629 std::string filename=get_config_file("settings");
1630 if(!synfigapp::Main::settings().load_from_file(filename))
1632 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1633 //if(!synfigapp::Main::settings().load_from_file(filename))
1635 gamma.set_gamma(1.0/2.2);
1636 reset_initial_window_configuration();
1639 setlocale(LC_NUMERIC,old_locale);
1643 synfig::warning("Caught exception when attempting to load settings.");
1648 App::reset_initial_window_configuration()
1650 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1651 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1652 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1653 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1654 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1655 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1656 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1657 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1658 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1659 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1660 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1661 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1662 #ifdef SINGLE_THREADED
1663 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1665 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1666 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1670 App::shutdown_request(GdkEventAny*)
1674 //return !shutdown_in_progress;
1680 if(shutdown_in_progress)return;
1683 get_ui_interface()->task(_("Quit Request"));
1686 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1690 std::list<etl::handle<Instance> >::iterator iter;
1691 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1693 if(!(*iter)->safe_close())
1697 if((*iter)->synfigapp::Instance::get_action_count())
1699 handle<synfigapp::UIInterface> uim;
1700 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1702 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1703 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1705 case synfigapp::UIInterface::RESPONSE_NO:
1707 case synfigapp::UIInterface::RESPONSE_YES:
1710 case synfigapp::UIInterface::RESPONSE_CANCEL:
1719 if((*iter)->synfigapp::Instance::is_modified())
1721 handle<synfigapp::UIInterface> uim;
1722 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1724 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() );
1725 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1727 case synfigapp::UIInterface::RESPONSE_NO:
1729 case synfigapp::UIInterface::RESPONSE_YES:
1730 (*iter)->dialog_cvs_commit();
1732 case synfigapp::UIInterface::RESPONSE_CANCEL:
1741 // This next line causes things to crash for some reason
1745 shutdown_in_progress=true;
1747 instance_list.clear();
1749 while(studio::App::events_pending())studio::App::iteration(false);
1752 auto_recover->normal_shutdown();
1754 get_ui_interface()->task(_("Quit Request sent"));
1760 dialog_setup->refresh();
1761 dialog_setup->show();
1764 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1765 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1768 //#define USE_WIN32_FILE_DIALOGS 1
1771 #ifdef USE_WIN32_FILE_DIALOGS
1772 static OPENFILENAME ofn={};
1776 #include <gdk/gdkwin32.h>
1780 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1782 info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1784 #ifdef USE_WIN32_FILE_DIALOGS
1785 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1787 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1788 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1789 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1791 ofn.lStructSize=sizeof(OPENFILENAME);
1792 ofn.hwndOwner = hWnd;
1793 ofn.hInstance = hInstance;
1794 ofn.lpstrFilter = szFilter;
1795 // ofn.lpstrCustomFilter=NULL;
1796 // ofn.nMaxCustFilter=0;
1797 // ofn.nFilterIndex=0;
1798 // ofn.lpstrFile=NULL;
1799 ofn.nMaxFile=MAX_PATH;
1800 // ofn.lpstrFileTitle=NULL;
1801 // ofn.lpstrInitialDir=NULL;
1802 // ofn.lpstrTitle=NULL;
1803 ofn.Flags=OFN_HIDEREADONLY;
1804 // ofn.nFileOffset=0;
1805 // ofn.nFileExtension=0;
1806 ofn.lpstrDefExt=TEXT("sif");
1807 // ofn.lCustData = 0l;
1809 // ofn.lpTemplateName=NULL;
1811 CHAR szFilename[MAX_PATH];
1813 strcpy(szFilename,filename.c_str());
1814 strcpy(szTitle,title.c_str());
1816 ofn.lpstrFile=szFilename;
1817 ofn.lpstrFileTitle=szTitle;
1819 if(GetOpenFileName(&ofn))
1821 filename=szFilename;
1827 synfig::String prev_path;
1829 if(!_preferences.get_value(preference, prev_path))
1832 prev_path = absolute_path(prev_path);
1834 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1836 dialog->set_current_folder(prev_path);
1837 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1838 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1840 if (filename.empty())
1841 dialog->set_filename(prev_path);
1842 else if (is_absolute_path(filename))
1843 dialog->set_filename(filename);
1845 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1847 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1848 filename = dialog->get_filename();
1849 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1850 _preferences.set_value(preference, dirname(filename));
1864 GtkWidget *fileselection;
1865 fileselection = gtk_file_selection_new(title.c_str());
1868 if(basename(filename)==filename)
1870 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1873 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1875 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1877 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1878 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1880 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1881 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1883 gtk_widget_show(fileselection);
1891 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1892 _preferences.set_value(preference,dirname(filename));
1896 gtk_widget_destroy(fileselection);
1899 gtk_widget_destroy(fileselection);
1906 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1908 info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1910 #if USE_WIN32_FILE_DIALOGS
1911 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1913 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1914 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1915 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1917 ofn.lStructSize=sizeof(OPENFILENAME);
1918 ofn.hwndOwner = hWnd;
1919 ofn.hInstance = hInstance;
1920 ofn.lpstrFilter = szFilter;
1921 // ofn.lpstrCustomFilter=NULL;
1922 // ofn.nMaxCustFilter=0;
1923 // ofn.nFilterIndex=0;
1924 // ofn.lpstrFile=NULL;
1925 ofn.nMaxFile=MAX_PATH;
1926 // ofn.lpstrFileTitle=NULL;
1927 // ofn.lpstrInitialDir=NULL;
1928 // ofn.lpstrTitle=NULL;
1929 ofn.Flags=OFN_OVERWRITEPROMPT;
1930 // ofn.nFileOffset=0;
1931 // ofn.nFileExtension=0;
1932 ofn.lpstrDefExt=TEXT("sif");
1933 // ofn.lCustData = 0l;
1935 // ofn.lpTemplateName=NULL;
1937 CHAR szFilename[MAX_PATH];
1939 strcpy(szFilename,filename.c_str());
1940 strcpy(szTitle,title.c_str());
1942 ofn.lpstrFile=szFilename;
1943 ofn.lpstrFileTitle=szTitle;
1945 if(GetSaveFileName(&ofn))
1947 filename=szFilename;
1948 _preferences.set_value(preference,dirname(filename));
1953 synfig::String prev_path;
1955 if(!_preferences.get_value(preference, prev_path))
1958 prev_path = absolute_path(prev_path);
1960 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1962 dialog->set_current_folder(prev_path);
1963 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1964 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1966 Widget_Enum *file_type_enum = 0;
1967 if (preference == ANIMATION_DIR_PREFERENCE)
1969 file_type_enum = manage(new Widget_Enum());
1970 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
1971 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
1972 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
1973 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
1974 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
1975 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
1977 Gtk::HBox *hbox = manage(new Gtk::HBox);
1978 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
1979 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
1982 dialog->set_extra_widget(*hbox);
1985 if (filename.empty())
1986 dialog->set_filename(prev_path);
1989 std::string full_path;
1990 if (is_absolute_path(filename))
1991 full_path = filename;
1993 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1995 // select the file if it exists
1996 dialog->set_filename(full_path);
1998 // if the file doesn't exist, put its name into the filename box
2000 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2001 dialog->set_current_name(basename(filename));
2004 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2005 if (preference == ANIMATION_DIR_PREFERENCE)
2006 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2007 filename = dialog->get_filename();
2008 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2009 _preferences.set_value(preference, dirname(filename));
2020 App::dialog_error_blocking(const std::string &title, const std::string &message)
2022 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2023 dialog.set_title(title);
2029 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2031 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2032 dialog.set_title(title);
2038 App::dialog_yes_no(const std::string &title, const std::string &message)
2043 true // use_separator
2045 Gtk::Label label(message);
2048 dialog.get_vbox()->pack_start(label);
2049 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2050 dialog.add_button(Gtk::StockID("gtk-no"),0);
2052 return dialog.run();
2056 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2061 true // use_separator
2063 Gtk::Label label(message);
2066 dialog.get_vbox()->pack_start(label);
2067 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2068 dialog.add_button(Gtk::StockID("gtk-no"),0);
2069 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2071 return dialog.run();
2075 App::dialog_not_implemented()
2077 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2078 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2083 try_open_url(const std::string &url)
2086 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2088 std::vector<std::string> command_line;
2089 std::vector<std::string> browsers;
2090 browsers.reserve(23);
2092 // Browser wrapper scripts
2093 #ifdef USE_OPEN_FOR_URLS
2094 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2096 browsers.push_back("xdg-open"); // XDG wrapper
2097 browsers.push_back("sensible-browser"); // Debian wrapper
2098 browsers.push_back("gnome-open"); // GNOME wrapper
2099 browsers.push_back("kfmclient"); // KDE wrapper
2100 browsers.push_back("exo-open"); // XFCE wrapper
2102 // Alternatives system
2103 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2104 browsers.push_back("x-www-browser"); // Debian GUI alternative
2106 // Individual browsers
2107 browsers.push_back("firefox");
2108 browsers.push_back("epiphany-browser");
2109 browsers.push_back("epiphany");
2110 browsers.push_back("konqueror");
2111 browsers.push_back("iceweasel");
2112 browsers.push_back("mozilla");
2113 browsers.push_back("netscape");
2114 browsers.push_back("icecat");
2115 browsers.push_back("galeon");
2116 browsers.push_back("midori");
2117 browsers.push_back("safari");
2118 browsers.push_back("opera");
2119 browsers.push_back("amaya");
2120 browsers.push_back("netsurf");
2121 browsers.push_back("dillo");
2123 // Try the user-specified browser first
2124 command_line.push_back(App::browser_command);
2125 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2126 command_line.push_back(url);
2128 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2129 catch( Glib::SpawnError& exception ){
2131 while ( !browsers.empty() )
2133 // Skip the browser if we already tried it
2134 if( browsers[0] == App::browser_command )
2137 // Construct the command line
2138 command_line.clear();
2139 command_line.push_back(browsers[0]);
2140 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2141 command_line.push_back(url);
2143 // Remove the browser from the list
2144 browsers.erase(browsers.begin());
2146 // Try to spawn the browser
2147 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2148 // Failed, move on to the next one
2149 catch(Glib::SpawnError& exception){ continue; }
2150 return true; // No exception means we succeeded!
2161 if (!try_open_url("http://synfig.org/Documentation"))
2163 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2164 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2165 dialog.set_title(_("Help"));
2171 App::open_url(const std::string &url)
2173 if(!try_open_url(url))
2175 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2176 dialog.set_secondary_text(url);
2177 dialog.set_title(_("No browser found"));
2183 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2188 true); // use_separator
2190 Gtk::Label label(message);
2192 dialog.get_vbox()->pack_start(label);
2195 entry.set_text(text);
2197 entry.set_activates_default(true);
2199 dialog.get_vbox()->pack_start(entry);
2201 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2202 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2203 dialog.set_default_response(Gtk::RESPONSE_OK);
2205 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2208 if(dialog.run()!=Gtk::RESPONSE_OK)
2211 text=entry.get_text();
2217 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2222 true); // use_separator
2224 Gtk::Label label(message);
2226 dialog.get_vbox()->pack_start(label);
2228 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2229 text_buffer->set_text(text);
2230 Gtk::TextView text_view(text_buffer);
2233 dialog.get_vbox()->pack_start(text_view);
2235 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2236 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2237 dialog.set_default_response(Gtk::RESPONSE_OK);
2239 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2242 if(dialog.run()!=Gtk::RESPONSE_OK)
2245 text=text_buffer->get_text();
2251 App::open(std::string filename)
2253 return open_as(filename,filename);
2256 // this is called from autorecover.cpp:
2257 // App::open_as(get_shadow_file_name(filename),filename)
2258 // other than that, 'filename' and 'as' are the same
2260 App::open_as(std::string filename,std::string as)
2263 char long_name[1024];
2264 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2265 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2266 // don't use it if that's the case
2267 if (long_name[0] != '\0')
2273 OneMoment one_moment;
2275 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
2276 if(canvas && get_instance(canvas))
2278 get_instance(canvas)->find_canvas_view(canvas)->present();
2279 info("%s is already open", filename.c_str());
2280 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2285 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2287 if (as.find(DEFAULT_FILENAME_PREFIX) != 0)
2288 add_recent_file(as);
2290 handle<Instance> instance(Instance::create(canvas));
2293 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2295 set_recent_file_window_size(instance);
2299 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)")))
2300 instance->dialog_cvs_update();
2305 dialog_error_blocking(_("Error"), x);
2310 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2321 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2323 String file_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2324 canvas->set_name(file_name);
2325 file_name += ".sifz";
2327 canvas->rend_desc().set_frame_rate(24.0);
2328 canvas->rend_desc().set_time_start(0.0);
2329 canvas->rend_desc().set_time_end(5.0);
2330 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2331 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2332 canvas->rend_desc().set_tl(Vector(-4,2.25));
2333 canvas->rend_desc().set_br(Vector(4,-2.25));
2334 canvas->rend_desc().set_w(480);
2335 canvas->rend_desc().set_h(270);
2336 canvas->rend_desc().set_antialias(1);
2337 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2338 canvas->set_file_name(file_name);
2340 handle<Instance> instance = Instance::create(canvas);
2342 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2343 instance->find_canvas_view(canvas)->canvas_properties.present();
2347 App::dialog_open(string filename)
2349 if (filename.empty())
2352 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2354 // If the filename still has wildcards, then we should
2355 // continue looking for the file we want
2356 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2362 get_ui_interface()->error(_("Unable to open file"));
2367 App::set_selected_instance(etl::loose_handle<Instance> instance)
2369 /* if(get_selected_instance()==instance)
2371 selected_instance=instance;
2372 signal_instance_selected()(instance);
2378 selected_instance=instance;
2379 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2383 instance->focus(instance->get_canvas());
2386 set_selected_canvas_view(0);
2388 signal_instance_selected()(instance);
2392 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2394 selected_canvas_view=canvas_view;
2395 signal_canvas_view_focus()(selected_canvas_view);
2398 selected_instance=canvas_view->get_instance();
2399 signal_instance_selected()(canvas_view->get_instance());
2402 if(get_selected_canvas_view()==canvas_view)
2404 signal_canvas_view_focus()(selected_canvas_view);
2405 signal_instance_selected()(canvas_view->get_instance());
2408 selected_canvas_view=canvas_view;
2409 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2410 set_selected_instance(canvas_view->get_instance());
2411 signal_canvas_view_focus()(selected_canvas_view);
2415 etl::loose_handle<Instance>
2416 App::get_instance(etl::handle<synfig::Canvas> canvas)
2418 if(!canvas) return 0;
2419 canvas=canvas->get_root();
2421 std::list<etl::handle<Instance> >::iterator iter;
2422 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2424 if((*iter)->get_canvas()==canvas)
2440 if(selected_instance)
2441 selected_instance->undo();
2447 if(selected_instance)
2448 selected_instance->redo();
2452 studio::App::get_base_path()
2454 return app_base_path_;