diff options
Diffstat (limited to 'src/DesktopIntegration.vala')
-rw-r--r-- | src/DesktopIntegration.vala | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/src/DesktopIntegration.vala b/src/DesktopIntegration.vala new file mode 100644 index 0000000..ebdc45e --- /dev/null +++ b/src/DesktopIntegration.vala @@ -0,0 +1,308 @@ +/* Copyright 2009-2014 Yorba Foundation + * + * This software is licensed under the GNU Lesser General Public License + * (version 2.1 or later). See the COPYING file in this distribution. + */ + +namespace DesktopIntegration { + +private const string SENDTO_EXEC = "nautilus-sendto"; +private const string DESKTOP_SLIDESHOW_XML_FILENAME = "wallpaper.xml"; + +private int init_count = 0; +private bool send_to_installed = false; +private ExporterUI send_to_exporter = null; +private ExporterUI desktop_slideshow_exporter = null; +private double desktop_slideshow_transition = 0.0; +private double desktop_slideshow_duration = 0.0; + +public void init() { + if (init_count++ != 0) + return; + + send_to_installed = Environment.find_program_in_path(SENDTO_EXEC) != null; +} + +public void terminate() { + if (--init_count == 0) + return; +} + +public AppInfo? get_default_app_for_mime_types(string[] mime_types, + Gee.ArrayList<string> preferred_apps) { + SortedList<AppInfo> external_apps = get_apps_for_mime_types(mime_types); + + foreach (string preferred_app in preferred_apps) { + foreach (AppInfo external_app in external_apps) { + if (external_app.get_name().contains(preferred_app)) + return external_app; + } + } + + return null; +} + +// compare the app names, case insensitive +public static int64 app_info_comparator(void *a, void *b) { + return ((AppInfo) a).get_name().down().collate(((AppInfo) b).get_name().down()); +} + +public SortedList<AppInfo> get_apps_for_mime_types(string[] mime_types) { + SortedList<AppInfo> external_apps = new SortedList<AppInfo>(app_info_comparator); + + if (mime_types.length == 0) + return external_apps; + + // 3 loops because SortedList.contains() wasn't paying nicely with AppInfo, + // probably because it has a special equality function + foreach (string mime_type in mime_types) { + string content_type = ContentType.from_mime_type(mime_type); + if (content_type == null) + break; + + foreach (AppInfo external_app in + AppInfo.get_all_for_type(content_type)) { + bool already_contains = false; + + foreach (AppInfo app in external_apps) { + if (app.get_name() == external_app.get_name()) { + already_contains = true; + break; + } + } + + // dont add Shotwell to app list + if (!already_contains && !external_app.get_name().contains(Resources.APP_TITLE)) + external_apps.add(external_app); + } + } + + return external_apps; +} + +public string? get_app_open_command(AppInfo app_info) { + string? str = app_info.get_commandline(); + + return str != null ? str : app_info.get_executable(); +} + +public bool is_send_to_installed() { + return send_to_installed; +} + +public void files_send_to(File[] files) { + if (files.length == 0) + return; + + string[] argv = new string[files.length + 1]; + argv[0] = SENDTO_EXEC; + + for (int ctr = 0; ctr < files.length; ctr++) + argv[ctr + 1] = files[ctr].get_path(); + + try { + AppWindow.get_instance().set_busy_cursor(); + + Pid child_pid; + Process.spawn_async( + "/", + argv, + null, // environment + SpawnFlags.SEARCH_PATH, + null, // child setup + out child_pid); + + AppWindow.get_instance().set_normal_cursor(); + } catch (Error err) { + AppWindow.get_instance().set_normal_cursor(); + AppWindow.error_message(_("Unable to launch Nautilus Send-To: %s").printf(err.message)); + } +} + +public void send_to(Gee.Collection<MediaSource> media) { + if (media.size == 0 || send_to_exporter != null) + return; + + ExportDialog dialog = new ExportDialog(_("Send To")); + + // determine the mix of media in the export collection -- if it contains only + // videos then we can use the Video.export_many( ) fast path and not have to + // worry about ExportFormatParameters or the Export... dialog + if (MediaSourceCollection.has_video(media) && !MediaSourceCollection.has_photo(media)) { + send_to_exporter = Video.export_many((Gee.Collection<Video>) media, + on_send_to_export_completed, true); + return; + } + + int scale; + ScaleConstraint constraint; + ExportFormatParameters export_params = ExportFormatParameters.current(); + if (!dialog.execute(out scale, out constraint, ref export_params)) + return; + + send_to_exporter = new ExporterUI(new Exporter.for_temp_file(media, + Scaling.for_constraint(constraint, scale, false), export_params)); + send_to_exporter.export(on_send_to_export_completed); +} + +private void on_send_to_export_completed(Exporter exporter, bool is_cancelled) { + if (!is_cancelled) + files_send_to(exporter.get_exported_files()); + + send_to_exporter = null; +} + +public void set_background(Photo photo) { + // attempt to set the wallpaper to the photo's native format, but if not writeable, go to the + // system default + PhotoFileFormat file_format = photo.get_best_export_file_format(); + + File save_as = AppDirs.get_data_subdir("wallpaper").get_child( + file_format.get_default_basename("wallpaper")); + + if (Config.Facade.get_instance().get_desktop_background() == save_as.get_path()) { + save_as = AppDirs.get_data_subdir("wallpaper").get_child( + file_format.get_default_basename("wallpaper_alt")); + } + + try { + photo.export(save_as, Scaling.for_original(), Jpeg.Quality.HIGH, file_format); + } catch (Error err) { + AppWindow.error_message(_("Unable to export background to %s: %s").printf(save_as.get_path(), + err.message)); + + return; + } + + Config.Facade.get_instance().set_desktop_background(save_as.get_path()); + + GLib.FileUtils.chmod(save_as.get_parse_name(), 0644); +} + +// Helper class for set_background_slideshow() +// Used to build xml file that describes background +// slideshow for Gnome +private class BackgroundSlideshowXMLBuilder { + private File destination; + private double duration; + private double transition; + private File tmp_file; + private DataOutputStream? outs = null; + private File? first_file = null; + private File? last_file = null; + + public BackgroundSlideshowXMLBuilder(File destination, double duration, double transition) { + this.destination = destination; + this.duration = duration; + this.transition = transition; + + tmp_file = destination.get_parent().get_child(destination.get_basename() + ".tmp"); + } + + public void open() throws Error { + outs = new DataOutputStream(tmp_file.replace(null, false, FileCreateFlags.NONE, null)); + outs.put_string("<background>\n"); + } + + private void write_transition(File from, File to) throws Error { + outs.put_string(" <transition>\n"); + outs.put_string(" <duration>%2.2f</duration>\n".printf(transition)); + outs.put_string(" <from>%s</from>\n".printf(from.get_path())); + outs.put_string(" <to>%s</to>\n".printf(to.get_path())); + outs.put_string(" </transition>\n"); + } + + private void write_static(File file) throws Error { + outs.put_string(" <static>\n"); + outs.put_string(" <duration>%2.2f</duration>\n".printf(duration)); + outs.put_string(" <file>%s</file>\n".printf(file.get_path())); + outs.put_string(" </static>\n"); + } + + public void add_photo(File file) throws Error { + assert(outs != null); + + if (first_file == null) + first_file = file; + + if (last_file != null) + write_transition(last_file, file); + + write_static(file); + + last_file = file; + } + + public File? close() throws Error { + if (outs == null) + return null; + + // transition back to first file + if (first_file != null && last_file != null) + write_transition(last_file, first_file); + + outs.put_string("</background>\n"); + + outs.close(); + outs = null; + + // move to destination name + tmp_file.move(destination, FileCopyFlags.OVERWRITE); + GLib.FileUtils.chmod(destination.get_parse_name(), 0644); + + return destination; + } +} + +public void set_background_slideshow(Gee.Collection<Photo> photos, double duration, double transition) { + if (desktop_slideshow_exporter != null) + return; + + File wallpaper_dir = AppDirs.get_data_subdir("wallpaper"); + + Gee.Set<string> exceptions = new Gee.HashSet<string>(); + exceptions.add(DESKTOP_SLIDESHOW_XML_FILENAME); + try { + delete_all_files(wallpaper_dir, exceptions); + } catch (Error err) { + warning("Error attempting to clear wallpaper directory: %s", err.message); + } + + desktop_slideshow_duration = duration; + desktop_slideshow_transition = transition; + + Exporter exporter = new Exporter(photos, wallpaper_dir, + Scaling.to_fill_screen(AppWindow.get_instance()), ExportFormatParameters.current(), + true); + desktop_slideshow_exporter = new ExporterUI(exporter); + desktop_slideshow_exporter.export(on_desktop_slideshow_exported); +} + +private void on_desktop_slideshow_exported(Exporter exporter, bool is_cancelled) { + desktop_slideshow_exporter = null; + + if (is_cancelled) + return; + + File? xml_file = null; + BackgroundSlideshowXMLBuilder xml_builder = new BackgroundSlideshowXMLBuilder( + AppDirs.get_data_subdir("wallpaper").get_child(DESKTOP_SLIDESHOW_XML_FILENAME), + desktop_slideshow_duration, desktop_slideshow_transition); + try { + xml_builder.open(); + + foreach (File file in exporter.get_exported_files()) + xml_builder.add_photo(file); + + xml_file = xml_builder.close(); + } catch (Error err) { + AppWindow.error_message(_("Unable to prepare desktop slideshow: %s").printf( + err.message)); + + return; + } + + Config.Facade.get_instance().set_desktop_background(xml_file.get_path()); +} + +} |