// // Copyright (C) 2009 Jordi Mas i Hernandez, jmas@softcatala.org // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.IO; using System.Runtime.InteropServices; using Gdk; using Mistelix.Core; namespace Mistelix.Backends.ThumbnailCache { // // This class uses Gnome-desktop thumbnailing infrastructure for loading and storing thumbnails // It allows to reuse the thumbnails created already by Nautilus and other GNOME applications // // See: http://library.gnome.org/devel/gnome-desktop/stable/ // public class Gnome : Provider { [DllImport ("libgnome-desktop-2")] static extern IntPtr gnome_desktop_thumbnail_factory_new (int size); [DllImport ("libgnome-desktop-2")] // returns GdkPixbuf * static extern IntPtr gnome_desktop_thumbnail_factory_generate_thumbnail (IntPtr factory, string uri, string mime_type); [DllImport ("libgnome-desktop-2")] static extern void gnome_desktop_thumbnail_factory_save_thumbnail (IntPtr factory, IntPtr thumbnail, string uri, ulong time); [DllImport ("libgnome-desktop-2")] static extern IntPtr gnome_desktop_thumbnail_factory_lookup (IntPtr factory, string uri, ulong time); [DllImport("libglib-2.0")] static extern IntPtr g_filename_to_uri (IntPtr filename, IntPtr hostname, IntPtr error); [DllImport("libgio-2.0")] static extern IntPtr g_content_type_guess (IntPtr filename, out byte data, UIntPtr data_size, out bool result_uncertain); [DllImport ("libgio-2.0")] static extern IntPtr g_file_new_for_uri (string uri); [DllImport ("libgio-2.0")] static extern ulong g_file_info_get_attribute_uint64 (IntPtr file, string attribute); [DllImport("libgio-2.0")] // returns GFileInfo * static extern IntPtr g_file_query_info (IntPtr gfile, string attributes, int flags, IntPtr cancellable, out IntPtr error); [DllImport("libgio-2.0")] static extern void g_file_info_get_modification_time (IntPtr raw, IntPtr result); [DllImport("libgobject-2.0")] static extern void g_object_unref (IntPtr raw); IntPtr factory_normal; IntPtr factory_large; const int GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL = 0; const int GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE = 1; public Gnome () { try { GLib.GType.Init (); // The following calls assume that Glib is initialized factory_normal = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL); factory_large = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE); } catch (Exception e) { Logger.Error ("Gnome.Gnome. Unhandled exception {0}", e); } } public override bool Installed { get { return (factory_normal != IntPtr.Zero); } } public override Gdk.Pixbuf GetThumbnail (string filename, int width, int height) { try { IntPtr pix_raw, path_raw, uri_raw, mime_raw, factory_raw, thumbnail_raw; string uri, mime_type, thumbnail_file; byte data; ulong data_size = 0, time; bool result_uncertain; Pixbuf pix; path_raw = GLib.Marshaller.StringToPtrGStrdup (filename); if (path_raw == IntPtr.Zero) return null; // Get URI uri_raw = g_filename_to_uri (path_raw, IntPtr.Zero, IntPtr.Zero); uri = GLib.Marshaller.Utf8PtrToString (uri_raw); factory_raw = (width > 128 || height > 128) ? factory_large : factory_normal; time = GetTimeModified (uri); if (time == 0) return null; // Verifies that the thumbnail exists and it is updated thumbnail_raw = gnome_desktop_thumbnail_factory_lookup (factory_raw, uri, time); thumbnail_file = GLib.Marshaller.Utf8PtrToString (thumbnail_raw); GLib.Marshaller.Free (thumbnail_raw); // Does thumbnail file exists already? if (String.IsNullOrEmpty (thumbnail_file) == false) { Logger.Debug ("Gnome.GetThumbnail. Cached image found {0}", thumbnail_file); GLib.Marshaller.Free (uri_raw); GLib.Marshaller.Free (path_raw); return new Pixbuf (thumbnail_file); } // Get MimeType mime_raw = g_content_type_guess (path_raw, out data, new UIntPtr (data_size), out result_uncertain); mime_type = GLib.Marshaller.PtrToStringGFree (mime_raw); pix_raw = gnome_desktop_thumbnail_factory_generate_thumbnail (factory_raw, uri, mime_type); GLib.Marshaller.Free (uri_raw); GLib.Marshaller.Free (path_raw); pix = new Gdk.Pixbuf (pix_raw); StoreThumbnail (uri, pix); return pix; } catch (Exception e) { Logger.Error ("Gnome.GetThumbnail. Error {0}", e); return null; } } public override void StoreThumbnail (string uri, Gdk.Pixbuf pixbuf) { IntPtr factory_raw; ulong time; try { time = GetTimeModified (uri); if (time == 0) return; factory_raw = (pixbuf.Width > 128 || pixbuf.Height > 128) ? factory_large : factory_normal; gnome_desktop_thumbnail_factory_save_thumbnail (factory_raw, pixbuf.Handle, uri, time); Logger.Debug ("Gnome.StoreThumbnail. Cached image {0}", uri); } catch (Exception e) { Logger.Error ("Gnome.StoreThumbnail. Error {0}", e); return; } } ulong GetTimeModified (string uri) { ulong time; IntPtr file_raw, fileinfo_raw, error_raw; file_raw = g_file_new_for_uri (uri); fileinfo_raw = g_file_query_info (file_raw, "time::modified", 0, IntPtr.Zero, out error_raw); g_object_unref (file_raw); if (fileinfo_raw == IntPtr.Zero) // File not found for example return 0; time = g_file_info_get_attribute_uint64 (fileinfo_raw, "time::modified"); return time; } } }