X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=synfig-studio%2Ftrunk%2Fsrc%2Fgtkmm%2Fapp.cpp;h=feb0c025df21bd97e2685f09348b7cdd72f07a27;hb=071939c9c44d0080e0843381adc19a6600f0fd69;hp=a9ed079fdeca25402066b4ae037bf6cc6ff1b482;hpb=5ae44bc4ae0f4410fd2830e7e42d4a7629d68e69;p=synfig.git diff --git a/synfig-studio/trunk/src/gtkmm/app.cpp b/synfig-studio/trunk/src/gtkmm/app.cpp index a9ed079..feb0c02 100644 --- a/synfig-studio/trunk/src/gtkmm/app.cpp +++ b/synfig-studio/trunk/src/gtkmm/app.cpp @@ -6,7 +6,8 @@ ** ** \legal ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2007 Chris Moore +** Copyright (c) 2007, 2008 Chris Moore +** Copyright (c) 2008 Gerald Young ** ** This package is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License as @@ -30,6 +31,11 @@ # include #endif +#ifdef WIN32 +#define WINVER 0x0500 +#include +#endif + #include #include #include @@ -51,6 +57,8 @@ #include +#include + #include #include @@ -119,10 +127,6 @@ #include #endif -#ifdef WIN32 -#define _WIN32_WINNT 0x0500 -#include -#endif #include #include #include @@ -203,6 +207,8 @@ App::signal_instance_deleted() { return signal_instance_deleted_; } static std::list recent_files; const std::list& App::get_recent_files() { return recent_files; } +static std::list recent_files_window_size; + int App::Busy::count; bool App::shutdown_in_progress; @@ -261,7 +267,15 @@ studio::Dock_Curves* dock_curves; std::list< etl::handle< studio::Module > > module_list_; bool studio::App::use_colorspace_gamma=true; +#ifdef SINGLE_THREADED bool studio::App::single_threaded=false; +#endif +bool studio::App::restrict_radius_ducks=false; +#ifdef USE_OPEN_FOR_URLS +String studio::App::browser_command("open"); // MacOS only +#else +String studio::App::browser_command("xdg-open"); // Linux XDG standard +#endif static int max_recent_files_=25; int studio::App::get_max_recent_files() { return max_recent_files_; } @@ -472,16 +486,28 @@ public: value=strprintf("%s",Distance::system_name(App::distance_system).c_str()); return true; } +#ifdef SINGLE_THREADED if(key=="single_threaded") { value=strprintf("%i",(int)App::single_threaded); return true; } +#endif if(key=="auto_recover_backup_interval") { value=strprintf("%i",App::auto_recover->get_timeout()); return true; } + if(key=="restrict_radius_ducks") + { + value=strprintf("%i",(int)App::restrict_radius_ducks); + return true; + } + if(key=="browser_command") + { + value=App::browser_command; + return true; + } return synfigapp::Settings::get_value(key,value); } @@ -532,12 +558,25 @@ public: App::distance_system=Distance::ident_system(value);; return true; } +#ifdef SINGLE_THREADED if(key=="single_threaded") { int i(atoi(value.c_str())); App::single_threaded=i; return true; } +#endif + if(key=="restrict_radius_ducks") + { + int i(atoi(value.c_str())); + App::restrict_radius_ducks=i; + return true; + } + if(key=="browser_command") + { + App::browser_command=value; + return true; + } return synfigapp::Settings::set_value(key,value); } @@ -550,8 +589,12 @@ public: ret.push_back("distance_system"); ret.push_back("file_history.size"); ret.push_back("use_colorspace_gamma"); +#ifdef SINGLE_THREADED ret.push_back("single_threaded"); +#endif ret.push_back("auto_recover_backup_interval"); + ret.push_back("restrict_radius_ducks"); + ret.push_back("browser_command"); return ret; } }; @@ -1031,7 +1074,6 @@ App::App(int *argc, char ***argv): Glib::set_application_name(_("Synfig Studio")); Splash splash_screen; - splash_screen.set_can_self_destruct(false); splash_screen.show(); shutdown_in_progress=false; @@ -1289,7 +1331,12 @@ App::~App() String App::get_user_app_directory() { +//! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445) +#ifdef WIN32 + return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR)); +#else return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR); +#endif } synfig::String @@ -1298,8 +1345,115 @@ App::get_config_file(const synfig::String& file) return Glib::build_filename(get_user_app_directory(),file); } +#define SCALE_FACTOR (1280) +//! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size +void +App::set_recent_file_window_size(etl::handle instance) +{ + int screen_w(Gdk::screen_width()); + int screen_h(Gdk::screen_height()); + + const std::string &canvas_window_size = *recent_files_window_size.begin(); + + if(canvas_window_size.empty()) + return; + + synfig::String::size_type current=0; + bool seen_root(false), shown_non_root(false); + + while(current != synfig::String::npos) + { + // find end of first field (canvas) or return + synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current); + if(separator == synfig::String::npos) break; + + // find the canvas + synfig::Canvas::Handle canvas; + try { + canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current)); + } + catch(Exception::IDNotFound) { + // can't find the canvas; skip to the next canvas or return + separator = canvas_window_size.find_first_of('\t', current); + if(separator == synfig::String::npos) return; + current = separator+1; + continue; + } + + if (canvas->is_root()) + seen_root = true; + else + shown_non_root = true; + + // check that we have the tab character the ends this canvas' data or return + current = separator+1; + separator = canvas_window_size.find_first_of('\t', current); + if(separator == synfig::String::npos) return; + + int x,y,w,h; + if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h)) + { + current = separator+1; + continue; + } + + if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0; + if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0; + x=x*screen_w/SCALE_FACTOR; + y=y*screen_h/SCALE_FACTOR; + if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET")) + x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET")); + if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET")) + y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET")); + + if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0; + if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0; + + CanvasView::Handle canvasview = instance->find_canvas_view(canvas); + canvasview->move(x,y); + canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR); + canvasview->present(); + + current = separator+1; + } + + if (shown_non_root && !seen_root) + instance->find_canvas_view(instance->get_canvas())->hide(); +} + +void +App::add_recent_file(const etl::handle instance) +{ + int screen_w(Gdk::screen_width()); + int screen_h(Gdk::screen_height()); + + std::string canvas_window_size; + + const Instance::CanvasViewList& cview_list = instance->canvas_view_list(); + Instance::CanvasViewList::const_iterator iter; + + for(iter=cview_list.begin();iter!=cview_list.end();iter++) + { + if( !((*iter)->is_visible()) ) + continue; + + etl::handle canvas = (*iter)->get_canvas(); + int x_pos, y_pos, x_size, y_size; + (*iter)->get_position(x_pos,y_pos); + (*iter)->get_size(x_size,y_size); + + canvas_window_size += strprintf("%s %d %d %d %d\t", + canvas->get_relative_id(canvas->get_root()).c_str(), + x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h, + x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h); + } + + add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size); +} +#undef SCALE_FACTOR + void -App::add_recent_file(const std::string &file_name) +App::add_recent_file(const std::string &file_name, const std::string &window_size) { std::string filename(file_name); @@ -1316,23 +1470,35 @@ App::add_recent_file(const std::string &file_name) if(!is_absolute_path(filename)) filename=absolute_path(filename); + std::string old_window_size; + list::iterator iter; + list::iterator iter_wsize; // Check to see if the file is already on the list. // If it is, then remove it from the list - for(iter=recent_files.begin();iter!=recent_files.end();iter++) + for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++) if(*iter==filename) { recent_files.erase(iter); + old_window_size = *iter_wsize; + recent_files_window_size.erase(iter_wsize); break; } // Push the filename to the front of the list recent_files.push_front(filename); + if(window_size.empty()) + recent_files_window_size.push_front(old_window_size); + else + recent_files_window_size.push_front(window_size); // Clean out the files at the end of the list. while(recent_files.size()>(unsigned)get_max_recent_files()) + { recent_files.pop_back(); + recent_files_window_size.pop_back(); + } signal_recent_files_changed_(); @@ -1382,7 +1548,23 @@ App::save_settings() for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++) file<<*iter<::reverse_iterator iter; + + for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++) + file<<*iter<add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT); - Widget_Enum *file_type_enum; + Widget_Enum *file_type_enum = 0; if (preference == ANIMATION_DIR_PREFERENCE) { file_type_enum = manage(new Widget_Enum()); - file_type_enum->set_param_desc(ParamDesc("filetype") - .set_hint("enum") - .add_enum_value(synfig::FILE_VERSION_0_61_08, "0.61.08", "0.61.08") - .add_enum_value(synfig::FILE_VERSION_0_61_07, "0.61.07", "0.61.07")); - file_type_enum->set_value(0); + file_type_enum->set_param_desc(ParamDesc().set_hint("enum") + .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current"))) + .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08") + .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07") + .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older")))); + file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version Gtk::HBox *hbox = manage(new Gtk::HBox); - hbox->pack_start(*manage(new Gtk::Label(_("File Type: "))),Gtk::PACK_SHRINK,0); + hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0); hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0); hbox->show_all(); @@ -1791,7 +2002,7 @@ App::dialog_save_file(const std::string &title, std::string &filename, std::stri if(dialog->run() == GTK_RESPONSE_ACCEPT) { if (preference == ANIMATION_DIR_PREFERENCE) - set_file_version(synfig::FileVersion(file_type_enum->get_value())); + set_file_version(synfig::ReleaseVersion(file_type_enum->get_value())); filename = dialog->get_filename(); info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str()); _preferences.set_value(preference, dirname(filename)); @@ -1867,6 +2078,106 @@ App::dialog_not_implemented() dialog.run(); } +static bool +try_open_url(const std::string &url) +{ +#ifdef WIN32 + return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW); +#else // !WIN32 + std::vector command_line; + std::vector browsers; + browsers.reserve(23); + + // Browser wrapper scripts +#ifdef USE_OPEN_FOR_URLS + browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console +#endif + browsers.push_back("xdg-open"); // XDG wrapper + browsers.push_back("sensible-browser"); // Debian wrapper + browsers.push_back("gnome-open"); // GNOME wrapper + browsers.push_back("kfmclient"); // KDE wrapper + browsers.push_back("exo-open"); // XFCE wrapper + + // Alternatives system + browsers.push_back("gnome-www-browser"); // Debian GNOME alternative + browsers.push_back("x-www-browser"); // Debian GUI alternative + + // Individual browsers + browsers.push_back("firefox"); + browsers.push_back("epiphany-browser"); + browsers.push_back("epiphany"); + browsers.push_back("konqueror"); + browsers.push_back("iceweasel"); + browsers.push_back("mozilla"); + browsers.push_back("netscape"); + browsers.push_back("icecat"); + browsers.push_back("galeon"); + browsers.push_back("midori"); + browsers.push_back("safari"); + browsers.push_back("opera"); + browsers.push_back("amaya"); + browsers.push_back("netsurf"); + browsers.push_back("dillo"); + + // Try the user-specified browser first + command_line.push_back(App::browser_command); + if( command_line[0] == "kfmclient" ) command_line.push_back("openURL"); + command_line.push_back(url); + + try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; } + catch( Glib::SpawnError& exception ){ + + while ( !browsers.empty() ) + { + // Skip the browser if we already tried it + if( browsers[0] == App::browser_command ) + continue; + + // Construct the command line + command_line.clear(); + command_line.push_back(browsers[0]); + if( command_line[0] == "kfmclient" ) command_line.push_back("openURL"); + command_line.push_back(url); + + // Remove the browser from the list + browsers.erase(browsers.begin()); + + // Try to spawn the browser + try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); } + // Failed, move on to the next one + catch(Glib::SpawnError& exception){ continue; } + return true; // No exception means we succeeded! + } + } + + return false; +#endif // !WIN32 +} + +void +App::dialog_help() +{ + if (!try_open_url("http://synfig.org/Documentation")) + { + Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true); + dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation")); + dialog.set_title(_("Help")); + dialog.run(); + } +} + +void +App::open_url(const std::string &url) +{ + if(!try_open_url(url)) + { + Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true); + dialog.set_secondary_text(url); + dialog.set_title(_("No browser found")); + dialog.run(); + } +} + bool App::dialog_entry(const std::string &title, const std::string &message,std::string &text) { @@ -1917,7 +2228,10 @@ App::open_as(std::string filename,std::string as) #ifdef WIN32 char long_name[1024]; if(GetLongPathName(as.c_str(),long_name,sizeof(long_name))); - as=long_name; + // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty + // don't use it if that's the case + if (long_name[0] != '\0') + as=long_name; #endif try @@ -1936,13 +2250,16 @@ App::open_as(std::string filename,std::string as) if(!canvas) throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str()); - add_recent_file(as); + if (as.find(DEFAULT_FILENAME_PREFIX) != 0) + add_recent_file(as); handle instance(Instance::create(canvas)); if(!instance) throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str()); + set_recent_file_window_size(instance); + one_moment.hide(); if(instance->is_updated() && App::dialog_yes_no(_("CVS Update"), _("There appears to be a newer version of this file available on the CVS repository.\nWould you like to update now? (It would probably be a good idea)"))) @@ -1968,9 +2285,10 @@ void App::new_instance() { handle canvas=synfig::Canvas::create(); - canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1)); - String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1)); + String file_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1)); + canvas->set_name(file_name); + file_name += ".sifz"; canvas->rend_desc().set_frame_rate(24.0); canvas->rend_desc().set_time_start(0.0); @@ -1992,9 +2310,10 @@ App::new_instance() } void -App::dialog_open() +App::dialog_open(string filename) { - string filename="*.sif"; + if (filename.empty()) + filename="*.sif"; while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE)) {