1 /* === S Y N F I G ========================================================= */
2 /*!	\file app.cpp
3 **	\brief writeme
4 **
5 **	$Id$
6 **
7 **	\legal
8 **	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **	Copyright (c) 2007, 2008 Chris Moore
10 **	Copyright (c) 2008 Gerald Young
11 **	Copyright (c) 2008, 2010-2013 Carlos López
12 **	Copyright (c) 2009, 2011 Nikita Kitaev
13 **	Copyright (c) 2012-2015 Konstantin Dmitriev
14 **	Copyright (c) 2013-2016 Jerome Blanchi
15 **
16 **	This package is free software; you can redistribute it and/or
17 **	modify it under the terms of the GNU General Public License as
18 **	published by the Free Software Foundation; either version 2 of
19 **	the License, or (at your option) any later version.
20 **
21 **	This package is distributed in the hope that it will be useful,
22 **	but WITHOUT ANY WARRANTY; without even the implied warranty of
23 **	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 **	General Public License for more details.
25 **	\endlegal
26 */
27 /* ========================================================================= */
28 
29 /* === H E A D E R S ======================================================= */
30 
31 #ifdef USING_PCH
32 #	include "pch.h"
33 #else
34 #ifdef HAVE_CONFIG_H
35 #	include <config.h>
36 #endif
37 
38 #include <fstream>
39 #include <iostream>
40 #include <locale>
41 #include <cstring>
42 
43 #ifdef __OpenBSD__
44 #include <errno.h>
45 #elif defined(HAVE_SYS_ERRNO_H)
46 #include <sys/errno.h>
47 #endif
48 #include <gtkmm/accelmap.h>
49 #include <gtkmm/cssprovider.h>
50 #include <gtkmm/dialog.h>
51 #include <gtkmm/filechooserdialog.h>
52 #include <gtkmm/filefilter.h>
53 #include <gtkmm/iconsource.h>
54 #include <gtkmm/label.h>
55 #include <gtkmm/messagedialog.h>
56 #include <gtkmm/stock.h>
57 #include <gtkmm/stockitem.h>
58 #include <gtkmm/textview.h>
59 #include <gtkmm/uimanager.h>
60 
61 #include <glibmm/main.h>
62 #include <glibmm/miscutils.h>
63 #include <glibmm/spawn.h>
64 #include <glibmm/thread.h>
65 #include <glibmm/timer.h>
66 
67 #include <gtk/gtk.h>
68 #include <gdk/gdk.h>
69 
70 #include <gdkmm/general.h>
71 
72 #ifdef _WIN32
73 #define WINVER 0x0500
74 #include <windows.h>
75 #endif
76 
77 #include <synfig/general.h>
78 
79 #include <synfig/canvasfilenaming.h>
80 #include <synfig/filesystemnative.h>
81 #include <synfig/filesystemgroup.h>
82 #include <synfig/filesystemtemporary.h>
83 #include <synfig/importer.h>
84 #include <synfig/loadcanvas.h>
85 #include <synfig/savecanvas.h>
86 
87 #include "app.h"
88 #include "splash.h"
89 #include "instance.h"
90 #include "canvasview.h"
91 #include "dialogs/about.h"
92 #include "dialogs/dialog_color.h"
93 #include "dialogs/dialog_gradient.h"
94 #include "dialogs/dialog_input.h"
95 #include "dialogs/dialog_setup.h"
96 #include "onemoment.h"
97 #include "devicetracker.h"
98 #include "widgets/widget_enum.h"
99 
100 #include "statemanager.h"
101 
102 #include "states/state_bline.h"
103 #include "states/state_brush.h"
104 #include "states/state_circle.h"
105 #include "states/state_draw.h"
106 #include "states/state_eyedrop.h"
107 #include "states/state_fill.h"
108 #include "states/state_gradient.h"
109 #include "states/state_lasso.h"
110 #include "states/state_mirror.h"
111 #include "states/state_normal.h"
112 #include "states/state_polygon.h"
113 #include "states/state_rectangle.h"
114 #include "states/state_rotate.h"
115 #include "states/state_scale.h"
116 #include "states/state_sketch.h"
117 #include "states/state_smoothmove.h"
118 #include "states/state_star.h"
119 #include "states/state_text.h"
120 #include "states/state_width.h"
121 #include "states/state_zoom.h"
122 
123 #include "autorecover.h"
124 
125 #include <synfigapp/settings.h>
126 
127 #include "docks/dockmanager.h"
128 #include "docks/dialog_tooloptions.h"
129 #include "docks/dock_canvases.h"
130 #include "docks/dock_children.h"
131 #include "docks/dock_curves.h"
132 #include "docks/dock_history.h"
133 #include "docks/dock_info.h"
134 #include "docks/dock_keyframes.h"
135 #include "docks/dock_layers.h"
136 #include "docks/dock_layergroups.h"
137 #include "docks/dock_params.h"
138 #include "docks/dock_metadata.h"
139 #include "docks/dock_navigator.h"
140 #include "docks/dock_timetrack.h"
141 #include "docks/dock_toolbox.h"
142 
143 #include "modules/module.h"
144 #include "modules/mod_palette/mod_palette.h"
145 
146 #include "ipc.h"
147 
148 #ifdef WITH_FMOD
149 #include <fmod.h>
150 #endif
151 
152 #include <gui/localization.h>
153 
154 #endif
155 
156 /* === U S I N G =========================================================== */
157 
158 using namespace std;
159 using namespace etl;
160 using namespace synfig;
161 using namespace studio;
162 
163 /* === M A C R O S ========================================================= */
164 
165 #ifndef DPM2DPI
166 #define DPM2DPI(x)	(float(x)/39.3700787402f)
167 #define DPI2DPM(x)	(float(x)*39.3700787402f)
168 #endif
169 
170 #ifdef _WIN32
171 #	ifdef IMAGE_DIR
172 #		undef IMAGE_DIR
173 #		define IMAGE_DIR "share\\pixmaps"
174 #	endif
175 #endif
176 
177 #ifndef IMAGE_DIR
178 #	define IMAGE_DIR "/usr/local/share/pixmaps"
179 #endif
180 
181 #ifndef IMAGE_EXT
182 #	define IMAGE_EXT	"tif"
183 #endif
184 
185 #ifdef _WIN32
186 #	ifdef PLUGIN_DIR
187 #		undef PLUGIN_DIR
188 #		define PLUGIN_DIR "share\\synfig\\plugins"
189 #	endif
190 #endif
191 
192 #ifndef PLUGIN_DIR
193 #	define PLUGIN_DIR "/usr/local/share/synfig/plugins"
194 #endif
195 
196 #include <synfigapp/main.h>
197 
198 /* === S I G N A L S ======================================================= */
199 
200 static sigc::signal<void> signal_present_all_;
201 sigc::signal<void>&
signal_present_all()202 App::signal_present_all() { return signal_present_all_; }
203 
204 static sigc::signal<void> signal_recent_files_changed_;
205 sigc::signal<void>&
signal_recent_files_changed()206 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
207 
208 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
209 sigc::signal<void,etl::loose_handle<CanvasView> >&
signal_canvas_view_focus()210 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
211 
212 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
213 sigc::signal<void,etl::handle<Instance> >&
signal_instance_selected()214 App::signal_instance_selected() { return signal_instance_selected_; }
215 
216 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
217 sigc::signal<void,etl::handle<Instance> >&
signal_instance_created()218 App::signal_instance_created() { return signal_instance_created_; }
219 
220 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
221 sigc::signal<void,etl::handle<Instance> >&
signal_instance_deleted()222 App::signal_instance_deleted() { return signal_instance_deleted_; }
223 
224 /* === G L O B A L S ======================================================= */
225 
226 static std::list<std::string> recent_files;
get_recent_files()227 const std::list<std::string>& App::get_recent_files() { return recent_files; }
228 
229 int	App::Busy::count;
230 bool App::shutdown_in_progress;
231 
232 synfig::Gamma App::gamma;
233 
234 Glib::RefPtr<studio::UIManager>	App::ui_manager_;
235 
236 int App::jack_locks_=0;
237 
238 synfig::Distance::System App::distance_system;
239 
240 studio::Dialog_Setup* App::dialog_setup;
241 
242 etl::handle< studio::ModPalette > mod_palette_;
243 //studio::Dialog_Palette* App::dialog_palette;
244 
245 std::list<etl::handle<Instance> > App::instance_list;
246 
247 static etl::handle<synfigapp::UIInterface> ui_interface_;
get_ui_interface()248 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
249 
250 etl::handle<Instance> App::selected_instance;
251 etl::handle<CanvasView> App::selected_canvas_view;
252 
253 studio::About *studio::App::about=NULL;
254 
255 studio::MainWindow *studio::App::main_window=NULL;
256 
257 studio::Dock_Toolbox *studio::App::dock_toolbox=NULL;
258 
259 studio::AutoRecover *studio::App::auto_recover=NULL;
260 
261 studio::IPC *ipc=NULL;
262 
263 studio::DockManager* studio::App::dock_manager=0;
264 
265 studio::DeviceTracker* studio::App::device_tracker=0;
266 
267 studio::Dialog_Gradient* studio::App::dialog_gradient;
268 
269 studio::Dialog_Color* studio::App::dialog_color;
270 
271 studio::Dialog_Input* studio::App::dialog_input;
272 
273 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
274 
275 studio::Dock_History* dock_history;
276 studio::Dock_Canvases* dock_canvases;
277 studio::Dock_Keyframes* dock_keyframes;
278 studio::Dock_Layers* dock_layers;
279 studio::Dock_Params* dock_params;
280 studio::Dock_MetaData* dock_meta_data;
281 studio::Dock_Children* dock_children;
282 studio::Dock_Info* dock_info;
283 studio::Dock_LayerGroups* dock_layer_groups;
284 studio::Dock_Navigator* dock_navigator;
285 studio::Dock_Timetrack* dock_timetrack;
286 studio::Dock_Curves* dock_curves;
287 
288 std::list< etl::handle< studio::Module > > module_list_;
289 
290 bool studio::App::use_colorspace_gamma=true;
291 #ifdef SINGLE_THREADED
292 	//#ifdef	WIN32
293 	bool studio::App::single_threaded=true;
294 	//#else
295 	//bool studio::App::single_threaded=false;
296 	//#endif // WIN32
297 #endif  // SINGLE THREADED
298 bool studio::App::restrict_radius_ducks=true;
299 bool studio::App::resize_imported_images=false;
300 bool studio::App::enable_experimental_features=false;
301 bool studio::App::use_dark_theme=false;
302 bool studio::App::show_file_toolbar=true;
303 String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
304 int studio::App::preferred_x_size=480;
305 int studio::App::preferred_y_size=270;
306 String studio::App::predefined_size(DEFAULT_PREDEFINED_SIZE);
307 String studio::App::predefined_fps(DEFAULT_PREDEFINED_FPS);
308 float studio::App::preferred_fps=24.0;
309 synfigapp::PluginManager studio::App::plugin_manager;
310 std::set< String > studio::App::brushes_path;
311 String studio::App::sequence_separator(".");
312 String studio::App::navigator_renderer;
313 String studio::App::workarea_renderer;
314 
315 bool studio::App::enable_mainwin_menubar = true;
316 String studio::App::ui_language ("os_LANG");
317 long studio::App::ui_handle_tooltip_flag(Duck::STRUCT_DEFAULT);
318 
319 static int max_recent_files_=25;
get_max_recent_files()320 int studio::App::get_max_recent_files() { return max_recent_files_; }
set_max_recent_files(int x)321 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
322 
323 static synfig::String app_base_path_;
324 
325 namespace studio {
326 
327 bool
really_delete_widget(Gtk::Widget * widget)328 really_delete_widget(Gtk::Widget *widget)
329 {
330 	// synfig::info("really delete %p", (void*)widget);
331 	delete widget;
332 	return false;
333 }
334 
335 // nasty workaround - when we've finished with a popup menu, we want to delete it
336 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
337 // so schedule the real delete to happen in 50ms, giving the action a chance to run
338 void
delete_widget(Gtk::Widget * widget)339 delete_widget(Gtk::Widget *widget)
340 {
341 	// synfig::info("delete %p", (void*)widget);
342 	Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
343 }
344 
345 }; // END of namespace studio
346 studio::StateManager* state_manager;
347 
348 
349 
350 
351 class GlobalUIInterface : public synfigapp::UIInterface
352 {
353 public:
354 
confirmation(const std::string & message,const std::string & details,const std::string & cancel,const std::string & confirm,Response dflt)355 	virtual Response confirmation(
356 			const std::string &message,
357 			const std::string &details,
358 			const std::string &cancel,
359 			const std::string &confirm,
360 			Response dflt
361 	)
362 	{
363 		Gtk::MessageDialog dialog(
364 			message,
365 			false,
366 			Gtk::MESSAGE_WARNING,
367 			Gtk::BUTTONS_NONE,
368 			true
369 		);
370 
371 		if (! details.empty())
372 			dialog.set_secondary_text(details);
373 
374 		dialog.add_button(cancel, RESPONSE_CANCEL);
375 		dialog.add_button(confirm, RESPONSE_OK);
376 		dialog.set_default_response(dflt);
377 
378 		dialog.show_all();
379 		return (Response) dialog.run();
380 	}
381 
382 
yes_no_cancel(const std::string & message,const std::string & details,const std::string & button1,const std::string & button2,const std::string & button3,Response dflt=RESPONSE_YES)383 	virtual Response yes_no_cancel(
384 				const std::string &message,
385 				const std::string &details,
386 				const std::string &button1,
387 				const std::string &button2,
388 				const std::string &button3,
389 				Response dflt=RESPONSE_YES
390 	)
391 	{
392 		Gtk::MessageDialog dialog(
393 			message,
394 			false,
395 			Gtk::MESSAGE_QUESTION,
396 			Gtk::BUTTONS_NONE,
397 			true
398 		);
399 
400 		dialog.set_secondary_text(details);
401 		dialog.add_button(button1, RESPONSE_NO);
402 		dialog.add_button(button2, RESPONSE_CANCEL);
403 		dialog.add_button(button3, RESPONSE_YES);
404 
405 		dialog.set_default_response(dflt);
406 		dialog.show();
407 		return (Response)dialog.run();
408 	}
409 
410 
411 	virtual bool
task(const std::string & task)412 	task(const std::string &task)
413 	{
414 		std::cerr<<task.c_str()<<std::endl;
415 		while(studio::App::events_pending())studio::App::iteration(false);
416 		return true;
417 	}
418 
419 	virtual bool
error(const std::string & err)420 	error(const std::string &err)
421 	{
422 		Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
423 		dialog.set_transient_for(*App::main_window);
424 		dialog.show();
425 		dialog.run();
426 		return true;
427 	}
428 
429 	virtual bool
warning(const std::string & err)430 	warning(const std::string &err)
431 	{
432 		std::cerr<<"warning: "<<err.c_str()<<std::endl;
433 		while(studio::App::events_pending())studio::App::iteration(false);
434 		return true;
435 	}
436 
437 	virtual bool
amount_complete(int,int)438 	amount_complete(int /*current*/, int /*total*/)
439 	{
440 		while(studio::App::events_pending())studio::App::iteration(false);
441 		return true;
442 	}
443 };
444 
445 /* === P R O C E D U R E S ================================================= */
446 
447 /*
448 void
449 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
450 {
451 	action_group_list.push_back(action_group);
452 	Gtk::UIManager::insert_action_group(action_group, pos);
453 }
454 
455 void
456 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
457 {
458 	std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
459 	for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
460 		if(*iter==action_group)
461 		{
462 			action_group_list.erase(iter);
463 			Gtk::UIManager::remove_action_group(action_group);
464 			return;
465 		}
466 	synfig::error("Unable to find action group");
467 }
468 
469 void
470 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
471 {
472 	ui_manager->insert_action_group(group,0);
473 	return;
474 	std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
475 	std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
476 
477 	for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
478 	{
479 		if(*iter && (*iter)->get_name()!="menus")
480 		{
481 			synfig::info("Removing action group "+(*iter)->get_name());
482 			ui_manager->remove_action_group(*iter);
483 		}
484 	}
485 	ui_manager->insert_action_group(group,0);
486 
487 	for(;!prev_groups.empty();prev_groups.pop_front())
488 	{
489 		if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
490 			ui_manager->insert_action_group(prev_groups.front(),1);
491 	}
492 }
493 */
494 class Preferences : public synfigapp::Settings
495 {
496 public:
get_value(const synfig::String & key,synfig::String & value) const497 	virtual bool get_value(const synfig::String& key, synfig::String& value)const
498 	{
499 		try
500 		{
501 			synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
502 			if(key=="gamma")
503 			{
504 				value=strprintf("%f %f %f %f",
505 					App::gamma.get_gamma_r(),
506 					App::gamma.get_gamma_g(),
507 					App::gamma.get_gamma_b(),
508 					App::gamma.get_black_level()
509 				);
510 				return true;
511 			}
512 			if(key=="time_format")
513 			{
514 				value=strprintf("%i",App::get_time_format());
515 				return true;
516 			}
517 			if(key=="file_history.size")
518 			{
519 				value=strprintf("%i",App::get_max_recent_files());
520 				return true;
521 			}
522 			if(key=="use_colorspace_gamma")
523 			{
524 				value=strprintf("%i",(int)App::use_colorspace_gamma);
525 				return true;
526 			}
527 			if(key=="distance_system")
528 			{
529 				value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
530 				return true;
531 			}
532 #ifdef SINGLE_THREADED
533 			if(key=="use_single_threaded")
534 			{
535 				value=strprintf("%i",(int)App::single_threaded);
536 				return true;
537 			}
538 #endif
539 			if(key=="auto_recover_backup")
540 			{
541 				value=strprintf("%i",App::auto_recover->get_enabled());
542 				return true;
543 			}
544 			if(key=="auto_recover_backup_interval")
545 			{
546 				value=strprintf("%i",App::auto_recover->get_timeout_ms());
547 				return true;
548 			}
549 			if(key=="restrict_radius_ducks")
550 			{
551 				value=strprintf("%i",(int)App::restrict_radius_ducks);
552 				return true;
553 			}
554 			if(key=="resize_imported_images")
555 			{
556 				value=strprintf("%i",(int)App::resize_imported_images);
557 				return true;
558 			}
559 			if(key=="enable_experimental_features")
560 			{
561 				value=strprintf("%i",(int)App::enable_experimental_features);
562 				return true;
563 			}
564 			if(key=="use_dark_theme")
565 			{
566 				value=strprintf("%i",(int)App::use_dark_theme);
567 				return true;
568 			}
569 			if(key=="show_file_toolbar")
570 			{
571 				value=strprintf("%i",(int)App::show_file_toolbar);
572 				return true;
573 			}
574 			//! "Keep brushes_path" preferences entry for backward compatibilty (15/12 - v1.0.3)
575 			//! Now brush path(s) are hold by input preferences : brush.path_count & brush.path_%d
576 			if(key=="brushes_path")
577 			{
578 				value="";
579 				if(!App::brushes_path.empty())
580 					value=*(App::brushes_path.begin());
581 				return true;
582 			}
583 			if(key=="custom_filename_prefix")
584 			{
585 				value=App::custom_filename_prefix;
586 				return true;
587 			}
588 			if(key=="preferred_x_size")
589 			{
590 				value=strprintf("%i",App::preferred_x_size);
591 				return true;
592 			}
593 			if(key=="preferred_y_size")
594 			{
595 				value=strprintf("%i",App::preferred_y_size);
596 				return true;
597 			}
598 			if(key=="predefined_size")
599 			{
600 				value=strprintf("%s",App::predefined_size.c_str());
601 				return true;
602 			}
603 			if(key=="preferred_fps")
604 			{
605 				value=strprintf("%f",App::preferred_fps);
606 				return true;
607 			}
608 			if(key=="predefined_fps")
609 			{
610 				value=strprintf("%s",App::predefined_fps.c_str());
611 				return true;
612 			}
613 			if(key=="sequence_separator")
614 			{
615 				value=App::sequence_separator;
616 				return true;
617 			}
618 			if(key=="navigator_renderer")
619 			{
620 				value=App::navigator_renderer;
621 				return true;
622 			}
623 			if(key=="workarea_renderer")
624 			{
625 				value=App::workarea_renderer;
626 				return true;
627 			}
628 			if(key=="enable_mainwin_menubar")
629 			{
630 				value=strprintf("%i", (int)App::enable_mainwin_menubar);
631 				return true;
632 			}
633 			if(key=="ui_handle_tooltip_flag")
634 			{
635 				value=strprintf("%il", (long)App::ui_handle_tooltip_flag);
636 				return true;
637 			}
638 		}
639 		catch(...)
640 		{
641 			synfig::warning("Preferences: Caught exception when attempting to get value.");
642 		}
643 		return synfigapp::Settings::get_value(key,value);
644 	}
645 
set_value(const synfig::String & key,const synfig::String & value)646 	virtual bool set_value(const synfig::String& key,const synfig::String& value)
647 	{
648 		try
649 		{
650 			synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
651 			if(key=="gamma")
652 			{
653 				float r,g,b,blk;
654 
655 				strscanf(value,"%f %f %f %f",
656 					&r,
657 					&g,
658 					&b,
659 					&blk
660 				);
661 
662 				App::gamma.set_all(r,g,b,blk);
663 
664 				return true;
665 			}
666 			if(key=="time_format")
667 			{
668 				int i(atoi(value.c_str()));
669 				App::set_time_format(static_cast<synfig::Time::Format>(i));
670 				return true;
671 			}
672 			if(key=="auto_recover_backup")
673 			{
674 				int i(atoi(value.c_str()));
675 				App::auto_recover->set_enabled(i);
676 				return true;
677 			}
678 			if(key=="auto_recover_backup_interval")
679 			{
680 				int i(atoi(value.c_str()));
681 				App::auto_recover->set_timeout_ms(i);
682 				return true;
683 			}
684 			if(key=="file_history.size")
685 			{
686 				int i(atoi(value.c_str()));
687 				App::set_max_recent_files(i);
688 				return true;
689 			}
690 			if(key=="use_colorspace_gamma")
691 			{
692 				int i(atoi(value.c_str()));
693 				App::use_colorspace_gamma=i;
694 				return true;
695 			}
696 			if(key=="distance_system")
697 			{
698 				App::distance_system=Distance::ident_system(value);;
699 				return true;
700 			}
701 #ifdef SINGLE_THREADED
702 			if(key=="use_single_threaded")
703 			{
704 				int i(atoi(value.c_str()));
705 				App::single_threaded=i;
706 				return true;
707 			}
708 #endif
709 			if(key=="restrict_radius_ducks")
710 			{
711 				int i(atoi(value.c_str()));
712 				App::restrict_radius_ducks=i;
713 				return true;
714 			}
715 			if(key=="resize_imported_images")
716 			{
717 				int i(atoi(value.c_str()));
718 				App::resize_imported_images=i;
719 				return true;
720 			}
721 			if(key=="enable_experimental_features")
722 			{
723 				int i(atoi(value.c_str()));
724 				App::enable_experimental_features=i;
725 				return true;
726 			}
727 			if(key=="use_dark_theme")
728 			{
729 				int i(atoi(value.c_str()));
730 				App::use_dark_theme=i;
731 				return true;
732 			}
733 			if(key=="show_file_toolbar")
734 			{
735 				int i(atoi(value.c_str()));
736 				App::show_file_toolbar=i;
737 				return true;
738 			}
739 			//! "Keep brushes_path" preferences entry for backward compatibilty (15/12 - v1.0.3)
740 			//! Now brush path(s) are hold by input preferences : brush.path_count & brush.path_%d
741 			if(key=="brushes_path")
742 			{
743 				App::brushes_path.insert(value);
744 				return true;
745 			}
746 			if(key=="custom_filename_prefix")
747 			{
748 				App::custom_filename_prefix=value;
749 				return true;
750 			}
751 			if(key=="preferred_x_size")
752 			{
753 				int i(atoi(value.c_str()));
754 				App::preferred_x_size=i;
755 				return true;
756 			}
757 			if(key=="preferred_y_size")
758 			{
759 				int i(atoi(value.c_str()));
760 				App::preferred_y_size=i;
761 				return true;
762 			}
763 			if(key=="predefined_size")
764 			{
765 				App::predefined_size=value;
766 				return true;
767 			}
768 			if(key=="preferred_fps")
769 			{
770 				float i(atof(value.c_str()));
771 				App::preferred_fps=i;
772 				return true;
773 			}
774 			if(key=="predefined_fps")
775 			{
776 				App::predefined_fps=value;
777 				return true;
778 			}
779 			if(key=="sequence_separator")
780 			{
781 				App::sequence_separator=value;
782 				return true;
783 			}
784 			if(key=="navigator_renderer")
785 			{
786 				App::navigator_renderer=value;
787 				return true;
788 			}
789 			if(key=="workarea_renderer")
790 			{
791 				App::workarea_renderer=value;
792 				return true;
793 			}
794 			if(key=="enable_mainwin_menubar")
795 			{
796 				int i(atoi(value.c_str()));
797 				App::enable_mainwin_menubar = i;
798 				return true;
799 			}
800 			if(key=="ui_handle_tooltip_flag")
801 			{
802 				long l(atol(value.c_str()));
803 				App::ui_handle_tooltip_flag = l;
804 				return true;
805 			}
806 		}
807 		catch(...)
808 		{
809 			synfig::warning("Preferences: Caught exception when attempting to set value.");
810 		}
811 		return synfigapp::Settings::set_value(key,value);
812 	}
813 
get_key_list() const814 	virtual KeyList get_key_list()const
815 	{
816 		KeyList ret(synfigapp::Settings::get_key_list());
817 		ret.push_back("gamma");
818 		ret.push_back("time_format");
819 		ret.push_back("distance_system");
820 		ret.push_back("file_history.size");
821 		ret.push_back("use_colorspace_gamma");
822 #ifdef SINGLE_THREADED
823 		ret.push_back("use_single_threaded");
824 #endif
825 		ret.push_back("auto_recover_backup");
826 		ret.push_back("auto_recover_backup_interval");
827 		ret.push_back("restrict_radius_ducks");
828 		ret.push_back("resize_imported_images");
829 		ret.push_back("enable_experimental_features");
830 		ret.push_back("use_dark_theme");
831 		ret.push_back("show_file_toolbar");
832 		ret.push_back("brushes_path");
833 		ret.push_back("custom_filename_prefix");
834 		ret.push_back("ui_language");
835 		ret.push_back("preferred_x_size");
836 		ret.push_back("preferred_y_size");
837 		ret.push_back("predefined_size");
838 		ret.push_back("preferred_fps");
839 		ret.push_back("predefined_fps");
840 		ret.push_back("sequence_separator");
841 		ret.push_back("navigator_renderer");
842 		ret.push_back("workarea_renderer");
843 		ret.push_back("enable_mainwin_menubar");
844 		ret.push_back("ui_handle_tooltip_flag");
845 
846 		return ret;
847 	}
848 };
849 
850 static ::Preferences _preferences;
851 
852 void
init_ui_manager()853 init_ui_manager()
854 {
855 	Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
856 
857 	Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create("actions");
858 
859 	menus_action_group->add( Gtk::Action::create("menu-file", _("_File")));
860 	menus_action_group->add( Gtk::Action::create("menu-open-recent", _("Open Recent")));
861 
862 	menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")));
863 
864 	menus_action_group->add( Gtk::Action::create("menu-view", _("_View")));
865 	menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Handles")));
866 	menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")));
867 	menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")));
868 
869 	menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")));
870 
871 	menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")));
872 	menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")));
873 	menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")));
874 	menus_action_group->add( Gtk::Action::create("menu-plugins", _("Plug-Ins")));
875 
876 	menus_action_group->add( Gtk::Action::create("menu-window", _("_Window")));
877 	menus_action_group->add( Gtk::Action::create("menu-arrange", _("_Arrange")));
878 	menus_action_group->add( Gtk::Action::create("menu-workspace", _("Work_space")));
879 
880 	menus_action_group->add( Gtk::Action::create("menu-help", _("_Help")) );
881 
882 	menus_action_group->add(Gtk::Action::create("menu-keyframe","Keyframe"));
883 
884 	// Add the synfigapp actions (layer panel toolbar items, etc...)
885 	synfigapp::Action::Book::iterator iter;
886 	for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
887 	{
888 		actions_action_group->add(Gtk::Action::create(
889 			"action-"+iter->second.name,
890 			get_action_stock_id(iter->second),
891 			iter->second.local_name,iter->second.local_name
892 		));
893 	}
894 
895 // predefined actions to initial menu items, so that there is all menu items listing
896 // even there is no any canvas instance existed, for example, when app just opened.
897 // the menu items (action names) should be named consistently with those in canvasview.cpp and others.
898 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); actions_action_group->add(action); }
899 
900 // actions in File menu
901 DEFINE_ACTION("new", Gtk::StockID("synfig-new"));
902 DEFINE_ACTION("open", Gtk::StockID("synfig-open"));
903 DEFINE_ACTION("save", Gtk::StockID("synfig-save"));
904 DEFINE_ACTION("save-as", Gtk::StockID("synfig-save_as"));
905 DEFINE_ACTION("save-all", Gtk::StockID("synfig-save_all"));
906 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
907 DEFINE_ACTION("import", _("Import..."));
908 DEFINE_ACTION("render", _("Render..."));
909 DEFINE_ACTION("preview", _("Preview..."));
910 DEFINE_ACTION("close-document", _("Close Document"));
911 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
912 
913 // actions in Edit menu
914 DEFINE_ACTION("undo", Gtk::StockID("synfig-undo"));
915 DEFINE_ACTION("redo", Gtk::StockID("synfig-redo"));
916 DEFINE_ACTION("copy", Gtk::Stock::COPY);
917 DEFINE_ACTION("cut", Gtk::Stock::CUT);
918 DEFINE_ACTION("paste", Gtk::Stock::PASTE);
919 DEFINE_ACTION("select-all-ducks", _("Select All Handles"));
920 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Handles"));
921 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
922 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
923 DEFINE_ACTION("input-devices", _("Input Devices..."));
924 DEFINE_ACTION("setup", _("Preferences..."));
925 DEFINE_ACTION("restore-default-settings", _("Restore Defaults"));
926 
927 // actions in View menu
928 DEFINE_ACTION("toggle-mainwin-menubar", _("Menubar"));
929 DEFINE_ACTION("toggle-mainwin-toolbar", _("Toolbar"));
930 
931 DEFINE_ACTION("mask-none-ducks", _("Toggle None/Last visible Handles"));
932 DEFINE_ACTION("mask-position-ducks", _("Show Position Handles"));
933 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Handles"));
934 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Handles"));
935 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Handles"));
936 DEFINE_ACTION("mask-width-ducks", _("Show Width Handles"));
937 DEFINE_ACTION("mask-widthpoint-position-ducks", _("Show WidthPoints Position Handles"));
938 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Handles"));
939 DEFINE_ACTION("mask-bone-setup-ducks", _("Show Bone Setup Handles"));
940 DEFINE_ACTION("mask-bone-recursive-ducks", _("Show Recursive Scale Bone Handles"));
941 DEFINE_ACTION("mask-bone-ducks", _("Next Bone Handles"));
942 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
943 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
944 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
945 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
946 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
947 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
948 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
949 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
950 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
951 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
952 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
953 
954 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
955   DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
956 
957 DEFINE_ACTION("play", _("Play"));
958 // the stop is not a normal stop but a pause. So use "Pause" in UI, including TEXT and
959 // icon. the internal code is still using stop.
960 DEFINE_ACTION("stop", _("Pause"));
961 
962 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
963 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
964 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
965 DEFINE_ACTION("toggle-guide-snap", _("Toggle Guide Snap"));
966 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
967 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
968 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
969 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
970 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
971 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
972 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
973 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
974 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
975 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
976 DEFINE_ACTION("jump-next-keyframe", _("Seek to Next Keyframe"));
977 DEFINE_ACTION("jump-prev-keyframe", _("Seek to previous Keyframe"));
978 DEFINE_ACTION("seek-next-frame", _("Seek to Next Frame"));
979 DEFINE_ACTION("seek-prev-frame", _("Seek to Previous Frame"));
980 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
981 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
982 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
983 DEFINE_ACTION("seek-end", _("Seek to End"));
984 
985 // actions in Canvas menu
986 DEFINE_ACTION("properties", _("Properties..."));
987 DEFINE_ACTION("options", _("Options..."));
988 
989 // actions in Layer menu
990 DEFINE_ACTION("amount-inc", _("Increase Layer Amount"))
991 DEFINE_ACTION("amount-dec", _("Decrease Layer Amount"))
992 
993 // actions in Window menu
994 DEFINE_ACTION("workspace-compositing", _("Compositing"));
995 DEFINE_ACTION("workspace-default", _("Default"));
996 DEFINE_ACTION("workspace-animating", _("Animating"));
997 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
998 DEFINE_ACTION("panel-toolbox","Toolbox");
999 DEFINE_ACTION("panel-tool_options",_("Tool Options"));
1000 DEFINE_ACTION("panel-history", "History");
1001 DEFINE_ACTION("panel-canvases",_("Canvas Browser"));
1002 DEFINE_ACTION("panel-keyframes",_("Keyframes"));
1003 DEFINE_ACTION("panel-layers",_("Layers"));
1004 DEFINE_ACTION("panel-params",_("Parameters"));
1005 DEFINE_ACTION("panel-meta_data",_("Canvas MetaData"));
1006 DEFINE_ACTION("panel-children",_("Library"));
1007 DEFINE_ACTION("panel-info",_("Info"));
1008 DEFINE_ACTION("panel-navigator",_("Navigator"));
1009 DEFINE_ACTION("panel-timetrack",_("Timetrack"));
1010 DEFINE_ACTION("panel-curves",_("Graphs"));
1011 DEFINE_ACTION("panel-groups",_("Sets"));
1012 DEFINE_ACTION("panel-pal_edit",_("Palette Editor"));
1013 
1014 // actions in Help menu
1015 DEFINE_ACTION("help", Gtk::Stock::HELP);
1016 DEFINE_ACTION("help-tutorials", Gtk::Stock::HELP);
1017 DEFINE_ACTION("help-reference", Gtk::Stock::HELP);
1018 DEFINE_ACTION("help-faq", Gtk::Stock::HELP);
1019 DEFINE_ACTION("help-support", Gtk::Stock::HELP);
1020 DEFINE_ACTION("help-about", Gtk::StockID("synfig-about"));
1021 
1022 // actions: Keyframe
1023 DEFINE_ACTION("keyframe-properties","Properties");
1024 
1025 
1026 //Layout the actions in the main menu (caret menu, right click on canvas menu) and toolbar:
1027 	Glib::ustring ui_info_menu =
1028 "	<menu action='menu-file'>"
1029 "		<menuitem action='new' />"
1030 "		<menuitem action='open' />"
1031 "		<menu action='menu-open-recent' />"
1032 "		<separator name='sep-file1'/>"
1033 "		<menuitem action='save' />"
1034 "		<menuitem action='save-as' />"
1035 "		<menuitem action='save-all' />"
1036 "		<menuitem action='revert' />"
1037 "		<separator name='sep-file2'/>"
1038 "		<menuitem action='import' />"
1039 "		<separator name='sep-file4'/>"
1040 "		<menuitem action='preview' />"
1041 "		<menuitem action='render' />"
1042 "		<separator name='sep-file5'/>"
1043 "		<menuitem action='close-document' />"
1044 "		<separator name='sep-file6'/>"
1045 "		<menuitem action='quit' />"
1046 "	</menu>"
1047 "	<menu action='menu-edit'>"
1048 "		<menuitem action='undo'/>"
1049 "		<menuitem action='redo'/>"
1050 "		<separator name='sep-edit1'/>"
1051 "		<menuitem action='cut'/>"
1052 "		<menuitem action='copy'/>"
1053 "		<menuitem action='paste'/>"
1054 "		<separator name='sep-edit2'/>"
1055 "		<menuitem action='select-all-layers'/>"
1056 "		<menuitem action='unselect-all-layers'/>"
1057 "		<menuitem action='select-all-ducks'/>"
1058 "		<menuitem action='unselect-all-ducks'/>"
1059 "		<separator name='sep-edit3'/>"
1060 "		<menuitem action='input-devices' />"
1061 "		<menuitem action='setup' />"
1062 "	</menu>"
1063 "	<menu action='menu-view'>"
1064 "		<menuitem action='toggle-mainwin-menubar' />"
1065 "		<menuitem action='toggle-mainwin-toolbar' />"
1066 "		<separator />"
1067 "		<menu action='menu-duck-mask'>"
1068 "			<menuitem action='mask-none-ducks' />"
1069 "			<menuitem action='mask-position-ducks' />"
1070 "			<menuitem action='mask-vertex-ducks' />"
1071 "			<menuitem action='mask-tangent-ducks' />"
1072 "			<menuitem action='mask-radius-ducks' />"
1073 "			<menuitem action='mask-width-ducks' />"
1074 "			<menuitem action='mask-widthpoint-position-ducks' />"
1075 "			<menuitem action='mask-angle-ducks' />"
1076 "			<menuitem action='mask-bone-setup-ducks' />"
1077 "			<menuitem action='mask-bone-recursive-ducks' />"
1078 "			<menuitem action='mask-bone-ducks' />"
1079 "		</menu>"
1080 "		<menu action='menu-preview-quality'>"
1081 "			<menuitem action='quality-00' />"
1082 "			<menuitem action='quality-01' />"
1083 "			<menuitem action='quality-02' />"
1084 "			<menuitem action='quality-03' />"
1085 "			<menuitem action='quality-04' />"
1086 "			<menuitem action='quality-05' />"
1087 "			<menuitem action='quality-06' />"
1088 "			<menuitem action='quality-07' />"
1089 "			<menuitem action='quality-08' />"
1090 "			<menuitem action='quality-09' />"
1091 "			<menuitem action='quality-10' />"
1092 "		</menu>"
1093 "		<menu action='menu-lowres-pixel'>"
1094 "			<menuitem action='decrease-low-res-pixel-size'/>"
1095 "			<menuitem action='increase-low-res-pixel-size'/>"
1096 "			<separator name='pixel-size-separator'/>"
1097 ;
1098 
1099 	for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
1100 		ui_info_menu += strprintf("			<menuitem action='lowres-pixel-%d' />", *iter);
1101 
1102 	ui_info_menu +=
1103 "		</menu>"
1104 "		<separator name='sep-view1'/>"
1105 "		<menuitem action='play'/>"
1106 "		<menuitem action='stop'/>"
1107 "		<separator name='sep-view2'/>"
1108 "		<menuitem action='toggle-grid-show'/>"
1109 "		<menuitem action='toggle-grid-snap'/>"
1110 "		<menuitem action='toggle-guide-show'/>"
1111 "		<menuitem action='toggle-guide-snap'/>"
1112 "		<menuitem action='toggle-low-res'/>"
1113 "		<menuitem action='toggle-onion-skin'/>"
1114 "		<separator name='sep-view3'/>"
1115 "		<menuitem action='canvas-zoom-in'/>"
1116 "		<menuitem action='canvas-zoom-out'/>"
1117 "		<menuitem action='canvas-zoom-fit'/>"
1118 "		<menuitem action='canvas-zoom-100'/>"
1119 "		<separator name='sep-view4'/>"
1120 "		<menuitem action='time-zoom-in'/>"
1121 "		<menuitem action='time-zoom-out'/>"
1122 "		<separator name='sep-view5'/>"
1123 "		<menuitem action='jump-prev-keyframe'/>"
1124 "		<menuitem action='jump-next-keyframe'/>"
1125 "		<menuitem action='seek-prev-frame'/>"
1126 "		<menuitem action='seek-next-frame'/>"
1127 "		<menuitem action='seek-prev-second'/>"
1128 "		<menuitem action='seek-next-second'/>"
1129 "		<menuitem action='seek-begin'/>"
1130 "		<menuitem action='seek-end'/>"
1131 "	</menu>"
1132 "	<menu action='menu-canvas'>"
1133 "		<menuitem action='properties'/>"
1134 "		<menuitem action='options'/>"
1135 "	</menu>"
1136 "	<menu action='menu-toolbox'>"
1137 "	</menu>"
1138 "	<menu action='menu-layer'>"
1139 "		<menu action='menu-layer-new'></menu>"
1140 "		<menuitem action='amount-inc'/>"
1141 "		<menuitem action='amount-dec'/>"
1142 "	</menu>"
1143 "	<menu action='menu-plugins'>"
1144 ;
1145 
1146 	list<synfigapp::PluginManager::plugin> plugin_list = studio::App::plugin_manager.get_list();
1147 	for(list<synfigapp::PluginManager::plugin>::const_iterator p=plugin_list.begin();p!=plugin_list.end();++p) {
1148 
1149 		// TODO: (Plugins) Arrange menu items into groups
1150 
1151 		synfigapp::PluginManager::plugin plugin = *p;
1152 
1153 		DEFINE_ACTION(plugin.id, plugin.name);
1154 		ui_info_menu += strprintf("	<menuitem action='%s'/>", plugin.id.c_str());
1155 	}
1156 
1157 	ui_info_menu +=
1158 "	</menu>"
1159 "	<menu action='menu-window'>"
1160 "		<menu action='menu-arrange'> </menu>"
1161 "		<menu action='menu-workspace'>"
1162 "			<menuitem action='workspace-default' />"
1163 "			<menuitem action='workspace-compositing' />"
1164 "			<menuitem action='workspace-animating' />"
1165 "		</menu>"
1166 "		<separator />"
1167 "		<menuitem action='dialog-flipbook'/>"
1168 "		<menuitem action='panel-toolbox' />"
1169 "		<menuitem action='panel-tool_options' />"
1170 "		<menuitem action='panel-history' />"
1171 "		<menuitem action='panel-canvases' />"
1172 "		<menuitem action='panel-keyframes' />"
1173 "		<menuitem action='panel-layers' />"
1174 "		<menuitem action='panel-params' />"
1175 "		<menuitem action='panel-meta_data' />"
1176 "		<menuitem action='panel-children' />"
1177 "		<menuitem action='panel-info' />"
1178 "		<menuitem action='panel-navigator' />"
1179 "		<menuitem action='panel-timetrack' />"
1180 "		<menuitem action='panel-curves' />"
1181 "		<menuitem action='panel-groups' />"
1182 "		<menuitem action='panel-pal_edit' />"
1183 "		<separator />"
1184 // opened documents will be listed here below the above separator.
1185 "	</menu>"
1186 "	<menu action='menu-help'>"
1187 "		<menuitem action='help'/>"
1188 "		<separator name='sep-help1'/>"
1189 "		<menuitem action='help-tutorials'/>"
1190 "		<menuitem action='help-reference'/>"
1191 "		<menuitem action='help-faq'/>"
1192 "		<separator name='sep-help2'/>"
1193 "		<menuitem action='help-support'/>"
1194 "		<separator name='sep-help3'/>"
1195 "		<menuitem action='help-about'/>"
1196 "	</menu>";
1197 
1198 	Glib::ustring ui_info_main_tool =
1199 "		<toolitem action='new'/>"
1200 "		<toolitem action='open'/>"
1201 "		<toolitem action='save'/>"
1202 "		<toolitem action='save-as'/>"
1203 "		<toolitem action='save-all'/>"
1204 "		<separator />"
1205 "		<toolitem action='undo'/>"
1206 "		<toolitem action='redo'/>"
1207 "		<separator />"
1208 "		<toolitem action='render'/>"
1209 "		<toolitem action='preview'/>";
1210 
1211 	Glib::ustring ui_info =
1212 "<ui>"
1213 "   <popup name='menu-toolbox' action='menu-toolbox'>"
1214 "	<menu action='menu-file'>"
1215 "	</menu>"
1216 "	</popup>"
1217 "	<popup name='menu-main' action='menu-main'>" + ui_info_menu + "</popup>"
1218 "	<menubar name='menubar-main' action='menubar-main'>" + ui_info_menu + "</menubar>"
1219 "	<toolbar name='toolbar-main'>" + ui_info_main_tool + "</toolbar>"
1220 "</ui>";
1221 
1222 	#undef DEFINE_ACTION
1223 
1224 	try
1225 	{
1226 		actions_action_group->set_sensitive(false);
1227 		App::ui_manager()->set_add_tearoffs(false);
1228 		App::ui_manager()->insert_action_group(menus_action_group,1);
1229 		App::ui_manager()->insert_action_group(actions_action_group,1);
1230 		App::ui_manager()->add_ui_from_string(ui_info);
1231 
1232 		//App::ui_manager()->get_accel_group()->unlock();
1233 	}
1234 	catch(const Glib::Error& ex)
1235 	{
1236 		synfig::error("building menus and toolbars failed: " + ex.what());
1237 	}
1238 
1239 	// Add default keyboard accelerators
1240 #define ACCEL(accel,path)						\
1241 	{											\
1242 		Gtk::AccelKey accel_key(accel,path);	\
1243 		Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod());	\
1244 	}
1245 
1246 #define ACCEL2(accel)							\
1247 	{											\
1248 		Gtk::AccelKey accel_key(accel);			\
1249 		Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod());	\
1250 	}
1251 
1252 	// the toolbox
1253 	ACCEL("<Mod1>a",								"<Actions>/action_group_state_manager/state-normal"			);
1254 	ACCEL("<Mod1>v",								"<Actions>/action_group_state_manager/state-smooth_move"		);
1255 	ACCEL("<Mod1>s",								"<Actions>/action_group_state_manager/state-scale"			);
1256 	ACCEL("<Mod1>t",								"<Actions>/action_group_state_manager/state-rotate"			);
1257 	ACCEL("<Mod1>m",								"<Actions>/action_group_state_manager/state-mirror"			);
1258 	ACCEL("<Mod1>c",								"<Actions>/action_group_state_manager/state-circle"			);
1259 	ACCEL("<Mod1>r",								"<Actions>/action_group_state_manager/state-rectangle"			);
1260 	ACCEL("<Mod1>q",								"<Actions>/action_group_state_manager/state-star"			);
1261 	ACCEL("<Mod1>g",								"<Actions>/action_group_state_manager/state-gradient"			);
1262 	ACCEL("<Mod1>p",								"<Actions>/action_group_state_manager/state-polygon"			);
1263 	ACCEL("<Mod1>b",								"<Actions>/action_group_state_manager/state-bline"			);
1264 	ACCEL("<Mod1>x",								"<Actions>/action_group_state_manager/state-text"			);
1265 	ACCEL("<Mod1>f",								"<Actions>/action_group_state_manager/state-fill"			);
1266 	ACCEL("<Mod1>e",								"<Actions>/action_group_state_manager/state-eyedrop"			);
1267 	ACCEL("<Mod1>z",								"<Actions>/action_group_state_manager/state-zoom"			);
1268 	ACCEL("<Mod1>d",								"<Actions>/action_group_state_manager/state-draw"			);
1269 	ACCEL("<Mod1>k",								"<Actions>/action_group_state_manager/state-sketch"			);
1270 	ACCEL("<Mod1>w",								"<Actions>/action_group_state_manager/state-width"			);
1271 
1272 	// everything else
1273 	ACCEL("<Control>a",								"<Actions>/canvasview/select-all-ducks"					);
1274 	ACCEL("<Control>d",								"<Actions>/canvasview/unselect-all-ducks"				);
1275 	ACCEL("<Control><Shift>a",							"<Actions>/canvasview/select-all-layers"				);
1276 	ACCEL("<Control><Shift>d",							"<Actions>/canvasview/unselect-all-layers"				);
1277 	ACCEL("F9",									"<Actions>/canvasview/render"						);
1278 	ACCEL("F11",									"<Actions>/canvasview/preview"						);
1279 	ACCEL("F8",									"<Actions>/canvasview/properties"					);
1280 	ACCEL("F12",									"<Actions>/canvasview/options"						);
1281 	ACCEL("<control>i",								"<Actions>/canvasview/import"						);
1282 	ACCEL2(Gtk::AccelKey(GDK_KEY_Escape,static_cast<Gdk::ModifierType>(0), 		"<Actions>/canvasview/stop"						));
1283 	ACCEL("<Control>g",								"<Actions>/canvasview/toggle-grid-show"					);
1284 	ACCEL("<Control>l",								"<Actions>/canvasview/toggle-grid-snap"					);
1285 	ACCEL("<Control>n",								"<Actions>/mainwindow/new"						);
1286 	ACCEL("<Control>o",								"<Actions>/mainwindow/open"						);
1287 	ACCEL("<Control>s",								"<Actions>/canvasview/save"						);
1288 	ACCEL("<Control><Shift>s",							"<Actions>/canvasview/save-as"						);
1289 	ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,					"<Actions>/canvasview/toggle-low-res"					));
1290 	ACCEL("<Mod1>0",                                                    		"<Actions>/canvasview/mask-none-ducks"          			);
1291 	ACCEL("<Mod1>1",								"<Actions>/canvasview/mask-position-ducks"				);
1292 	ACCEL("<Mod1>2",								"<Actions>/canvasview/mask-vertex-ducks"				);
1293 	ACCEL("<Mod1>3",								"<Actions>/canvasview/mask-tangent-ducks"				);
1294 	ACCEL("<Mod1>4",								"<Actions>/canvasview/mask-radius-ducks"				);
1295 	ACCEL("<Mod1>5",								"<Actions>/canvasview/mask-width-ducks"					);
1296 	ACCEL("<Mod1>6",								"<Actions>/canvasview/mask-angle-ducks"					);
1297 	ACCEL("<Mod1>7",								"<Actions>/canvasview/mask-bone-setup-ducks"				);
1298 	ACCEL("<Mod1>8",								"<Actions>/canvasview/mask-bone-recursive-ducks"			);
1299 	ACCEL("<Mod1>9",								"<Actions>/canvasview/mask-bone-ducks"					);
1300 	ACCEL("<Mod1>5",								"<Actions>/canvasview/mask-widthpoint-position-ducks"			);
1301 	ACCEL2(Gtk::AccelKey(GDK_KEY_Page_Up,Gdk::SHIFT_MASK,				"<Actions>/action_group_layer_action_manager/action-LayerRaise"		));
1302 	ACCEL2(Gtk::AccelKey(GDK_KEY_Page_Down,Gdk::SHIFT_MASK,				"<Actions>/action_group_layer_action_manager/action-LayerLower"		));
1303 	ACCEL("<Control>1",								"<Actions>/canvasview/quality-01"					);
1304 	ACCEL("<Control>2",								"<Actions>/canvasview/quality-02"					);
1305 	ACCEL("<Control>3",								"<Actions>/canvasview/quality-03"					);
1306 	ACCEL("<Control>4",								"<Actions>/canvasview/quality-04"					);
1307 	ACCEL("<Control>5",								"<Actions>/canvasview/quality-05"					);
1308 	ACCEL("<Control>6",								"<Actions>/canvasview/quality-06"					);
1309 	ACCEL("<Control>7",								"<Actions>/canvasview/quality-07"					);
1310 	ACCEL("<Control>8",								"<Actions>/canvasview/quality-08"					);
1311 	ACCEL("<Control>9",								"<Actions>/canvasview/quality-09"					);
1312 	ACCEL("<Control>0",								"<Actions>/canvasview/quality-10"					);
1313 	ACCEL("<Control>z",								"<Actions>/action_group_dock_history/undo"				);
1314 	ACCEL("<Control>r",								"<Actions>/action_group_dock_history/redo"				);
1315 	ACCEL2(Gtk::AccelKey(GDK_KEY_Delete,Gdk::CONTROL_MASK,				"<Actions>/action_group_layer_action_manager/action-LayerRemove"	));
1316 	ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,					"<Actions>/canvasview/decrease-low-res-pixel-size"			));
1317 	ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,					"<Actions>/canvasview/increase-low-res-pixel-size"			));
1318 	ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,			"<Actions>/action_group_layer_action_manager/amount-dec"		));
1319 	ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,			"<Actions>/action_group_layer_action_manager/amount-inc"		));
1320 	ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,					"<Actions>/canvasview/jump-next-keyframe"				));
1321 	ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,					"<Actions>/canvasview/jump-prev-keyframe"				));
1322 	ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,					"<Actions>/canvasview/canvas-zoom-in"					));
1323 	ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,					"<Actions>/canvasview/canvas-zoom-out"					));
1324 	ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,					"<Actions>/canvasview/time-zoom-in"					));
1325 	ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,					"<Actions>/canvasview/time-zoom-out"					));
1326 	ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,					"<Actions>/canvasview/seek-next-frame"					));
1327 	ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,					"<Actions>/canvasview/seek-prev-frame"					));
1328 	ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,					"<Actions>/canvasview/seek-next-second"					));
1329 	ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,					"<Actions>/canvasview/seek-prev-second"					));
1330 	ACCEL("<Mod1>o",								"<Actions>/canvasview/toggle-onion-skin"				);
1331 	ACCEL("<Control><Shift>z",							"<Actions>/canvasview/canvas-zoom-fit"					);
1332 	ACCEL("<Control>p",								"<Actions>/canvasview/play"						);
1333 	ACCEL("Home",									"<Actions>/canvasview/seek-begin"					);
1334 	ACCEL("End",									"<Actions>/canvasview/seek-end"						);
1335 
1336 
1337 #undef ACCEL
1338 #undef ACCEL2
1339 }
1340 
1341 #ifdef _WIN32
1342 #define mkdir(x,y) mkdir(x)
1343 #endif
1344 
1345 /* === M E T H O D S ======================================================= */
1346 
App(const synfig::String & basepath,int * argc,char *** argv)1347 App::App(const synfig::String& basepath, int *argc, char ***argv):
1348 	Gtk::Main(argc,argv),
1349 	IconController(basepath)
1350 {
1351 
1352 	app_base_path_=etl::dirname(basepath);
1353 
1354 	// Set ui language
1355 	load_language_settings();
1356 	if (ui_language != "os_LANG")
1357 	{
1358 		Glib::setenv ("LANGUAGE",  App::ui_language.c_str(), 1);
1359 	}
1360 
1361 	std::string path_to_icons;
1362 #ifdef _WIN32
1363 	path_to_icons=basepath+ETL_DIRECTORY_SEPARATOR+".."+ETL_DIRECTORY_SEPARATOR+IMAGE_DIR;
1364 #else
1365 	path_to_icons=IMAGE_DIR;
1366 #endif
1367 	char* synfig_root=getenv("SYNFIG_ROOT");
1368 	if(synfig_root) {
1369 		path_to_icons=synfig_root;
1370 		path_to_icons+=ETL_DIRECTORY_SEPARATOR;
1371 		path_to_icons+="share";
1372 		path_to_icons+=ETL_DIRECTORY_SEPARATOR;
1373 		path_to_icons+="pixmaps";
1374 		path_to_icons+=ETL_DIRECTORY_SEPARATOR;
1375 		path_to_icons+="synfigstudio";
1376 	}
1377 	path_to_icons+=ETL_DIRECTORY_SEPARATOR;
1378 	init_icons(path_to_icons);
1379 
1380 	ui_interface_=new GlobalUIInterface();
1381 
1382 	// don't call thread_init() if threads are already initialized
1383 	// on some machines bonobo_init() initialized threads before we get here
1384 	if (!g_thread_supported())
1385 		Glib::thread_init();
1386 
1387 	distance_system=Distance::SYSTEM_PIXELS;
1388 
1389 	if(mkdir(synfigapp::Main::get_user_app_directory().c_str(),ACCESSPERMS)<0)
1390 	{
1391 		if(errno!=EEXIST)
1392 			synfig::error("UNABLE TO CREATE \"%s\"",synfigapp::Main::get_user_app_directory().c_str());
1393 	}
1394 	else
1395 	{
1396 		synfig::info("Created directory \"%s\"",synfigapp::Main::get_user_app_directory().c_str());
1397 	}
1398 
1399 
1400 	ipc=new IPC();
1401 
1402 	if(!SYNFIG_CHECK_VERSION())
1403 	{
1404 		cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1405 		dialog_message_1b(
1406 			"ERROR",
1407 			_("Synfig version mismatched!"),
1408 			_("This copy of Synfig Studio was compiled against a "
1409 			"different version of libsynfig than what is currently "
1410 			"installed. Synfig Studio will now abort. Try downloading "
1411 			"the latest version from the Synfig website at "
1412 			"http://www.synfig.org/cms/en/download/"),
1413 			_("Close"));
1414 
1415 		throw 40;
1416 	}
1417 	Glib::set_application_name(_("Synfig Studio"));
1418 
1419 	Splash splash_screen;
1420 	splash_screen.show();
1421 
1422 	shutdown_in_progress=false;
1423 	SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1424 	SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1425 
1426 	// Initialize the Synfig library
1427 	try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(basepath,&synfig_init_cb)); }
1428 	catch(std::runtime_error &x)
1429 	{
1430 		get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1431 		throw;
1432 	}
1433 	catch(...)
1434 	{
1435 		get_ui_interface()->error(_("Failed to initialize synfig!"));
1436 		throw;
1437 	}
1438 
1439 
1440 	// add the preferences to the settings
1441 	synfigapp::Main::settings().add_domain(&_preferences,"pref");
1442 
1443 	try
1444 	{
1445 		// Try to load settings early to get access to some important
1446 		// values, like "enable_experimental_features".
1447 		studio_init_cb.task(_("Loading Basic Settings..."));
1448 
1449 		load_settings("pref.use_dark_theme");
1450 		App::apply_gtk_settings();
1451 
1452 		load_settings("pref.show_file_toolbar");
1453 
1454 		// Set experimental features
1455 		load_settings("pref.enable_experimental_features");
1456 
1457 		// Set main window menu and toolbar
1458 		load_settings("pref.enable_mainwin_menubar");
1459 
1460 		studio_init_cb.task(_("Loading Plugins..."));
1461 
1462 		std::string pluginsprefix;
1463 
1464 		// system plugins path
1465 #ifdef _WIN32
1466 		pluginsprefix=App::get_base_path()+ETL_DIRECTORY_SEPARATOR+PLUGIN_DIR;
1467 #else
1468 		pluginsprefix=PLUGIN_DIR;
1469 #endif
1470 		char* synfig_root=getenv("SYNFIG_ROOT");
1471 		if(synfig_root) {
1472 			pluginsprefix=std::string(synfig_root)
1473 				+ETL_DIRECTORY_SEPARATOR+"share"
1474 				+ETL_DIRECTORY_SEPARATOR+"synfig"
1475 				+ETL_DIRECTORY_SEPARATOR+"plugins";
1476 		}
1477 		plugin_manager.load_dir(pluginsprefix);
1478 
1479 		// user plugins path
1480 		pluginsprefix=Glib::build_filename(synfigapp::Main::get_user_app_directory(),"plugins");
1481 		plugin_manager.load_dir(pluginsprefix);
1482 
1483 		studio_init_cb.task(_("Init UI Manager..."));
1484 		App::ui_manager_=studio::UIManager::create();
1485 		init_ui_manager();
1486 
1487 		studio_init_cb.task(_("Init Dock Manager..."));
1488 		dock_manager=new studio::DockManager();
1489 
1490 		studio_init_cb.task(_("Init State Manager..."));
1491 		state_manager=new StateManager();
1492 
1493 		studio_init_cb.task(_("Init Main Window..."));
1494 		main_window=new studio::MainWindow();
1495 		main_window->add_accel_group(App::ui_manager_->get_accel_group());
1496 
1497 		studio_init_cb.task(_("Init Toolbox..."));
1498 		dock_toolbox=new studio::Dock_Toolbox();
1499 		dock_manager->register_dockable(*dock_toolbox);
1500 
1501 		studio_init_cb.task(_("Init About Dialog..."));
1502 		about=new studio::About();
1503 
1504 		studio_init_cb.task(_("Init Tool Options..."));
1505 		dialog_tool_options=new studio::Dialog_ToolOptions();
1506 		dock_manager->register_dockable(*dialog_tool_options);
1507 
1508 		studio_init_cb.task(_("Init History..."));
1509 		dock_history=new studio::Dock_History();
1510 		dock_manager->register_dockable(*dock_history);
1511 
1512 		studio_init_cb.task(_("Init Canvases..."));
1513 		dock_canvases=new studio::Dock_Canvases();
1514 		dock_manager->register_dockable(*dock_canvases);
1515 
1516 		studio_init_cb.task(_("Init Keyframes..."));
1517 		dock_keyframes=new studio::Dock_Keyframes();
1518 		dock_manager->register_dockable(*dock_keyframes);
1519 
1520 //! Must be done before Dock_Timetrack and Dock_Curves :
1521 //! both are connected to a studio::LayerTree::param_tree_view_'s signal, and
1522 //! studio::LayerTree is created from Dock_Layers::init_canvas_view_vfunc
1523 		studio_init_cb.task(_("Init Layers..."));
1524 		dock_layers=new studio::Dock_Layers();
1525 		dock_manager->register_dockable(*dock_layers);
1526 
1527 		studio_init_cb.task(_("Init Parameters..."));
1528 		dock_params=new studio::Dock_Params();
1529 		dock_manager->register_dockable(*dock_params);
1530 
1531 		studio_init_cb.task(_("Init MetaData..."));
1532 		dock_meta_data=new studio::Dock_MetaData();
1533 		dock_manager->register_dockable(*dock_meta_data);
1534 
1535 		studio_init_cb.task(_("Init Library..."));
1536 		dock_children=new studio::Dock_Children();
1537 		dock_manager->register_dockable(*dock_children);
1538 
1539 		studio_init_cb.task(_("Init Info..."));
1540 		dock_info = new studio::Dock_Info();
1541 		dock_manager->register_dockable(*dock_info);
1542 
1543 		studio_init_cb.task(_("Init Navigator..."));
1544 		dock_navigator = new studio::Dock_Navigator();
1545 		dock_manager->register_dockable(*dock_navigator);
1546 
1547 		studio_init_cb.task(_("Init Timetrack..."));
1548 		dock_timetrack = new studio::Dock_Timetrack();
1549 		dock_manager->register_dockable(*dock_timetrack);
1550 
1551 		studio_init_cb.task(_("Init Curve Editor..."));
1552 		dock_curves = new studio::Dock_Curves();
1553 		dock_manager->register_dockable(*dock_curves);
1554 
1555 		studio_init_cb.task(_("Init Layer Sets..."));
1556 		dock_layer_groups = new studio::Dock_LayerGroups();
1557 		dock_manager->register_dockable(*dock_layer_groups);
1558 
1559 
1560 		studio_init_cb.task(_("Init Color Dialog..."));
1561 		dialog_color=new studio::Dialog_Color();
1562 
1563 		studio_init_cb.task(_("Init Gradient Dialog..."));
1564 		dialog_gradient=new studio::Dialog_Gradient();
1565 
1566 		studio_init_cb.task(_("Init DeviceTracker..."));
1567 		device_tracker=new studio::DeviceTracker();
1568 
1569 		//Init Tools...was here
1570 
1571 		studio_init_cb.task(_("Init ModPalette..."));
1572 		module_list_.push_back(new ModPalette()); module_list_.back()->start();
1573 
1574 		studio_init_cb.task(_("Init Setup Dialog..."));
1575 		dialog_setup=new studio::Dialog_Setup(*App::main_window);
1576 
1577 		studio_init_cb.task(_("Init Input Dialog..."));
1578 		dialog_input=new studio::Dialog_Input(*App::main_window);
1579 		dialog_input->signal_apply().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1580 
1581 		studio_init_cb.task(_("Init auto recovery..."));
1582 		auto_recover=new AutoRecover();
1583 
1584 		studio_init_cb.amount_complete(9250,10000);
1585 		studio_init_cb.task(_("Loading Settings..."));
1586 		load_accel_map();
1587 		if (!load_settings())
1588 		{
1589 			gamma.set_gamma(1.0/2.2);
1590 			set_workspace_default();
1591 		}
1592 		load_file_window_size();
1593 
1594 		// Init Tools must be done after load_accel_map() : accelerators keys
1595 		// are displayed in toolbox labels
1596 		studio_init_cb.task(_("Init Tools..."));
1597 		/* editing tools */
1598 		state_manager->add_state(&state_normal);
1599 		state_manager->add_state(&state_smooth_move);
1600 		state_manager->add_state(&state_scale);
1601 		state_manager->add_state(&state_rotate);
1602 		state_manager->add_state(&state_mirror);
1603 
1604 		/* geometry */
1605 		state_manager->add_state(&state_circle);
1606 		state_manager->add_state(&state_rectangle);
1607 		state_manager->add_state(&state_star);
1608 		if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1609 		state_manager->add_state(&state_gradient);
1610 
1611 		/* bline tools */
1612 		state_manager->add_state(&state_bline);
1613 		if(!getenv("SYNFIG_DISABLE_DRAW"   )) state_manager->add_state(&state_draw ); // Enabled for now.  Let's see whether they're good enough yet.
1614                 state_manager->add_state(&state_lasso); // Enabled for now.  Let's see whether they're good enough yet.
1615 		if(!getenv("SYNFIG_DISABLE_WIDTH"  )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1616 		state_manager->add_state(&state_fill);
1617 		state_manager->add_state(&state_eyedrop);
1618 
1619 		/* other */
1620 		state_manager->add_state(&state_text);
1621 		if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1622 		if(!getenv("SYNFIG_DISABLE_BRUSH"  )) state_manager->add_state(&state_brush);
1623 		state_manager->add_state(&state_zoom);
1624 
1625 
1626 		device_tracker->load_preferences();
1627 		// If the default bline width is modified before focus a canvas
1628 		// window, the Distance widget doesn't understand the given value
1629 		// and produces this message:
1630 		// Distance::ident_system(): Unknown distance system ".00pt"
1631 		// setting the default bline width to 1 unit.
1632 		// This line fixes that.
1633 		synfigapp::Main::set_bline_width(synfigapp::Main::get_selected_input_device()->get_bline_width());
1634 
1635 		studio_init_cb.task(_("Checking auto-recover..."));
1636 
1637 		studio_init_cb.amount_complete(9900,10000);
1638 
1639 		bool opened_any = false;
1640 		if (!getenv("SYNFIG_DISABLE_AUTO_RECOVERY") && auto_recover->recovery_needed())
1641 		{
1642 			splash_screen.hide();
1643 			if (get_ui_interface()->confirmation(
1644 					_("Auto recovery file(s) found. Do you want to recover unsaved changes?"),
1645 					_("Synfig Studio seems to have crashed before you could save all your files."),
1646 					_("Ignore"),
1647 					_("Recover")
1648 				) == synfigapp::UIInterface::RESPONSE_OK)
1649 			{
1650 				int number_recovered;
1651 				if(!auto_recover->recover(number_recovered))
1652 					if (number_recovered)
1653 						get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1654 					else
1655 						get_ui_interface()->error(_("Unable to recover from previous crash"));
1656 				else
1657 					dialog_message_1b(
1658 						"WARNING",
1659 						_("It would be a good idea to review and save recovered files now."),
1660 						_("Synfig Studio has attempted to recover from a previous crash. "
1661 						"The files just recovered are NOT YET SAVED."),
1662 						_("Thanks"));
1663 
1664 				if (number_recovered)
1665 					opened_any = true;
1666 			}
1667 			else
1668 			{
1669 				auto_recover->clear_backups();
1670 			}
1671 			splash_screen.show();
1672 		}
1673 
1674 		// Look for any files given on the command line,
1675 		// and load them if found.
1676 		for(;*argc>=1;(*argc)--)
1677 			if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1678 			{
1679 				studio_init_cb.task(_("Loading files..."));
1680 				splash_screen.hide();
1681 				open((*argv)[*argc]);
1682 				opened_any = true;
1683 				splash_screen.show();
1684 			}
1685 
1686 		// if no file was specified to be opened, create a new document to help new users get started more easily
1687 		if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1688 			new_instance();
1689 
1690 		studio_init_cb.task(_("Done."));
1691 		studio_init_cb.amount_complete(10000,10000);
1692 
1693 		// To avoid problems with some window managers and gtk >= 2.18
1694 		// we should show dock dialogs after the settings load.
1695 		// If dock dialogs are shown before the settings are loaded,
1696 		// the windows manager can act over it.
1697 		// See discussions here:
1698 		// * http://synfig.org/forums/viewtopic.php?f=1&t=1131&st=0&sk=t&sd=a&start=30
1699 		// * http://synfig.org/forums/viewtopic.php?f=15&t=1062
1700 		dock_manager->show_all_dock_dialogs();
1701 
1702 		main_window->present();
1703 		dock_toolbox->present();
1704 
1705 		splash_screen.hide();
1706 
1707 		String message;
1708 		String details;
1709 		/*
1710 		if (App::enable_experimental_features) {
1711 			message = _("Following experimental features are enabled: ");
1712 			message += ("Skeleton Layer");
1713 			detials = _("The experimental features are NOT intended for production use. "
1714 					"It is quite posiible their functionality will change in the "
1715 					"future versions, which can break compatibility for your "
1716 					"files. Use for testing purposes only. You can disable "
1717 					"experimental features on the \"Misc\" tab of Setup dialog.");
1718 		}
1719 		*/
1720 #ifdef _WIN32
1721 		if (message!=""){
1722 			message = _("There is a bug, which can cause computer to hang/freeze when "
1723 					"resizing the canvas window.");
1724 			details = _("If you got affected by this issue, consider pressing ALT+TAB "
1725 					"to unfreeze your system and get it back to the working "
1726 					"state. Please accept our apologies for inconvenience, we "
1727 					"hope to get this issue resolved in the future versions.");
1728 		}
1729 #endif
1730 		if (message!="")
1731 			dialog_message_1b("WARNING",
1732 					message,
1733 					details,
1734 					_("Got it"));
1735 	}
1736 	catch(String &x)
1737 	{
1738 		get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1739 	}
1740 	catch(...)
1741 	{
1742 		get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1743 	}
1744 }
1745 
get_state_manager()1746 StateManager* App::get_state_manager() { return state_manager; }
1747 
~App()1748 App::~App()
1749 {
1750 	shutdown_in_progress=true;
1751 
1752 	save_settings();
1753 
1754 	synfigapp::Main::settings().remove_domain("pref");
1755 
1756 	selected_instance=0;
1757 
1758 	// Unload all of the modules
1759 	for(;!module_list_.empty();module_list_.pop_back())
1760 		;
1761 
1762 	delete state_manager;
1763 
1764 	delete ipc;
1765 
1766 	delete auto_recover;
1767 
1768 	delete about;
1769 
1770 	main_window->hide();
1771 
1772 	delete main_window;
1773 
1774 	delete dialog_setup;
1775 
1776 	delete dialog_gradient;
1777 
1778 	delete dialog_color;
1779 
1780 	delete dialog_input;
1781 
1782 	delete dock_manager;
1783 
1784 	instance_list.clear();
1785 }
1786 
1787 synfig::String
get_config_file(const synfig::String & file)1788 App::get_config_file(const synfig::String& file)
1789 {
1790 	return Glib::build_filename(synfigapp::Main::get_user_app_directory(),file);
1791 }
1792 
1793 void
add_recent_file(const etl::handle<Instance> instance)1794 App::add_recent_file(const etl::handle<Instance> instance)
1795 {
1796 	add_recent_file(absolute_path(instance->get_file_name()));
1797 }
1798 
1799 void
add_recent_file(const std::string & file_name)1800 App::add_recent_file(const std::string &file_name)
1801 {
1802 	std::string filename(file_name);
1803 
1804 	assert(!filename.empty());
1805 
1806 	if(filename.empty())
1807 		return;
1808 
1809 	// Toss out any "hidden" files
1810 	if(basename(filename)[0]=='.')
1811 		return;
1812 
1813 	// If we aren't an absolute path, turn ourselves into one
1814 	if(!is_absolute_path(filename))
1815 		filename=absolute_path(filename);
1816 
1817 	list<string>::iterator iter;
1818 	// Check to see if the file is already on the list.
1819 	// If it is, then remove it from the list
1820 	for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1821 		if(*iter==filename)
1822 		{
1823 			recent_files.erase(iter);
1824 			break;
1825 		}
1826 
1827 
1828 	// Push the filename to the front of the list
1829 	recent_files.push_front(filename);
1830 
1831 	// Clean out the files at the end of the list.
1832 	while(recent_files.size()>(unsigned)get_max_recent_files())
1833 	{
1834 		recent_files.pop_back();
1835 	}
1836 
1837 	signal_recent_files_changed_();
1838 
1839 	return;
1840 }
1841 
1842 static Time::Format _App_time_format(Time::FORMAT_FRAMES);
1843 
jack_is_locked()1844 bool App::jack_is_locked()
1845 {
1846 	return jack_locks_ > 0;
1847 }
1848 
jack_lock()1849 void App::jack_lock()
1850 {
1851 	++jack_locks_;
1852 	if (jack_locks_ == 1)
1853 	{
1854 		// lock jack in instances
1855 		for(std::list< etl::handle<Instance> >::const_iterator i = instance_list.begin(); i != instance_list.end(); ++i)
1856 		{
1857 			const Instance::CanvasViewList &views = (*i)->canvas_view_list();
1858 			for(Instance::CanvasViewList::const_iterator j = views.begin(); j != views.end(); ++j)
1859 				(*j)->jack_lock();
1860 		}
1861 	}
1862 }
1863 
jack_unlock()1864 void App::jack_unlock()
1865 {
1866 	--jack_locks_;
1867 	assert(jack_locks_ >= 0);
1868 	if (jack_locks_ == 0)
1869 	{
1870 		// unlock jack in instances
1871 		for(std::list< etl::handle<Instance> >::const_iterator i = instance_list.begin(); i != instance_list.end(); ++i)
1872 		{
1873 			const Instance::CanvasViewList &views = (*i)->canvas_view_list();
1874 			for(Instance::CanvasViewList::const_iterator j = views.begin(); j != views.end(); ++j)
1875 				(*j)->jack_unlock();
1876 		}
1877 	}
1878 }
1879 
1880 
1881 Time::Format
get_time_format()1882 App::get_time_format()
1883 {
1884 	return _App_time_format;
1885 }
1886 
1887 void
set_time_format(synfig::Time::Format x)1888 App::set_time_format(synfig::Time::Format x)
1889 {
1890 	_App_time_format=x;
1891 }
1892 
1893 
1894 void
save_settings()1895 App::save_settings()
1896 {
1897 	try
1898 	{
1899 		synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
1900 		{
1901 			std::string filename=get_config_file("accelrc");
1902 			Gtk::AccelMap::save(filename);
1903 		}
1904 		{
1905 			std::string filename=get_config_file("language");
1906 
1907 			std::ofstream file(filename.c_str());
1908 
1909 			if(!file)
1910 			{
1911 				synfig::warning("Unable to save %s",filename.c_str());
1912 			} else {
1913 				file<<App::ui_language.c_str()<<endl;
1914 			}
1915 		}
1916 		do{
1917 			std::string filename=get_config_file("recentfiles");
1918 
1919 			std::ofstream file(filename.c_str());
1920 
1921 			if(!file)
1922 			{
1923 				synfig::warning("Unable to save %s",filename.c_str());
1924 				break;
1925 			}
1926 
1927 			list<string>::reverse_iterator iter;
1928 
1929 			for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1930 				file<<(*iter).c_str()<<endl;
1931 		}while(0);
1932 		std::string filename=get_config_file("settings-1.0");
1933 		synfigapp::Main::settings().save_to_file(filename);
1934 
1935 	}
1936 	catch(...)
1937 	{
1938 		synfig::warning("Caught exception when attempting to save settings.");
1939 	}
1940 }
1941 
1942 bool
load_settings(const synfig::String & key_filter)1943 App::load_settings(const synfig::String& key_filter)
1944 {
1945 	bool ret=false;
1946 	try
1947 	{
1948 		synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
1949 		std::string filename=get_config_file("settings-1.0");
1950 		ret=synfigapp::Main::settings().load_from_file(filename, key_filter);
1951 	}
1952 	catch(...)
1953 	{
1954 		synfig::warning("Caught exception when attempting to load settings.");
1955 	}
1956 	return ret;
1957 }
1958 
1959 void
load_accel_map()1960 App::load_accel_map()
1961 {
1962 	try
1963 	{
1964 		synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
1965 		{
1966 			std::string filename=get_config_file("accelrc");
1967 			Gtk::AccelMap::load(filename);
1968 		}
1969 	}
1970 	catch(...)
1971 	{
1972 		synfig::warning("Caught exception when attempting to load accel map settings.");
1973 	}
1974 }
1975 
1976 void
load_file_window_size()1977 App::load_file_window_size()
1978 {
1979 	try
1980 	{
1981 		synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
1982 		{
1983 			std::string filename=get_config_file("recentfiles");
1984 			std::ifstream file(filename.c_str());
1985 
1986 			while(file)
1987 			{
1988 				std::string recent_file;
1989 				std::string recent_file_window_size;
1990 				getline(file,recent_file);
1991 				if(!recent_file.empty() && FileSystemNative::instance()->is_file(recent_file))
1992 					add_recent_file(recent_file);
1993 			}
1994 		}
1995 
1996 	}
1997 	catch(...)
1998 	{
1999 		synfig::warning("Caught exception when attempting to load window settings.");
2000 	}
2001 }
2002 
2003 void
load_language_settings()2004 App::load_language_settings()
2005 {
2006 	try
2007 	{
2008 		synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
2009 		{
2010 			std::string filename=get_config_file("language");
2011 			std::ifstream file(filename.c_str());
2012 
2013 			while(file)
2014 			{
2015 				std::string language;
2016 				getline(file,language);
2017 				if(!language.empty())
2018 					App::ui_language=language;
2019 			}
2020 		}
2021 
2022 	}
2023 	catch(...)
2024 	{
2025 		synfig::warning("Caught exception when attempting to loading language settings.");
2026 	}
2027 }
2028 
2029 void
set_workspace_default()2030 App::set_workspace_default()
2031 {
2032 	Glib::RefPtr<Gdk::Display> display(Gdk::Display::get_default());
2033 	Glib::RefPtr<const Gdk::Screen> screen(display->get_default_screen());
2034 	Gdk::Rectangle rect;
2035 	// A proper way to obtain the primary monitor is to use the
2036 	// Gdk::Screen::get_primary_monitor () const member. But as it
2037 	// was introduced in gtkmm 2.20 I assume that the monitor 0 is the
2038 	// primary one.
2039 	screen->get_monitor_geometry(0,rect);
2040 	float dx = (float)rect.get_x();
2041 	float dy = (float)rect.get_y();
2042 	float sx = (float)rect.get_width();
2043 	float sy = (float)rect.get_height();
2044 
2045 	std::string tpl =
2046 	"[mainwindow|%0X|%0Y|%100x|%90y|"
2047 		"[hor|%75x"
2048 			"|[vert|%70y"
2049 				"|[hor|%10x"
2050 					"|[book|toolbox]"
2051 					"|[mainnotebook]"
2052 				"]"
2053 				"|[hor|%25x"
2054 					"|[book|params|keyframes]"
2055 					"|[book|timetrack|curves|children|meta_data]"
2056 				"]"
2057 			"]"
2058 			"|[vert|%20y"
2059 				"|[book|canvases|pal_edit|navigator|info]"
2060 				"|[vert|%25y"
2061 					"|[book|tool_options|history]"
2062                                         "|[book|layers|groups]"
2063 				"]"
2064 			"]"
2065 		"]"
2066 	"]";
2067 
2068 	std::string layout = DockManager::layout_from_template(tpl, dx, dy, sx, sy);
2069 	dock_manager->load_layout_from_string(layout);
2070 	dock_manager->show_all_dock_dialogs();
2071 }
2072 
2073 void
set_workspace_compositing()2074 App::set_workspace_compositing()
2075 {
2076 	Glib::RefPtr<Gdk::Display> display(Gdk::Display::get_default());
2077 	Glib::RefPtr<const Gdk::Screen> screen(display->get_default_screen());
2078 	Gdk::Rectangle rect;
2079 	// A proper way to obtain the primary monitor is to use the
2080 	// Gdk::Screen::get_primary_monitor () const member. But as it
2081 	// was introduced in gtkmm 2.20 I assume that the monitor 0 is the
2082 	// primary one.
2083 	screen->get_monitor_geometry(0,rect);
2084 	float dx = (float)rect.get_x();
2085 	float dy = (float)rect.get_y();
2086 	float sx = (float)rect.get_width();
2087 	float sy = (float)rect.get_height();
2088 
2089 	std::string tpl =
2090 	"[mainwindow|%0X|%0Y|%100x|%90y|"
2091 		"[hor|%1x"
2092 			"|[vert|%1y|[book|toolbox]|[book|tool_options]]"
2093 			"|[hor|%60x|[mainnotebook]"
2094 				"|[hor|%50x|[book|params]"
2095 					"|[vert|%30y|[book|history|groups]|[book|layers|canvases]]"
2096 			"]"
2097 		"]"
2098 	"]";
2099 
2100 	std::string layout = DockManager::layout_from_template(tpl, dx, dy, sx, sy);
2101 	dock_manager->load_layout_from_string(layout);
2102 	dock_manager->show_all_dock_dialogs();
2103 }
2104 
2105 void
set_workspace_animating()2106 App::set_workspace_animating()
2107 {
2108 	Glib::RefPtr<Gdk::Display> display(Gdk::Display::get_default());
2109 	Glib::RefPtr<const Gdk::Screen> screen(display->get_default_screen());
2110 	Gdk::Rectangle rect;
2111 	// A proper way to obtain the primary monitor is to use the
2112 	// Gdk::Screen::get_primary_monitor () const member. But as it
2113 	// was introduced in gtkmm 2.20 I assume that the monitor 0 is the
2114 	// primary one.
2115 	screen->get_monitor_geometry(0,rect);
2116 	float dx = (float)rect.get_x();
2117 	float dy = (float)rect.get_y();
2118 	float sx = (float)rect.get_width();
2119 	float sy = (float)rect.get_height();
2120 
2121 	std::string tpl =
2122 	"[mainwindow|%0X|%0Y|%100x|%90y|"
2123 		"[hor|%70x"
2124 			"|[vert|%1y"
2125 				"|[hor|%1x|[book|toolbox]|[mainnotebook]]"
2126 				"|[hor|%25x|[book|params|children]|[book|timetrack|curves]]"
2127 			"]"
2128 			"|[vert|%30y"
2129 				"|[book|keyframes|history|groups]|[book|layers|canvases]]"
2130 			"]"
2131 		"]"
2132 	"]";
2133 
2134 	std::string layout = DockManager::layout_from_template(tpl, dx, dy, sx, sy);
2135 	dock_manager->load_layout_from_string(layout);
2136 	dock_manager->show_all_dock_dialogs();
2137 }
2138 
2139 
2140 void
restore_default_settings()2141 App::restore_default_settings()
2142 {
2143 	// TODO autorecover default auto_recover_backup_interval
2144 	synfigapp::Main::settings().set_value("pref.distance_system","pt");
2145 	synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
2146 #ifdef SINGLE_THREADED
2147 	synfigapp::Main::settings().set_value("pref.use_single_threaded","1");
2148 #endif
2149 	synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","1");
2150 	synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
2151 	synfigapp::Main::settings().set_value("pref.enable_experimental_features","0");
2152 	synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
2153 	synfigapp::Main::settings().set_value("pref.ui_language", "os_LANG");
2154 	synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
2155 	synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
2156 	synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
2157 	synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
2158 	synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
2159 	synfigapp::Main::settings().set_value("sequence_separator", ".");
2160 	synfigapp::Main::settings().set_value("navigator_renderer", "");
2161 	synfigapp::Main::settings().set_value("workarea_renderer", "");
2162 	synfigapp::Main::settings().set_value("pref.enable_mainwin_menubar", "1");
2163 	ostringstream temp;
2164 	temp << Duck::STRUCT_DEFAULT;
2165 	synfigapp::Main::settings().set_value("pref.ui_handle_tooltip_flag", temp.str());
2166 	synfigapp::Main::settings().set_value("pref.auto_recover_backup", "1");
2167 }
2168 
2169 void
apply_gtk_settings()2170 App::apply_gtk_settings()
2171 {
2172 	GtkSettings *gtk_settings;
2173 	gtk_settings = gtk_settings_get_default ();
2174 
2175 	gchar *theme_name=getenv("SYNFIG_GTK_THEME");
2176 	if(theme_name) {
2177 		g_object_set (G_OBJECT (gtk_settings), "gtk-theme-name", theme_name, NULL);
2178 	}
2179 
2180 	// dark theme
2181 	g_object_set (G_OBJECT (gtk_settings), "gtk-application-prefer-dark-theme", App::use_dark_theme, NULL);
2182 
2183 	// enable menu icons
2184 	g_object_set (G_OBJECT (gtk_settings), "gtk-menu-images", TRUE, NULL);
2185 
2186 	// fix CSS
2187 	Glib::ustring data;
2188 	// Fix GtkPaned (big margin makes it hard to grab first keyframe))
2189 	data += "GtkPaned { margin: 2px; }\n";
2190 	// Fix #348: Synfig's Interface went Too Thick
2191 	// following css works for gtk 3.14:
2192 	data += ".button                            { padding-left: 4px; padding-right: 4px; }\n";
2193 	data += ".button                            { padding-top: 0px; padding-bottom: 0px; }\n";
2194 	data += ".button *                          { padding-top: 4px; padding-bottom: 4px; }\n";
2195 	data += ".button > GtkBox                   { padding-top: 0px; padding-bottom: 0px; }\n";
2196 	data += ".button > GtkBox > *               { padding-top: 4px; padding-bottom: 4px; }\n";
2197 	data += ".button > GtkLabel                 { padding-top: 0px; padding-bottom: 0px; }\n";
2198 	data += "GtkComboBox > .button > GtkBox > * { padding-top: 0px; padding-bottom: 0px; }\n";
2199 	data += ".entry                             { padding-top: 0px; padding-bottom: 0px; }\n";
2200 	// following css works for gtk 3.22:
2201 #ifdef __APPLE__
2202 	// This is a temporary fix as we do not have gtk 3.22 on OSX build yet --KD
2203 	data += "button { padding: 0px; }\n";
2204 #else
2205 	data += "button { min-height: 16px; min-width: 16px; padding: 0px; }\n";
2206 #endif
2207 	data += "button > box { padding: 5px; }\n";
2208 	data += "button > image { padding: 5px; }\n";
2209 #ifndef __APPLE__
2210 	// This is a temporary fix as we do not have gtk 3.22 on OSX build yet --KD
2211 	data += "entry, spinbutton { min-height: 16px; }\n";
2212 #endif
2213 	data += "combobox > box > button > box { padding-top: 0px; padding-bottom: 0px; }\n";
2214 	// Fix #810: Insetsetive context menus on OSX
2215 	g_object_get (G_OBJECT (gtk_settings), "gtk-theme-name", &theme_name, NULL);
2216 	if ( String(theme_name) == "Adwaita" )
2217 		data += ".window-frame, .window-frame:backdrop { box-shadow: none; margin: 0; }\n";
2218 	if (!data.empty()) {
2219 		Glib::RefPtr<Gtk::CssProvider> css = Gtk::CssProvider::create();
2220 		try {
2221 			css->load_from_data(data);
2222 		} catch (Gtk::CssProviderError &e) {
2223 			synfig::warning("Failed to load css rules. %s", e.what().c_str());
2224 		}
2225 		Glib::RefPtr<Gdk::Screen> screen = Gdk::Screen::get_default();
2226 		Gtk::StyleContext::add_provider_for_screen(screen,css, GTK_STYLE_PROVIDER_PRIORITY_USER);
2227 	}
2228 }
2229 
2230 bool
shutdown_request(GdkEventAny *)2231 App::shutdown_request(GdkEventAny*)
2232 {
2233 	quit();
2234 	return true;
2235 	//return !shutdown_in_progress;
2236 }
2237 
2238 void
quit()2239 App::quit()
2240 {
2241 	if(shutdown_in_progress)return;
2242 
2243 	get_ui_interface()->task(_("Quit Request"));
2244 	if(Busy::count)
2245 	{
2246 		dialog_message_1b(
2247 			"ERROR",
2248 			_("Tasks are currently running. Please cancel the current tasks and try again"),
2249 			"details",
2250 			_("Close"));
2251 
2252 		return;
2253 	}
2254 
2255 	std::list<etl::handle<Instance> >::iterator iter;
2256 	for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
2257 	{
2258 		if(!(*iter)->safe_close())
2259 			return;
2260 
2261 /*
2262 		if((*iter)->synfigapp::Instance::get_action_count())
2263 		{
2264 			handle<synfigapp::UIInterface> uim;
2265 			uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
2266 			assert(uim);
2267 			string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
2268 			switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
2269 			{
2270 				case synfigapp::UIInterface::RESPONSE_NO:
2271 					break;
2272 				case synfigapp::UIInterface::RESPONSE_YES:
2273 					(*iter)->save();
2274 					break;
2275 				case synfigapp::UIInterface::RESPONSE_CANCEL:
2276 					return;
2277 				default:
2278 					assert(0);
2279 					return;
2280 			}
2281 		}
2282 
2283 
2284 		if((*iter)->synfigapp::Instance::is_modified())
2285 		{
2286 			handle<synfigapp::UIInterface> uim;
2287 			uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
2288 			assert(uim);
2289 			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() );
2290 			switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
2291 			{
2292 				case synfigapp::UIInterface::RESPONSE_NO:
2293 					break;
2294 				case synfigapp::UIInterface::RESPONSE_YES:
2295 					(*iter)->dialog_cvs_commit();
2296 					break;
2297 				case synfigapp::UIInterface::RESPONSE_CANCEL:
2298 					return;
2299 				default:
2300 					assert(0);
2301 					return;
2302 			}
2303 		}
2304 */
2305 
2306 		// This next line causes things to crash for some reason
2307 		//(*iter)->close();
2308 	}
2309 
2310 	instance_list.clear();
2311 
2312 	while(studio::App::events_pending())studio::App::iteration(false);
2313 
2314 	Gtk::Main::quit();
2315 
2316 	get_ui_interface()->task(_("Quit Request sent"));
2317 }
2318 
2319 void
show_setup()2320 App::show_setup()
2321 {
2322 	dialog_setup->refresh();
2323 	dialog_setup->show();
2324 }
2325 
Signal_Open_Ok(GtkWidget *,int * val)2326 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
Signal_Open_Cancel(GtkWidget *,int * val)2327 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
2328 
2329 //#ifdef _WIN32
2330 //#define USE_WIN32_FILE_DIALOGS 1
2331 //#endif
2332 
2333 #ifdef USE_WIN32_FILE_DIALOGS
2334 static OPENFILENAME ofn={};
2335 #endif
2336 
2337 #ifdef _WIN32
2338 #include <gdk/gdkwin32.h>
2339 #endif
2340 
2341 bool
dialog_open_file(const std::string & title,std::string & filename,std::string preference)2342 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
2343 {
2344 	// info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2345 	// TODO: Win32 native dialod not ready yet
2346 #ifdef USE_WIN32_FILE_DIALOGS
2347 	static TCHAR szFilter[] = TEXT (_("All Files (*.*)\0*.*\0\0")) ;
2348 
2349 	GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2350 	HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2351 	HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2352 
2353 	ofn.lStructSize=sizeof(OPENFILENAME);
2354 	ofn.hwndOwner = hWnd;
2355 	ofn.hInstance = hInstance;
2356 	ofn.lpstrFilter = szFilter;
2357 //	ofn.lpstrCustomFilter=NULL;
2358 //	ofn.nMaxCustFilter=0;
2359 //	ofn.nFilterIndex=0;
2360 //	ofn.lpstrFile=NULL;
2361 	ofn.nMaxFile=MAX_PATH;
2362 //	ofn.lpstrFileTitle=NULL;
2363 //	ofn.lpstrInitialDir=NULL;
2364 //	ofn.lpstrTitle=NULL;
2365 	ofn.Flags=OFN_HIDEREADONLY;
2366 //	ofn.nFileOffset=0;
2367 //	ofn.nFileExtension=0;
2368 	ofn.lpstrDefExt=TEXT("sif");
2369 //	ofn.lCustData = 0l;
2370 	ofn.lpfnHook=NULL;
2371 //	ofn.lpTemplateName=NULL;
2372 
2373 	CHAR szFilename[MAX_PATH];
2374 	CHAR szTitle[500];
2375 	strcpy(szFilename,filename.c_str());
2376 	strcpy(szTitle,title.c_str());
2377 
2378 	ofn.lpstrFile=szFilename;
2379 	ofn.lpstrFileTitle=szTitle;
2380 
2381 	if(GetOpenFileName(&ofn))
2382 	{
2383 		filename=szFilename;
2384 		return true;
2385 	}
2386 	return false;
2387 
2388 #else   // not USE_WIN32_FILE_DIALOGS
2389 	synfig::String prev_path;
2390 
2391 	if(!_preferences.get_value(preference, prev_path))
2392 		prev_path = Glib::get_home_dir();
2393 	prev_path = absolute_path(prev_path);
2394 
2395 	Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(*App::main_window,
2396 				title, Gtk::FILE_CHOOSER_ACTION_OPEN);
2397 
2398 	dialog->set_transient_for(*App::main_window);
2399 	dialog->set_current_folder(prev_path);
2400 	dialog->add_button(_("Cancel"), Gtk::RESPONSE_CANCEL)->set_image_from_icon_name("gtk-cancel", Gtk::ICON_SIZE_BUTTON);
2401 	dialog->add_button(_("Import"),   Gtk::RESPONSE_ACCEPT)->set_image_from_icon_name("gtk-open", Gtk::ICON_SIZE_BUTTON);
2402 
2403 	// 0 All supported files
2404 	// 0.1 Synfig documents. sfg is not supported to import
2405 	Glib::RefPtr<Gtk::FileFilter> filter_supported = Gtk::FileFilter::create();
2406 	filter_supported->set_name(_("All supported files"));
2407 	filter_supported->add_mime_type("application/x-sif");
2408 	filter_supported->add_pattern("*.sif");
2409 	filter_supported->add_pattern("*.sifz");
2410 	// 0.2 Image files
2411 	filter_supported->add_mime_type("image/png");
2412 	filter_supported->add_mime_type("image/jpeg");
2413 	filter_supported->add_mime_type("image/jpg");
2414 	filter_supported->add_mime_type("image/bmp");
2415 	filter_supported->add_mime_type("image/svg+xml");
2416 	filter_supported->add_pattern("*.png");
2417 	filter_supported->add_pattern("*.jpeg");
2418 	filter_supported->add_pattern("*.jpg");
2419 	filter_supported->add_pattern("*.bmp");
2420 	filter_supported->add_pattern("*.svg");
2421 	filter_supported->add_pattern("*.lst");
2422 	// 0.3 Audio files
2423 	filter_supported->add_mime_type("audio/x-vorbis+ogg");
2424 	filter_supported->add_mime_type("audio/mpeg");
2425 	filter_supported->add_mime_type("audio/x-wav");
2426 	filter_supported->add_pattern("*.ogg");
2427 	filter_supported->add_pattern("*.mp3");
2428 	filter_supported->add_pattern("*.wav");
2429 	// 0.4 lipsync files
2430 	filter_supported->add_pattern("*.pgo");
2431 
2432 	// Sub fileters
2433 	// 1 Synfig documents. sfg is not supported to import
2434 	Glib::RefPtr<Gtk::FileFilter> filter_synfig = Gtk::FileFilter::create();
2435 	filter_synfig->set_name(_("Synfig files (*.sif, *.sifz)"));
2436 	filter_synfig->add_mime_type("application/x-sif");
2437 	filter_synfig->add_pattern("*.sif");
2438 	filter_synfig->add_pattern("*.sifz");
2439 
2440 	// 2.1 Image files
2441 	Glib::RefPtr<Gtk::FileFilter> filter_image = Gtk::FileFilter::create();
2442 	filter_image->set_name(_("Images (*.png, *.jpeg, *.bmp, *.svg)"));
2443 	filter_image->add_mime_type("image/png");
2444 	filter_image->add_mime_type("image/jpeg");
2445 	filter_image->add_mime_type("image/jpg");
2446 	filter_image->add_mime_type("image/bmp");
2447 	filter_image->add_mime_type("image/svg+xml");
2448 	filter_image->add_pattern("*.png");
2449 	filter_image->add_pattern("*.jpeg");
2450 	filter_image->add_pattern("*.jpg");
2451 	filter_image->add_pattern("*.bmp");
2452 	filter_image->add_pattern("*.svg");
2453 
2454 	// 2.2 Image sequence/list files
2455 	Glib::RefPtr<Gtk::FileFilter> filter_image_list = Gtk::FileFilter::create();
2456 	filter_image_list->set_name(_("Image sequence files (*.lst)"));
2457 	filter_image_list->add_pattern("*.lst");
2458 
2459 	// 3 Audio files
2460 	Glib::RefPtr<Gtk::FileFilter> filter_audio = Gtk::FileFilter::create();
2461 	filter_audio->set_name(_("Audio (*.ogg, *.mp3, *.wav)"));
2462 	filter_audio->add_mime_type("audio/x-vorbis+ogg");
2463 	filter_audio->add_mime_type("audio/mpeg");
2464 	filter_audio->add_mime_type("audio/x-wav");
2465 	filter_audio->add_pattern("*.ogg");
2466 	filter_audio->add_pattern("*.mp3");
2467 	filter_audio->add_pattern("*.wav");
2468 
2469 	// 4 Lipsync files
2470 	Glib::RefPtr<Gtk::FileFilter> filter_lipsync = Gtk::FileFilter::create();
2471 	filter_lipsync->set_name(_("Lipsync (*.pgo)"));
2472 	filter_lipsync->add_pattern("*.pgo");
2473 
2474 	// 5 Any files
2475 	Glib::RefPtr<Gtk::FileFilter> filter_any = Gtk::FileFilter::create();
2476 	filter_any->set_name(_("Any files"));
2477 	filter_any->add_pattern("*");
2478 
2479 	dialog->add_filter(filter_supported);
2480 	dialog->add_filter(filter_synfig);
2481 	dialog->add_filter(filter_image);
2482 	dialog->add_filter(filter_image_list);
2483 	dialog->add_filter(filter_audio);
2484 	dialog->add_filter(filter_lipsync);
2485 	dialog->add_filter(filter_any);
2486 
2487 	if (filename.empty())
2488 		dialog->set_filename(prev_path);
2489 	else if (is_absolute_path(filename))
2490 		dialog->set_filename(filename);
2491 	else
2492 		dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
2493 
2494 	if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2495 		filename = dialog->get_filename();
2496 		// info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
2497 		_preferences.set_value(preference, dirname(filename));
2498 		delete dialog;
2499 		return true;
2500 	}
2501 
2502 	delete dialog;
2503 	return false;
2504 #endif   // not USE_WIN32_FILE_DIALOGS
2505 }
2506 
2507 
2508 bool
dialog_open_file_spal(const std::string & title,std::string & filename,std::string preference)2509 App::dialog_open_file_spal(const std::string &title, std::string &filename, std::string preference)
2510 {
2511 	synfig::String prev_path;
2512 
2513 	if(!_preferences.get_value(preference, prev_path))
2514 		prev_path = Glib::get_home_dir();
2515 	prev_path = absolute_path(prev_path);
2516 
2517 	Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(*App::main_window,
2518 				title, Gtk::FILE_CHOOSER_ACTION_OPEN);
2519 
2520 	dialog->set_transient_for(*App::main_window);
2521 	dialog->set_current_folder(prev_path);
2522 	dialog->add_button(_("Cancel"), Gtk::RESPONSE_CANCEL)->set_image_from_icon_name("gtk-cancel", Gtk::ICON_SIZE_BUTTON);
2523 	dialog->add_button(_("Load"),   Gtk::RESPONSE_ACCEPT)->set_image_from_icon_name("gtk-open", Gtk::ICON_SIZE_BUTTON);
2524 
2525 	Glib::RefPtr<Gtk::FileFilter> filter_supported = Gtk::FileFilter::create();
2526 	filter_supported->set_name(_("Palette files (*.spal, *.gpl)"));
2527 	filter_supported->add_pattern("*.spal");
2528 	filter_supported->add_pattern("*.gpl");
2529 	dialog->add_filter(filter_supported);
2530 
2531 	// show only Synfig color palette file (*.spal)
2532 	Glib::RefPtr<Gtk::FileFilter> filter_spal = Gtk::FileFilter::create();
2533 	filter_spal->set_name(_("Synfig palette files (*.spal)"));
2534 	filter_spal->add_pattern("*.spal");
2535 	dialog->add_filter(filter_spal);
2536 
2537 	// ...and add GIMP color palette file too (*.gpl)
2538         Glib::RefPtr<Gtk::FileFilter> filter_gpl = Gtk::FileFilter::create();
2539 	filter_gpl->set_name(_("GIMP palette files (*.gpl)"));
2540 	filter_gpl->add_pattern("*.gpl");
2541 	dialog->add_filter(filter_gpl);
2542 
2543 	if (filename.empty())
2544 	dialog->set_filename(prev_path);
2545 	else if (is_absolute_path(filename))
2546 	dialog->set_filename(filename);
2547 	else
2548 	dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
2549 
2550 	if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2551 		filename = dialog->get_filename();
2552 		_preferences.set_value(preference, dirname(filename));
2553 		delete dialog;
2554 		return true;
2555 	}
2556 
2557 	delete dialog;
2558 	return false;
2559 }
2560 
2561 bool
dialog_open_file_sketch(const std::string & title,std::string & filename,std::string preference)2562 App::dialog_open_file_sketch(const std::string &title, std::string &filename, std::string preference)
2563 {
2564 	synfig::String prev_path;
2565 
2566 	if(!_preferences.get_value(preference, prev_path))
2567 		prev_path = Glib::get_home_dir();
2568 	prev_path = absolute_path(prev_path);
2569 
2570 	Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(*App::main_window,
2571 				title, Gtk::FILE_CHOOSER_ACTION_OPEN);
2572 
2573 	dialog->set_transient_for(*App::main_window);
2574 	dialog->set_current_folder(prev_path);
2575 	dialog->add_button(_("Cancel"), Gtk::RESPONSE_CANCEL)->set_image_from_icon_name("gtk-cancel", Gtk::ICON_SIZE_BUTTON);
2576 	dialog->add_button(_("Load"),   Gtk::RESPONSE_ACCEPT)->set_image_from_icon_name("gtk-open", Gtk::ICON_SIZE_BUTTON);
2577 
2578 	// show only Synfig sketch file (*.sketch)
2579 	Glib::RefPtr<Gtk::FileFilter> filter_sketch = Gtk::FileFilter::create();
2580 	filter_sketch->set_name(_("Synfig sketch files (*.sketch)"));
2581 	filter_sketch->add_pattern("*.sketch");
2582 	dialog->add_filter(filter_sketch);
2583 
2584 	if (filename.empty())
2585 	dialog->set_filename(prev_path);
2586 	else if (is_absolute_path(filename))
2587 	dialog->set_filename(filename);
2588 	else
2589 	dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
2590 
2591 	if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2592 		filename = dialog->get_filename();
2593 		_preferences.set_value(preference, dirname(filename));
2594 		delete dialog;
2595 		return true;
2596 	}
2597 
2598 	delete dialog;
2599 	return false;
2600 }
2601 
2602 
2603 bool
dialog_open_file_image(const std::string & title,std::string & filename,std::string preference)2604 App::dialog_open_file_image(const std::string &title, std::string &filename, std::string preference)
2605 {
2606 	synfig::String prev_path;
2607 
2608 	if(!_preferences.get_value(preference, prev_path))
2609 		prev_path = Glib::get_home_dir();
2610 
2611 	prev_path = absolute_path(prev_path);
2612 
2613 	Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(*App::main_window,
2614 				title, Gtk::FILE_CHOOSER_ACTION_OPEN);
2615 
2616 	dialog->set_transient_for(*App::main_window);
2617 	dialog->set_current_folder(prev_path);
2618 	dialog->add_button(_("Cancel"), Gtk::RESPONSE_CANCEL)->set_image_from_icon_name("gtk-cancel", Gtk::ICON_SIZE_BUTTON);
2619 	dialog->add_button(_("Load"),   Gtk::RESPONSE_ACCEPT)->set_image_from_icon_name("gtk-open", Gtk::ICON_SIZE_BUTTON);
2620 
2621 	// show only images
2622 	Glib::RefPtr<Gtk::FileFilter> filter_image = Gtk::FileFilter::create();
2623 	filter_image->set_name(_("Images and sequence files (*.png, *.jpg, *.jpeg, *.bmp, *.svg, *.lst)"));
2624 	filter_image->add_mime_type("image/png");
2625 	filter_image->add_mime_type("image/jpeg");
2626 	filter_image->add_mime_type("image/jpg");
2627 	filter_image->add_mime_type("image/bmp");
2628 	filter_image->add_mime_type("image/svg+xml");
2629 	filter_image->add_pattern("*.png");
2630 	filter_image->add_pattern("*.jpeg");
2631 	filter_image->add_pattern("*.jpg");
2632 	filter_image->add_pattern("*.bmp");
2633 	filter_image->add_pattern("*.svg");
2634 	filter_image->add_pattern("*.lst");
2635 	dialog->add_filter(filter_image);
2636 
2637 	// Any files
2638 	Glib::RefPtr<Gtk::FileFilter> filter_any = Gtk::FileFilter::create();
2639 	filter_any->set_name(_("Any files"));
2640 	filter_any->add_pattern("*");
2641 	dialog->add_filter(filter_any);
2642 
2643 	if (filename.empty())
2644 		dialog->set_filename(prev_path);
2645 	else if (is_absolute_path(filename))
2646 		dialog->set_filename(filename);
2647 	else
2648 		dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
2649 
2650 	if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2651 		filename = dialog->get_filename();
2652 		_preferences.set_value(preference, dirname(filename));
2653 		delete dialog;
2654 		return true;
2655 	}
2656 
2657 	delete dialog;
2658 	return false;
2659 }
2660 
2661 
2662 bool
dialog_open_file_audio(const std::string & title,std::string & filename,std::string preference)2663 App::dialog_open_file_audio(const std::string &title, std::string &filename, std::string preference)
2664 {
2665 	synfig::String prev_path;
2666 
2667 	if(!_preferences.get_value(preference, prev_path))
2668 		prev_path = Glib::get_home_dir();
2669 
2670 	prev_path = absolute_path(prev_path);
2671 
2672 	Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(*App::main_window,
2673 				title, Gtk::FILE_CHOOSER_ACTION_OPEN);
2674 
2675 	dialog->set_transient_for(*App::main_window);
2676 	dialog->set_current_folder(prev_path);
2677 	dialog->add_button(_("Cancel"), Gtk::RESPONSE_CANCEL)->set_image_from_icon_name("gtk-cancel", Gtk::ICON_SIZE_BUTTON);
2678 	dialog->add_button(_("Load"),   Gtk::RESPONSE_ACCEPT)->set_image_from_icon_name("gtk-open", Gtk::ICON_SIZE_BUTTON);
2679 
2680 	// Audio files
2681 	Glib::RefPtr<Gtk::FileFilter> filter_audio = Gtk::FileFilter::create();
2682 	filter_audio->set_name(_("Audio (*.ogg, *.mp3, *.wav)"));
2683 	filter_audio->add_mime_type("audio/x-vorbis+ogg");
2684 	filter_audio->add_mime_type("audio/mpeg");
2685 	filter_audio->add_mime_type("audio/x-wav");
2686 	filter_audio->add_pattern("*.ogg");
2687 	filter_audio->add_pattern("*.mp3");
2688 	filter_audio->add_pattern("*.wav");
2689 	dialog->add_filter(filter_audio);
2690 
2691 	// Any files
2692 	Glib::RefPtr<Gtk::FileFilter> filter_any = Gtk::FileFilter::create();
2693 	filter_any->set_name(_("Any files"));
2694 	filter_any->add_pattern("*");
2695 	dialog->add_filter(filter_any);
2696 
2697 	if (filename.empty())
2698 	dialog->set_filename(prev_path);
2699 	else if (is_absolute_path(filename))
2700 	dialog->set_filename(filename);
2701 	else
2702 	dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
2703 
2704 	if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2705 		filename = dialog->get_filename();
2706 		_preferences.set_value(preference, dirname(filename));
2707 		delete dialog;
2708 		return true;
2709 	}
2710 
2711 	delete dialog;
2712 	return false;
2713 }
2714 
2715 void
on_open_dialog_with_history_selection_changed(Gtk::FileChooserDialog * dialog,Gtk::Button * history_button)2716 on_open_dialog_with_history_selection_changed(Gtk::FileChooserDialog *dialog, Gtk::Button* history_button)
2717 {
2718 	// activate the history button when something is selected
2719 	history_button->set_sensitive(!dialog->get_filename().empty());
2720 }
2721 
2722 bool
dialog_open_file_with_history_button(const std::string & title,std::string & filename,bool & show_history,std::string preference)2723 App::dialog_open_file_with_history_button(const std::string &title, std::string &filename, bool &show_history, std::string preference)
2724 {
2725 	// info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2726 
2727 // TODO: Win32 native dialog not ready yet
2728 //#ifdef USE_WIN32_FILE_DIALOGS
2729 #if 0
2730 	static TCHAR szFilter[] = TEXT (_("All Files (*.*)\0*.*\0\0")) ;
2731 
2732 	GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2733 	HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2734 	HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2735 
2736 	ofn.lStructSize=sizeof(OPENFILENAME);
2737 	ofn.hwndOwner = hWnd;
2738 	ofn.hInstance = hInstance;
2739 	ofn.lpstrFilter = szFilter;
2740 //	ofn.lpstrCustomFilter=NULL;
2741 //	ofn.nMaxCustFilter=0;
2742 //	ofn.nFilterIndex=0;
2743 //	ofn.lpstrFile=NULL;
2744 	ofn.nMaxFile=MAX_PATH;
2745 //	ofn.lpstrFileTitle=NULL;
2746 //	ofn.lpstrInitialDir=NULL;
2747 //	ofn.lpstrTitle=NULL;
2748 	ofn.Flags=OFN_HIDEREADONLY;
2749 //	ofn.nFileOffset=0;
2750 //	ofn.nFileExtension=0;
2751 	ofn.lpstrDefExt=TEXT("sif");
2752 //	ofn.lCustData = 0l;
2753 	ofn.lpfnHook=NULL;
2754 //	ofn.lpTemplateName=NULL;
2755 
2756 	CHAR szFilename[MAX_PATH];
2757 	CHAR szTitle[500];
2758 	strcpy(szFilename,filename.c_str());
2759 	strcpy(szTitle,title.c_str());
2760 
2761 	ofn.lpstrFile=szFilename;
2762 	ofn.lpstrFileTitle=szTitle;
2763 
2764 	if(GetOpenFileName(&ofn))
2765 	{
2766 		filename=szFilename;
2767 		return true;
2768 	}
2769 	return false;
2770 
2771 #else   // not USE_WIN32_FILE_DIALOGS
2772 	synfig::String prev_path;
2773 
2774 	if(!_preferences.get_value(preference, prev_path))
2775 		prev_path = Glib::get_home_dir();
2776 
2777 	prev_path = absolute_path(prev_path);
2778 
2779 	Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(*App::main_window,
2780 				title, Gtk::FILE_CHOOSER_ACTION_OPEN);
2781 
2782 		dialog->set_transient_for(*App::main_window);
2783 	dialog->set_current_folder(prev_path);
2784 	dialog->add_button(_("Cancel"), Gtk::RESPONSE_CANCEL)->set_image_from_icon_name("gtk-cancel", Gtk::ICON_SIZE_BUTTON);
2785 	dialog->add_button(_("Open"),   Gtk::RESPONSE_ACCEPT)->set_image_from_icon_name("gtk-open", Gtk::ICON_SIZE_BUTTON);
2786 	Gtk::Button* history_button = dialog->add_button(_("Open history"), RESPONSE_ACCEPT_WITH_HISTORY);
2787 	// TODO: the Open history button should be file type sensitive one.
2788 	dialog->set_response_sensitive(RESPONSE_ACCEPT_WITH_HISTORY, true);
2789 
2790 	// File filters
2791 	// Synfig Documents
2792 	Glib::RefPtr<Gtk::FileFilter> filter_supported = Gtk::FileFilter::create();
2793 	filter_supported->set_name(_("Synfig files (*.sif, *.sifz, *.sfg)"));
2794 	filter_supported->add_mime_type("application/x-sif");
2795 	filter_supported->add_pattern("*.sif");
2796 	filter_supported->add_pattern("*.sifz");
2797 	filter_supported->add_pattern("*.sfg");
2798 	// Any files
2799 	Glib::RefPtr<Gtk::FileFilter> filter_any = Gtk::FileFilter::create();
2800 	filter_any->set_name(_("Any files"));
2801 	filter_any->add_pattern("*");
2802 
2803 	dialog->add_filter(filter_supported);
2804 	dialog->add_filter(filter_any);
2805 
2806 	if (filename.empty())
2807 		dialog->set_filename(prev_path);
2808 	else if (is_absolute_path(filename))
2809 		dialog->set_filename(filename);
2810 	else
2811 		dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
2812 
2813 	// this ptr is't available to a static member fnc, connect to global function.
2814 	sigc::connection connection_sc = dialog->signal_selection_changed().connect(sigc::bind(sigc::ptr_fun(on_open_dialog_with_history_selection_changed), dialog, history_button));
2815 
2816 	int response = dialog->run();
2817 	if (response == Gtk::RESPONSE_ACCEPT || response == RESPONSE_ACCEPT_WITH_HISTORY) {
2818 		filename = dialog->get_filename();
2819 		show_history = response == RESPONSE_ACCEPT_WITH_HISTORY;
2820 		// info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
2821 		_preferences.set_value(preference, dirname(filename));
2822 		delete dialog;
2823 		return true;
2824 	}
2825 
2826 	connection_sc.disconnect();
2827 	delete dialog;
2828 	return false;
2829 #endif   // not USE_WIN32_FILE_DIALOGS
2830 }
2831 
2832 bool
dialog_open_folder(const std::string & title,std::string & foldername,std::string preference,Gtk::Window & transientwind)2833 App::dialog_open_folder(const std::string &title, std::string &foldername, std::string preference, Gtk::Window& transientwind)
2834 {
2835 	synfig::String prev_path;
2836 	synfigapp::Settings settings;
2837 	if(settings.get_value(preference, prev_path))
2838 		prev_path = ".";
2839 
2840 	prev_path = absolute_path(prev_path);
2841 
2842 	Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(*App::main_window,
2843 			title, Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
2844 
2845 	dialog->set_transient_for(transientwind);
2846 	dialog->set_current_folder(prev_path);
2847 	dialog->add_button(_("Cancel"), Gtk::RESPONSE_CANCEL)->set_image_from_icon_name("gtk-cancel", Gtk::ICON_SIZE_BUTTON);
2848 	dialog->add_button(_("Open"),   Gtk::RESPONSE_ACCEPT)->set_image_from_icon_name("gtk-open", Gtk::ICON_SIZE_BUTTON);
2849 
2850 	if(dialog->run() == GTK_RESPONSE_ACCEPT)
2851 	{
2852 		foldername = dialog->get_filename();
2853 		delete dialog;
2854 		return true;
2855 	}
2856 	delete dialog;
2857 	return false;
2858 }
2859 
2860 
2861 bool
dialog_save_file(const std::string & title,std::string & filename,std::string preference)2862 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
2863 {
2864 	// info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2865 
2866 #if USE_WIN32_FILE_DIALOGS
2867 	static TCHAR szFilter[] = TEXT (_("All Files (*.*)\0*.*\0\0")) ;
2868 
2869 	GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2870 	HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2871 	HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2872 
2873 	ofn.lStructSize=sizeof(OPENFILENAME);
2874 	ofn.hwndOwner = hWnd;
2875 	ofn.hInstance = hInstance;
2876 	ofn.lpstrFilter = szFilter;
2877 //	ofn.lpstrCustomFilter=NULL;
2878 //	ofn.nMaxCustFilter=0;
2879 //	ofn.nFilterIndex=0;
2880 //	ofn.lpstrFile=NULL;
2881 	ofn.nMaxFile=MAX_PATH;
2882 //	ofn.lpstrFileTitle=NULL;
2883 //	ofn.lpstrInitialDir=NULL;
2884 //	ofn.lpstrTitle=NULL;
2885 	ofn.Flags=OFN_OVERWRITEPROMPT;
2886 //	ofn.nFileOffset=0;
2887 //	ofn.nFileExtension=0;
2888 	ofn.lpstrDefExt=TEXT("sif");
2889 //	ofn.lCustData = 0l;
2890 	ofn.lpfnHook=NULL;
2891 //	ofn.lpTemplateName=NULL;
2892 
2893 	CHAR szFilename[MAX_PATH];
2894 	CHAR szTitle[500];
2895 	strcpy(szFilename,filename.c_str());
2896 	strcpy(szTitle,title.c_str());
2897 
2898 	ofn.lpstrFile=szFilename;
2899 	ofn.lpstrFileTitle=szTitle;
2900 
2901 	if(GetSaveFileName(&ofn))
2902 	{
2903 		filename=szFilename;
2904 		_preferences.set_value(preference,dirname(filename));
2905 		return true;
2906 	}
2907 	return false;
2908 #else
2909 	synfig::String prev_path;
2910 
2911 	if(!_preferences.get_value(preference, prev_path))
2912 		prev_path = Glib::get_home_dir();
2913 
2914 	prev_path = absolute_path(prev_path);
2915 
2916 	Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(*App::main_window, title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2917 
2918 	// file type filters
2919 	Glib::RefPtr<Gtk::FileFilter> filter_sif = Gtk::FileFilter::create();
2920 	filter_sif->set_name(_("Uncompressed Synfig file (*.sif)"));
2921 
2922 	// sif share same mime type "application/x-sif" with sifz, so it will mixed .sif and .sifz files. Use only
2923 	// pattern ("*.sif") for sif file format should be oK.
2924 	//filter_sif->add_mime_type("application/x-sif");
2925 	filter_sif->add_pattern("*.sif");
2926 
2927 	Glib::RefPtr<Gtk::FileFilter> filter_sifz = Gtk::FileFilter::create();
2928 	filter_sifz->set_name(_("Compressed Synfig file (*.sifz)"));
2929 	filter_sifz->add_pattern("*.sifz");
2930 
2931 	Glib::RefPtr<Gtk::FileFilter> filter_sfg = Gtk::FileFilter::create();
2932 	filter_sfg->set_name(_("Container format file (*.sfg)"));
2933 	filter_sfg->add_pattern("*.sfg");
2934 
2935 	dialog->set_current_folder(prev_path);
2936 	dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2937 	dialog->add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_ACCEPT);
2938 
2939 	dialog->add_filter(filter_sifz);
2940 	dialog->add_filter(filter_sif);
2941 	dialog->add_filter(filter_sfg);
2942 
2943 	Widget_Enum *file_type_enum = 0;
2944 	if (preference == ANIMATION_DIR_PREFERENCE)
2945 	{
2946 		file_type_enum = manage(new Widget_Enum());
2947 		file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2948 				.add_enum_value(synfig::RELEASE_VERSION_CURRENT, "Current", _("Current"))
2949 				.add_enum_value(synfig::RELEASE_VERSION_1_2_0, "1.2.1", "1.2.1")
2950 				.add_enum_value(synfig::RELEASE_VERSION_1_2_0, "1.2.0", "1.2.0")
2951 				.add_enum_value(synfig::RELEASE_VERSION_1_0_2, "1.0.2", "1.0.2")
2952 				.add_enum_value(synfig::RELEASE_VERSION_1_0, "1.0", "1.0")
2953 				.add_enum_value(synfig::RELEASE_VERSION_0_64_3, "0.64.3", "0.64.3")
2954 				.add_enum_value(synfig::RELEASE_VERSION_0_64_2, "0.64.2", "0.64.2")
2955 				.add_enum_value(synfig::RELEASE_VERSION_0_64_1, "0.64.1", "0.64.1")
2956 				.add_enum_value(synfig::RELEASE_VERSION_0_64_0, "0.64.0", "0.64.0")
2957 				.add_enum_value(synfig::RELEASE_VERSION_0_63_04, "0.63.05", "0.63.05")
2958 				.add_enum_value(synfig::RELEASE_VERSION_0_63_04, "0.63.04", "0.63.04")
2959 				.add_enum_value(synfig::RELEASE_VERSION_0_63_03, "0.63.03", "0.63.03")
2960 				.add_enum_value(synfig::RELEASE_VERSION_0_63_02, "0.63.02", "0.63.02")
2961 				.add_enum_value(synfig::RELEASE_VERSION_0_63_01, "0.63.01", "0.63.01")
2962 				.add_enum_value(synfig::RELEASE_VERSION_0_63_00, "0.63.00", "0.63.00")
2963 				.add_enum_value(synfig::RELEASE_VERSION_0_62_02, "0.62.02", "0.62.02")
2964 				.add_enum_value(synfig::RELEASE_VERSION_0_62_01, "0.62.01", "0.62.01")
2965 				.add_enum_value(synfig::RELEASE_VERSION_0_62_00, "0.62.00", "0.61.00")
2966 				.add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", "0.61.09")
2967 				.add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2968 				.add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2969 				.add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2970 		file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2971 
2972 		Gtk::Grid *grid = manage(new Gtk::Grid);
2973 		grid->attach(*manage(new Gtk::Label(_("File Format Version: "))),0,0,1,1);
2974 		grid->attach(*file_type_enum,1,0,1,1);
2975 		grid->show_all();
2976 
2977 		dialog->set_extra_widget(*grid);
2978 	}
2979 
2980 	if (filename.empty()) {
2981 		dialog->set_filename(prev_path);
2982 
2983 	}else{
2984 		std::string full_path;
2985 		if (is_absolute_path(filename))
2986 			full_path = filename;
2987 		else
2988 			full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2989 
2990 		// select the file if it exists
2991 		dialog->set_filename(full_path);
2992 
2993 		// if the file doesn't exist, put its name into the filename box
2994 		struct stat s;
2995 		if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2996 			dialog->set_current_name(basename(filename));
2997 
2998 	}
2999 	// set file filter according to previous file format
3000 	if (filename_extension(filename) == ".sif" ) dialog->set_filter(filter_sif);
3001 	if (filename_extension(filename)== ".sifz" ) dialog->set_filter(filter_sifz);
3002 	if (filename_extension(filename) == ".sfg" ) dialog->set_filter(filter_sfg);
3003 
3004 	// set focus to the file name entry(box) of dialog instead to avoid the name
3005 	// we are going to save changes while changing file filter each time.
3006 	dialog->set_current_name(basename(filename));
3007 
3008 	if(dialog->run() == GTK_RESPONSE_ACCEPT) {
3009 
3010 		if (preference == ANIMATION_DIR_PREFERENCE)
3011 			set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
3012 
3013 		// add file extension according to file filter selected by user if he doesn't type file extension in
3014 		// file name entry. Right now it still detetes file extension from file name entry, if extension is one
3015 		// of .sif, sifz and sfg, it will be used otherwise, saved file format will depend on selected file filter.
3016 		// It should be improved by changing file extension according to selted file type filter, such as:
3017 		// dialog->property_filter().signal_changed().connect(sigc::mem_fun(*this, &App::on_save_dialog_filter_changed));
3018 		filename = dialog->get_filename();
3019 
3020 		if (filename_extension(filename) != ".sif" &&
3021 			filename_extension(filename) != ".sifz" &&
3022 			filename_extension(filename) != ".sfg")
3023 		{
3024 			if (dialog->get_filter() == filter_sif)
3025 				filename = dialog->get_filename() + ".sif";
3026 			else if (dialog->get_filter() == filter_sifz)
3027 				filename = dialog->get_filename() + ".sifz";
3028 			else if (dialog->get_filter() == filter_sfg)
3029 				filename = dialog->get_filename() + ".sfg";
3030 		}
3031 
3032 	// info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
3033 	_preferences.set_value(preference, dirname(filename));
3034 	delete dialog;
3035 	return true;
3036     }
3037 
3038     delete dialog;
3039     return false;
3040 #endif
3041 }
3042 
3043 
3044 bool
dialog_save_file_spal(const std::string & title,std::string & filename,std::string preference)3045 App::dialog_save_file_spal(const std::string &title, std::string &filename, std::string preference)
3046 {
3047 	synfig::String prev_path;
3048 	if(!_preferences.get_value(preference, prev_path))
3049 		prev_path=Glib::get_home_dir();
3050 	prev_path = absolute_path(prev_path);
3051 
3052 	Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(*App::main_window, title, Gtk::FILE_CHOOSER_ACTION_SAVE);
3053 
3054 	// file type filters
3055 	Glib::RefPtr<Gtk::FileFilter> filter_spal = Gtk::FileFilter::create();
3056 	filter_spal->set_name(_("Synfig palette files (*.spal)"));
3057 	filter_spal->add_pattern("*.spal");
3058 
3059 	dialog->set_current_folder(prev_path);
3060 	dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3061 	dialog->add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_ACCEPT);
3062 
3063 	dialog->add_filter(filter_spal);
3064 
3065 	if (filename.empty()) {
3066 		dialog->set_filename(prev_path);
3067 
3068 	}else{
3069 		std::string full_path;
3070 		if (is_absolute_path(filename))
3071 			full_path = filename;
3072 		else
3073 			full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
3074 
3075 		// select the file if it exists
3076 		dialog->set_filename(full_path);
3077 
3078 		// if the file doesn't exist, put its name into the filename box
3079 		struct stat s;
3080 		if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
3081 			dialog->set_current_name(basename(filename));
3082 
3083 	}
3084 
3085 	dialog->set_filter(filter_spal);
3086 
3087 	// set focus to the file name entry(box) of dialog instead to avoid the name
3088 	// we are going to save changes while changing file filter each time.
3089 	dialog->set_current_name(basename(filename));
3090 
3091 	if(dialog->run() == GTK_RESPONSE_ACCEPT) {
3092 
3093 		// add file extension according to file filter selected by user
3094 		filename = dialog->get_filename();
3095 		if (filename_extension(filename) != ".spal")
3096 			filename = dialog->get_filename() + ".spal";
3097 
3098 	delete dialog;
3099 	return true;
3100 	}
3101 
3102 	delete dialog;
3103 	return false;
3104 }
3105 
3106 bool
dialog_save_file_sketch(const std::string & title,std::string & filename,std::string preference)3107 App::dialog_save_file_sketch(const std::string &title, std::string &filename, std::string preference)
3108 {
3109 	synfig::String prev_path;
3110 	if(!_preferences.get_value(preference, prev_path))
3111 		prev_path=Glib::get_home_dir();
3112 	prev_path = absolute_path(prev_path);
3113 
3114 	Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(*App::main_window, title, Gtk::FILE_CHOOSER_ACTION_SAVE);
3115 
3116 	// file type filters
3117 	Glib::RefPtr<Gtk::FileFilter> filter_sketch = Gtk::FileFilter::create();
3118 	filter_sketch->set_name(_("Synfig sketch files (*.sketch)"));
3119 	filter_sketch->add_pattern("*.sketch");
3120 
3121 	dialog->set_current_folder(prev_path);
3122 	dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3123 	dialog->add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_ACCEPT);
3124 
3125 	dialog->add_filter(filter_sketch);
3126 
3127 	if (filename.empty()) {
3128 		dialog->set_filename(prev_path);
3129 
3130 	}else{
3131 		std::string full_path;
3132 		if (is_absolute_path(filename))
3133 			full_path = filename;
3134 		else
3135 			full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
3136 
3137 		// select the file if it exists
3138 		dialog->set_filename(full_path);
3139 
3140 		// if the file doesn't exist, put its name into the filename box
3141 		struct stat s;
3142 		if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
3143 			dialog->set_current_name(basename(filename));
3144 
3145 	}
3146 
3147 	dialog->set_filter(filter_sketch);
3148 
3149 	// set focus to the file name entry(box) of dialog instead to avoid the name
3150 	// we are going to save changes while changing file filter each time.
3151 	dialog->set_current_name(basename(filename));
3152 
3153 	if(dialog->run() == GTK_RESPONSE_ACCEPT) {
3154 
3155 		// add file extension according to file filter selected by user
3156 		filename = dialog->get_filename();
3157 		if (filename_extension(filename) != ".sketch")
3158 			filename = dialog->get_filename() + ".sketch";
3159 
3160 	delete dialog;
3161 	return true;
3162 	}
3163 
3164 	delete dialog;
3165 	return false;
3166 }
3167 
3168 
3169 bool
dialog_save_file_render(const std::string & title,std::string & filename,std::string preference)3170 App::dialog_save_file_render(const std::string &title, std::string &filename, std::string preference)
3171 {
3172 	synfig::String prev_path;
3173 	if(!_preferences.get_value(preference, prev_path))
3174 		prev_path=Glib::get_home_dir();
3175 	prev_path = absolute_path(prev_path);
3176 
3177 	Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(*App::main_window, title, Gtk::FILE_CHOOSER_ACTION_SAVE);
3178 
3179 	dialog->set_current_folder(prev_path);
3180 	dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3181 	dialog->add_button(Gtk::Stock::OK,   Gtk::RESPONSE_ACCEPT);
3182 
3183 	if (filename.empty()) {
3184 		dialog->set_filename(prev_path);
3185 
3186 	}else{
3187 		std::string full_path;
3188 		if (is_absolute_path(filename))
3189 			full_path = filename;
3190 		else
3191 			full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
3192 
3193 		// select the file if it exists
3194 		dialog->set_filename(full_path);
3195 
3196 		// if the file doesn't exist, put its name into the filename box
3197 		struct stat s;
3198 		if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
3199 			dialog->set_current_name(basename(filename));
3200 
3201 	}
3202 
3203 	if(dialog->run() == GTK_RESPONSE_ACCEPT)
3204 	{
3205 		filename = dialog->get_filename();
3206 
3207 		delete dialog;
3208 		return true;
3209 	}
3210 
3211 	delete dialog;
3212 	return false;
3213 }
3214 
3215 
3216 bool
dialog_select_list_item(const std::string & title,const std::string & message,const std::list<std::string> & list,int & item_index)3217 App::dialog_select_list_item(const std::string &title, const std::string &message, const std::list<std::string> &list, int &item_index)
3218 {
3219 	Gtk::Dialog dialog(title, *App::main_window, true);
3220 
3221 	Gtk::Label* label = manage (new Gtk::Label(message, 0, 0));
3222 	label->set_line_wrap();
3223 
3224 	class ModelColumns : public Gtk::TreeModel::ColumnRecord
3225 	{
3226 	public:
3227 		Gtk::TreeModelColumn<int> column_index;
3228 		Gtk::TreeModelColumn<Glib::ustring> column_main;
3229 		ModelColumns() { add(column_index); add(column_main); }
3230 	} model_columns;
3231 
3232 	Glib::RefPtr<Gtk::ListStore> list_store = Gtk::ListStore::create(model_columns);
3233 
3234 	int k = 0;
3235 	for(std::list<std::string>::const_iterator i = list.begin(); i != list.end(); i++) {
3236 		Gtk::ListStore::iterator j = list_store->append();
3237 		j->set_value(model_columns.column_index, k++);
3238 		j->set_value(model_columns.column_main, Glib::ustring(*i));
3239 	}
3240 
3241 	Gtk::TreeView * tree = manage (new Gtk::TreeView(list_store));
3242 	Gtk::TreeViewColumn column_index("", model_columns.column_index);
3243 	Gtk::TreeViewColumn column_main("", model_columns.column_main);
3244 	column_index.set_visible(false);
3245 	tree->append_column(column_index);
3246 	tree->append_column(column_main);
3247 	tree->set_hexpand(TRUE);
3248 	tree->set_halign(Gtk::ALIGN_FILL);
3249 	tree->set_vexpand(TRUE);
3250 	tree->set_valign(Gtk::ALIGN_FILL);
3251 
3252 	Gtk::TreeModel::Row selected_row = list_store->children()[item_index];
3253 	if (selected_row)
3254 		tree->get_selection()->select(selected_row);
3255 
3256 	Gtk::Grid* grid = manage(new Gtk::Grid());
3257 	grid->attach(*label, 0, 0, 1, 1);
3258 	grid->attach(*tree, 0, 1, 1, 2);
3259 
3260 	dialog.get_content_area()->pack_start(*grid);
3261 	dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3262 	dialog.add_button(Gtk::Stock::OPEN,   Gtk::RESPONSE_ACCEPT);
3263 	dialog.set_default_size(300, 450);
3264 	dialog.show_all();
3265 
3266 	if (dialog.run() == Gtk::RESPONSE_ACCEPT) {
3267 		item_index = tree->get_selection()->get_selected()->get_value(model_columns.column_index);
3268 		return true;
3269 	}
3270 
3271 	return false;
3272 }
3273 
3274 
3275 void
dialog_not_implemented()3276 App::dialog_not_implemented()
3277 {
3278 	Gtk::MessageDialog dialog(*App::main_window, _("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
3279 	dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
3280 	dialog.run();
3281 }
3282 
3283 
3284 // message dialog with 1 button.
3285 void
dialog_message_1b(const std::string & type,const std::string & message,const std::string & details,const std::string & button1,const std::string & long_details)3286 App::dialog_message_1b(
3287 	const std::string &type,
3288 		//INFO:		Gtk::MESSAGE_INFO - Informational message.
3289 		//WARNING:	Gtk::MESSAGE_WARNING - Non-fatal warning message.
3290 		//QUESTION:	Gtk::MESSAGE_QUESTION - Question requiring a choice.
3291 		//ERROR:	Gtk::MESSAGE_ERROR - Fatal error message.
3292 		//OTHER:	Gtk::MESSAGE_OTHER - None of the above, doesn’t get an icon.
3293 	const std::string &message,
3294 	const std::string &details,
3295 	const std::string &button1,
3296 	const std::string &long_details)
3297 {
3298 	Gtk::MessageType _type = Gtk::MESSAGE_OTHER; // default
3299 	if (type == "INFO")
3300 		_type = Gtk::MESSAGE_INFO;
3301 	if (type == "WARNING")
3302 		_type = Gtk::MESSAGE_WARNING;
3303 	if (type == "QUESTION")
3304 		_type = Gtk::MESSAGE_QUESTION;
3305 	if (type == "ERROR")
3306 		_type = Gtk::MESSAGE_ERROR;
3307 	if (type == "OTHER")
3308 		_type = Gtk::MESSAGE_OTHER;
3309 
3310 	Gtk::MessageDialog dialog(*App::main_window, message, false, _type, Gtk::BUTTONS_NONE, true);
3311 
3312 	if (details != "details")
3313 		dialog.set_secondary_text(details);
3314 
3315 	Gtk::Label label;
3316 	Gtk::ScrolledWindow sw;
3317 	if (long_details != "long_details")
3318 	{
3319 		label.set_text(long_details);
3320 		label.show();
3321 		sw.add(label);
3322 		sw.set_size_request(400,300);
3323 		sw.show();
3324 		dialog.get_content_area()->pack_end(sw);
3325 		dialog.set_resizable(true);
3326 	}
3327 
3328 	dialog.add_button(button1, 0);
3329 
3330 	dialog.run();
3331 }
3332 
3333 
3334 // message dialog with 2 buttons.
3335 bool
dialog_message_2b(const std::string & message,const std::string & details,const Gtk::MessageType & type,const std::string & button1,const std::string & button2)3336 App::dialog_message_2b(const std::string &message,
3337 	const std::string &details,
3338 	const Gtk::MessageType &type,
3339 		//MESSAGE_INFO - Informational message.
3340 		//MESSAGE_WARNING - Non-fatal warning message.
3341 		//MESSAGE_QUESTION - Question requiring a choice.
3342 		//MESSAGE_ERROR - Fatal error message.
3343 		//MESSAGE_OTHER - None of the above, doesn’t get an icon.
3344 	const std::string &button1,
3345 	const std::string &button2)
3346 {
3347 	Gtk::MessageDialog dialog(*App::main_window, message, false, type, Gtk::BUTTONS_NONE, true);
3348 	dialog.set_secondary_text(details);
3349 	dialog.add_button(button1, 0);
3350 	dialog.add_button(button2, 1);
3351 
3352 	return	dialog.run();
3353 }
3354 
3355 
3356 // message dialog with 3 buttons.
3357 int
dialog_message_3b(const std::string & message,const std::string & detials,const Gtk::MessageType & type,const std::string & button1,const std::string & button2,const std::string & button3)3358 App::dialog_message_3b(const std::string &message,
3359 	const std::string &detials,
3360 	const Gtk::MessageType &type,
3361 		//MESSAGE_INFO - Informational message.
3362 		//MESSAGE_WARNING - Non-fatal warning message.
3363 		//MESSAGE_QUESTION - Question requiring a choice.
3364 		//MESSAGE_ERROR - Fatal error message.
3365 		//MESSAGE_OTHER - None of the above, doesn’t get an icon.
3366 	const std::string &button1,
3367 	const std::string &button2,
3368 	const std::string &button3)
3369 {
3370 	Gtk::MessageDialog dialog(*App::main_window, message, false, type, Gtk::BUTTONS_NONE, true);
3371 	dialog.set_secondary_text(detials);
3372 	dialog.add_button(button1, 0);
3373 	dialog.add_button(button2, 1);
3374 	dialog.add_button(button3, 2);
3375 
3376 	return dialog.run();
3377 }
3378 
3379 
3380 static bool
try_open_uri(const std::string & uri)3381 try_open_uri(const std::string &uri)
3382 {
3383 	return gtk_show_uri(NULL, uri.c_str(), GDK_CURRENT_TIME, NULL);
3384 }
3385 
3386 void
dialog_help()3387 App::dialog_help()
3388 {
3389 	if (!try_open_uri("http://synfig.org/wiki/Category:Manual"))
3390 	{
3391 		Gtk::MessageDialog dialog(*App::main_window, _("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
3392 		dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://synfig.org/wiki/Category:Manual"));
3393 		dialog.set_title(_("Help"));
3394 		dialog.run();
3395 	}
3396 }
3397 
open_uri(const std::string & uri)3398 void App::open_uri(const std::string &uri)
3399 {
3400 	synfig::info("Opening URI: " + uri);
3401 	if(!try_open_uri(uri))
3402 	{
3403 		Gtk::MessageDialog dialog(*App::main_window, _("No compatible application was found. Please load open file manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
3404 		dialog.set_secondary_text(uri);
3405 		dialog.set_title(_("Error"));
3406 		dialog.run();
3407 	}
3408 }
3409 
3410 bool
dialog_entry(const std::string & action,const std::string & content,std::string & text,const std::string & button1,const std::string & button2)3411 App::dialog_entry(const std::string &action, const std::string &content, std::string &text, const std::string &button1, const std::string &button2)
3412 {
3413 	Gtk::MessageDialog dialog(
3414 		*App::main_window,
3415 		action,
3416 		false,
3417 		Gtk::MESSAGE_INFO,
3418 		Gtk::BUTTONS_NONE,
3419 		true
3420 	);
3421 
3422 	// TODO Group All HARDCODED user interface information somewhere "global"
3423 	// TODO All UI info from .rc
3424 #define DIALOG_ENTRY_MARGIN 18
3425 	Gtk::Label* label = manage (new Gtk::Label(content));
3426 	label->set_margin_start(DIALOG_ENTRY_MARGIN);
3427 
3428 	Gtk::Entry* entry = manage(new Gtk::Entry());
3429 	entry->set_text(text);
3430 	entry->set_margin_end(DIALOG_ENTRY_MARGIN);
3431 	entry->set_activates_default(true);
3432 	entry->set_hexpand(TRUE);
3433 	entry->set_halign(Gtk::ALIGN_FILL);
3434 #undef DIALOG_ENTRY_MARGIN
3435 
3436 	Gtk::Grid* grid = manage (new Gtk::Grid());
3437 	grid->add(*label);
3438 	grid->add(*entry);
3439 
3440 	grid->show_all();
3441 
3442 	dialog.get_content_area()->pack_start(*grid);
3443 	dialog.add_button(button1, Gtk::RESPONSE_CANCEL);
3444 	dialog.add_button(button2, Gtk::RESPONSE_OK);
3445 
3446 	dialog.set_default_response(Gtk::RESPONSE_OK);
3447 	entry->signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
3448 	dialog.show();
3449 
3450 	if(dialog.run()!=Gtk::RESPONSE_OK)
3451 		return false;
3452 
3453 	text = entry->get_text();
3454 
3455 	return true;
3456 }
3457 
3458 
3459 bool
dialog_paragraph(const std::string & title,const std::string & message,std::string & text)3460 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
3461 {
3462 	Gtk::Dialog dialog(
3463 		title,			// Title
3464 		*App::main_window,	// Parent
3465 		true			// Modal
3466 	);
3467 
3468 	Gtk::Label* label = manage(new Gtk::Label(message));
3469 	label->show();
3470 	dialog.get_content_area()->pack_start(*label);
3471 
3472 	Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
3473 	text_buffer->set_text(text);
3474 	Gtk::TextView text_view(text_buffer);
3475 	text_view.show();
3476 
3477 	dialog.get_content_area()->pack_start(text_view);
3478 
3479 	dialog.add_button(_("OK"),   Gtk::RESPONSE_OK)->set_image_from_icon_name("gtk-ok", Gtk::ICON_SIZE_BUTTON);
3480 	dialog.add_button(_("Cancel"), Gtk::RESPONSE_CANCEL)->set_image_from_icon_name("gtk-cancel", Gtk::ICON_SIZE_BUTTON);
3481 	dialog.set_default_response(Gtk::RESPONSE_OK);
3482 
3483 	//text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
3484 	dialog.show();
3485 
3486 	if(dialog.run()!=Gtk::RESPONSE_OK)
3487 		return false;
3488 
3489 	text=text_buffer->get_text();
3490 
3491 	return true;
3492 }
3493 
3494 std::string
get_temporary_directory()3495 App::get_temporary_directory()
3496 {
3497 	return synfigapp::Main::get_user_app_directory() + ETL_DIRECTORY_SEPARATOR + "tmp";
3498 }
3499 
3500 synfig::FileSystemTemporary::Handle
wrap_into_temporary_filesystem(synfig::FileSystem::Handle canvas_file_system,std::string filename,std::string as,synfig::FileContainerZip::file_size_t truncate_storage_size)3501 App::wrap_into_temporary_filesystem(
3502 	synfig::FileSystem::Handle canvas_file_system,
3503 	std::string filename,
3504 	std::string as,
3505 	synfig::FileContainerZip::file_size_t truncate_storage_size )
3506 {
3507 	FileSystemTemporary::Handle temporary_file_system = new FileSystemTemporary("instance", get_temporary_directory(), canvas_file_system);
3508 	temporary_file_system->set_meta("filename", filename);
3509 	temporary_file_system->set_meta("as", as);
3510 	temporary_file_system->set_meta("truncate", etl::strprintf("%d", truncate_storage_size));
3511 	return temporary_file_system;
3512 }
3513 
3514 bool
open(std::string filename)3515 App::open(std::string filename)
3516 {
3517 	return open_as(filename,filename);
3518 }
3519 
3520 bool
open_as(std::string filename,std::string as,synfig::FileContainerZip::file_size_t truncate_storage_size)3521 App::open_as(std::string filename,std::string as,synfig::FileContainerZip::file_size_t truncate_storage_size)
3522 {
3523 #ifdef _WIN32
3524     size_t buf_size = PATH_MAX - 1;
3525     char* long_name = (char*)malloc(buf_size);
3526     long_name[0] = '\0';
3527     if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
3528     // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
3529     // don't use it if that's the case
3530     if (long_name[0] != '\0')
3531         as=String(long_name);
3532     free(long_name);
3533 #endif
3534 
3535 	try
3536 	{
3537 		OneMoment one_moment;
3538 		String errors, warnings;
3539 
3540 		// try open container
3541 		FileSystem::Handle container = CanvasFileNaming::make_filesystem_container(filename, truncate_storage_size);
3542 		if (!container)
3543 			throw (String)strprintf(_("Unable to open container \"%s\"\n\n"),filename.c_str());
3544 
3545 		// make canvas file system
3546 		FileSystem::Handle canvas_file_system = CanvasFileNaming::make_filesystem(container);
3547 
3548 		// wrap into temporary file system
3549 		canvas_file_system = wrap_into_temporary_filesystem(canvas_file_system, filename, as, truncate_storage_size);
3550 
3551 		// file to open inside canvas file-system
3552 		String canvas_filename = CanvasFileNaming::project_file(filename);
3553 
3554 		etl::handle<synfig::Canvas> canvas = open_canvas_as(canvas_file_system ->get_identifier(canvas_filename), as, errors, warnings);
3555 		if(canvas && get_instance(canvas))
3556 		{
3557 			get_instance(canvas)->find_canvas_view(canvas)->present();
3558 			info("%s is already open", canvas_filename.c_str());
3559 			// throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
3560 		}
3561 		else
3562 		{
3563 			if(!canvas)
3564 				throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
3565 
3566 			if (warnings != "")
3567 				dialog_message_1b(
3568 					"WARNING",
3569 					_("Warning"),
3570 					"details",
3571 					_("Close"),
3572 					warnings);
3573 
3574 			if (as.find(custom_filename_prefix.c_str()) != 0)
3575 				add_recent_file(as);
3576 
3577 			handle<Instance> instance(Instance::create(canvas, container));
3578 
3579 			if(!instance)
3580 				throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
3581 
3582 			one_moment.hide();
3583 
3584 			if(instance->is_updated() && App::dialog_message_2b(
3585 				_("Newer version of this file available on the CVS repository!"),
3586 				_("repository. Would you like to update now? (It would probably be a good idea)"),
3587 				Gtk::MESSAGE_QUESTION,
3588 				_("Cancel"),
3589 				_("Update Anyway"))
3590 			)
3591 				instance->dialog_cvs_update();
3592 		}
3593 	}
3594 	catch(String &x)
3595 	{
3596 		dialog_message_1b(
3597 			"ERROR",
3598 			x,
3599 			"details",
3600 			_("Close"));
3601 
3602 		return false;
3603 	}
3604 	catch(runtime_error &x)
3605 	{
3606 		dialog_message_1b(
3607 			"ERROR",
3608 			x.what(),
3609 			"details",
3610 			_("Close"));
3611 
3612 		return false;
3613 	}
3614 	catch(...)
3615 	{
3616 		dialog_message_1b(
3617 			"ERROR",
3618 			_("Uncaught error on file open (BUG)"),
3619 			"details",
3620 			_("Close"));
3621 
3622 		return false;
3623 	}
3624 
3625 	return true;
3626 }
3627 
3628 // this is called from autorecover.cpp
3629 bool
open_from_temporary_filesystem(std::string temporary_filename)3630 App::open_from_temporary_filesystem(std::string temporary_filename)
3631 {
3632 	try
3633 	{
3634 		OneMoment one_moment;
3635 		String errors, warnings;
3636 
3637 		// try open temporary container
3638 		FileSystemTemporary::Handle file_system_temporary(new FileSystemTemporary(""));
3639 		if (!file_system_temporary->open_temporary(temporary_filename))
3640 			throw (String)strprintf(_("Unable to open temporary container \"%s\"\n\n"), temporary_filename.c_str());
3641 
3642 		// get original filename
3643 		String filename = file_system_temporary->get_meta("filename");
3644 		String as = file_system_temporary->get_meta("as");
3645 		String truncate = file_system_temporary->get_meta("truncate");
3646 		if (filename.empty() || as.empty() || truncate.empty())
3647 			throw (String)strprintf(_("Original filename was not set in temporary container \"%s\"\n\n"), temporary_filename.c_str());
3648 #ifdef __APPLE__
3649 		FileContainerZip::file_size_t truncate_storage_size = atoll(truncate.c_str());
3650 #else
3651 		FileContainerZip::file_size_t truncate_storage_size = stoll(truncate);
3652 #endif
3653 
3654 		// make canvas file-system
3655 		FileSystem::Handle canvas_container = CanvasFileNaming::make_filesystem_container(filename, truncate_storage_size);
3656 		FileSystem::Handle canvas_file_system = CanvasFileNaming::make_filesystem(canvas_container);
3657 
3658 		// wrap into temporary
3659 		file_system_temporary->set_sub_file_system(canvas_file_system);
3660 		canvas_file_system = file_system_temporary;
3661 
3662 		// file to open inside canvas file system
3663 		String canvas_filename = CanvasFileNaming::project_file(canvas_file_system);
3664 
3665 		etl::handle<synfig::Canvas> canvas(open_canvas_as(canvas_file_system->get_identifier(canvas_filename), as, errors, warnings));
3666 		if(canvas && get_instance(canvas))
3667 		{
3668 			get_instance(canvas)->find_canvas_view(canvas)->present();
3669 			info("%s is already open", as.c_str());
3670 			// throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
3671 		}
3672 		else
3673 		{
3674 			if(!canvas)
3675 				throw (String)strprintf(_("Unable to load \"%s\":\n\n"), temporary_filename.c_str()) + errors;
3676 
3677 			if (warnings != "")
3678 				dialog_message_1b(
3679 						"WARNING",
3680 						strprintf("%s:\n\n%s", _("Warning"), warnings.c_str()),
3681 						"details",
3682 						_("Close"));
3683 
3684 			if (as.find(custom_filename_prefix.c_str()) != 0)
3685 				add_recent_file(as);
3686 
3687 			handle<Instance> instance(Instance::create(canvas, canvas_container));
3688 
3689 			if(!instance)
3690 				throw (String)strprintf(_("Unable to create instance for \"%s\""), temporary_filename.c_str());
3691 
3692 			one_moment.hide();
3693 
3694 			if(instance->is_updated() && App::dialog_message_2b(
3695 				_("Newer version of this file avaliable on the CVS repository!"),
3696 				_("Would you like to update now (It would probably be a good idea)"),
3697 				Gtk::MESSAGE_QUESTION,
3698 				_("Cancel"),
3699 				_("Update Anyway"))
3700 			)
3701 				instance->dialog_cvs_update();
3702 
3703 			// This file isn't saved! mark it as such
3704 			instance->inc_action_count();
3705 		}
3706 	}
3707 	catch(String &x)
3708 	{
3709 		dialog_message_1b(
3710 				"ERROR",
3711 				 x,
3712 				"details",
3713 				_("Close"));
3714 
3715 		return false;
3716 	}
3717 	catch(runtime_error &x)
3718 	{
3719 		dialog_message_1b(
3720 				"ERROR",
3721 				x.what(),
3722 				"details",
3723 				_("Close"));
3724 
3725 		return false;
3726 	}
3727 	catch(...)
3728 	{
3729 		dialog_message_1b(
3730 				"ERROR",
3731 				_("Uncaught error on file open (BUG)"),
3732 				"details",
3733 				_("Close"));
3734 
3735 		return false;
3736 	}
3737 
3738 	return true;
3739 }
3740 
3741 
3742 void
new_instance()3743 App::new_instance()
3744 {
3745 	handle<synfig::Canvas> canvas=synfig::Canvas::create();
3746 
3747 	String filename(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
3748 	canvas->set_name(filename);
3749 
3750 	canvas->rend_desc().set_frame_rate(preferred_fps);
3751 	canvas->rend_desc().set_time_start(0.0);
3752 	canvas->rend_desc().set_time_end(5.0);
3753 	canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
3754 	canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
3755 	// The top left and botton right positions are expressed in units
3756 	// Original convention is that 1 unit = 60 pixels
3757 	canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
3758 	canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
3759 	canvas->rend_desc().set_w(preferred_x_size);
3760 	canvas->rend_desc().set_h(preferred_y_size);
3761 	canvas->rend_desc().set_antialias(1);
3762 	canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
3763 	canvas->set_file_name(filename);
3764 	canvas->keyframe_list().add(synfig::Keyframe());
3765 
3766 	FileSystem::Handle container = new FileSystemEmpty();
3767 	FileSystem::Handle file_system = CanvasFileNaming::make_filesystem(container);
3768 	file_system = wrap_into_temporary_filesystem(file_system, filename, filename);
3769 
3770 	// file name inside canvas file-system
3771 	String canvas_filename = CanvasFileNaming::project_file(filename);
3772 	canvas->set_identifier(file_system->get_identifier(canvas_filename));
3773 
3774 	handle<Instance> instance = Instance::create(canvas, container);
3775 
3776 	if (getenv("SYNFIG_AUTO_ADD_SKELETON_LAYER"))
3777 		instance->find_canvas_view(canvas)->add_layer("skeleton");
3778 
3779 	if (getenv("SYNFIG_AUTO_ADD_MOTIONBLUR_LAYER"))
3780 		instance->find_canvas_view(canvas)->add_layer("MotionBlur");
3781 
3782 	if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
3783 		instance->find_canvas_view(canvas)->canvas_properties.present();
3784 }
3785 
3786 void
dialog_open(string filename)3787 App::dialog_open(string filename)
3788 {
3789 	if (filename.empty() && selected_instance)
3790 		filename = selected_instance->get_file_name();
3791 	if (filename.empty())
3792 		filename="*.sif";
3793 
3794 	bool show_history = false;
3795 	while(dialog_open_file_with_history_button(_("Please select a file"), filename, show_history, ANIMATION_DIR_PREFERENCE))
3796 	{
3797 		// If the filename still has wildcards, then we should
3798 		// continue looking for the file we want
3799 		if(find(filename.begin(),filename.end(),'*')!=filename.end())
3800 			continue;
3801 
3802 		FileContainerZip::file_size_t truncate_storage_size = 0;
3803 
3804 		// TODO: ".sfg" literal
3805 		if (show_history && filename_extension(filename) == ".sfg")
3806 		{
3807 			// read history
3808 			std::list<FileContainerZip::HistoryRecord> history
3809 				= FileContainerZip::read_history(filename);
3810 
3811 			// build list of history entries for dialog (descending)
3812 			std::list<std::string> list;
3813 			int index = 0;
3814 			for(std::list<FileContainerZip::HistoryRecord>::const_iterator i = history.begin(); i != history.end(); i++)
3815 				list.push_front(strprintf("%s%d", _("History entry #"), ++index));
3816 
3817 			// show dialog
3818 			index=0;
3819 			if (!dialog_select_list_item(_("Please select a file"), _("Select one of previous versions of file"), list, index))
3820 				continue;
3821 
3822 			// find selected entry in list (descending)
3823 			for(std::list<FileContainerZip::HistoryRecord>::const_reverse_iterator i = history.rbegin(); i != history.rend(); i++)
3824 				if (0 == index--)
3825 					truncate_storage_size = i->storage_size;
3826 		}
3827 
3828 		if(open_as(filename,filename,truncate_storage_size))
3829 			break;
3830 
3831 		get_ui_interface()->error(_("Unable to open file"));
3832 	}
3833 }
3834 
3835 void
set_selected_instance(etl::loose_handle<Instance> instance)3836 App::set_selected_instance(etl::loose_handle<Instance> instance)
3837 {
3838 /*	if(get_selected_instance()==instance)
3839 	{
3840 		selected_instance=instance;
3841 		signal_instance_selected()(instance);
3842 		return;
3843 	}
3844 	else
3845 	{
3846 */
3847 		selected_instance=instance;
3848 		if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
3849 		{
3850 			if(instance)
3851 			{
3852 				instance->focus(instance->get_canvas());
3853 			}
3854 			else
3855 				set_selected_canvas_view(0);
3856 		}
3857 		signal_instance_selected()(instance);
3858 }
3859 
3860 void
set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)3861 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
3862 {
3863 	if(selected_canvas_view != canvas_view)
3864 	{
3865 		etl::loose_handle<CanvasView> prev = selected_canvas_view;
3866 		selected_canvas_view = NULL;
3867 		if (prev) prev->deactivate();
3868 		selected_canvas_view = canvas_view;
3869 		signal_canvas_view_focus()(selected_canvas_view);
3870 		if (selected_canvas_view) selected_canvas_view->activate();
3871 	}
3872 
3873 	if(canvas_view)
3874 	{
3875 		selected_instance=canvas_view->get_instance();
3876 		signal_instance_selected()(selected_instance);
3877 	}
3878 
3879 /*
3880 	if(get_selected_canvas_view()==canvas_view)
3881 	{
3882 		signal_canvas_view_focus()(selected_canvas_view);
3883 		signal_instance_selected()(canvas_view->get_instance());
3884 		return;
3885 	}
3886 	selected_canvas_view=canvas_view;
3887 	if(canvas_view && canvas_view->get_instance() != get_selected_instance())
3888 		set_selected_instance(canvas_view->get_instance());
3889 	signal_canvas_view_focus()(selected_canvas_view);
3890 */
3891 }
3892 
3893 etl::loose_handle<Instance>
get_instance(etl::handle<synfig::Canvas> canvas)3894 App::get_instance(etl::handle<synfig::Canvas> canvas)
3895 {
3896 	if(!canvas) return 0;
3897 	canvas=canvas->get_root();
3898 
3899 	std::list<etl::handle<Instance> >::iterator iter;
3900 	for(iter=instance_list.begin();iter!=instance_list.end();++iter)
3901 	{
3902 		if((*iter)->get_canvas()==canvas)
3903 			return *iter;
3904 	}
3905 	return 0;
3906 }
3907 
3908 void
dialog_about()3909 App::dialog_about()
3910 {
3911 	if(about)
3912 		about->show();
3913 }
3914 
3915 void
undo()3916 studio::App::undo()
3917 {
3918 	if(selected_instance)
3919 		selected_instance->undo();
3920 }
3921 
3922 void
redo()3923 studio::App::redo()
3924 {
3925 	if(selected_instance)
3926 		selected_instance->redo();
3927 }
3928 
3929 synfig::String
get_base_path()3930 studio::App::get_base_path()
3931 {
3932 	return FileSystem::fix_slashes(app_base_path_);
3933 }
3934 
3935 void
setup_changed()3936 studio::App::setup_changed()
3937 {
3938 	std::list<etl::handle<Instance> >::iterator iter;
3939 	for(iter=instance_list.begin();iter!=instance_list.end();++iter)
3940 	{
3941 		std::list< etl::handle<synfigapp::CanvasInterface> >::iterator citer;
3942 		std::list< etl::handle<synfigapp::CanvasInterface> >& cilist((*iter)->canvas_interface_list());
3943 		for(citer=cilist.begin();citer!=cilist.end();++citer)
3944 			{
3945 				(*citer)->signal_rend_desc_changed()();
3946 			}
3947 	}
3948 }
3949 
3950 void
process_all_events()3951 studio::App::process_all_events()
3952 {
3953 	Glib::usleep(1);
3954 	while(studio::App::events_pending()) {
3955 		while(studio::App::events_pending())
3956 			studio::App::iteration(false);
3957 		Glib::usleep(1);
3958 	}
3959 }
3960