New test.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / MimeIcon.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //
24 //  Alexander Olk       xenomorph2@onlinehome.de
25 //
26
27 // use
28 // public static int GetIconIndexForFile( string full_filename )
29 // public static int GetIconIndexForMimeType( string mime_type )
30 // to get the image index in MimeIconEngine.SmallIcons and MimeIconEngine.LargeIcons
31
32 using System;
33 using System.Reflection;
34 using System.Drawing;
35 using System.Collections;
36 //using System.Collections.Specialized;
37 using System.IO;
38 using System.Text;
39 using System.Runtime.InteropServices;
40 using System.Xml;
41
42 namespace System.Windows.Forms
43 {
44         internal enum MimeExtensionHandlerStatus
45         {
46                 OK,
47                 ERROR
48         }
49         
50         internal enum EPlatformHandler
51         {
52                 Default,
53                 GNOME
54         }
55         
56         internal class ResourceImageLoader
57         {
58                 static Assembly assembly = typeof (ResourceImageLoader).Assembly;
59                 
60                 static internal Bitmap Get (string name)
61                 {
62                         using (Stream stream = assembly.GetManifestResourceStream (name)) {
63                                 if (stream == null) {
64                                         Console.WriteLine ("Failed to read {0}", name);
65                                         return null;
66                                 }
67                                 
68                                 return new Bitmap (stream);
69                         }
70                 }
71         }
72         
73         internal class MimeIconEngine
74         {
75                 public static ImageList SmallIcons = new ImageList();
76                 public static ImageList LargeIcons = new ImageList();
77                 
78                 private static EPlatformHandler platform = EPlatformHandler.Default;
79                 
80                 internal static Hashtable MimeIconIndex = new Hashtable ();
81                 
82                 private static PlatformMimeIconHandler platformMimeHandler = null;
83                 
84                 private static object lock_object = new Object();
85                 
86                 static MimeIconEngine ()
87                 {
88                         SmallIcons.ColorDepth = ColorDepth.Depth32Bit;
89                         SmallIcons.TransparentColor = Color.Transparent;
90                         LargeIcons.ColorDepth = ColorDepth.Depth32Bit;
91                         LargeIcons.TransparentColor = Color.Transparent;
92                         
93                         string session =  Environment.GetEnvironmentVariable ("DESKTOP_SESSION");
94                         
95                         if (session != null) {
96                                 session = session.ToUpper ();
97                                 
98                                 if (session == "DEFAULT") {
99                                         string helper = Environment.GetEnvironmentVariable ("GNOME_DESKTOP_SESSION_ID");
100                                         
101                                         if (helper != null)
102                                                 session = "GNOME";
103                                 }
104                         } else
105                                 session = "";
106                         
107                         if (session == "GNOME") {
108                                 SmallIcons.ImageSize = new Size (24, 24);
109                                 LargeIcons.ImageSize = new Size (48, 48);
110                                 
111                                 platformMimeHandler = new GnomeHandler ();
112                                 if (platformMimeHandler.Start () == MimeExtensionHandlerStatus.OK) {
113                                         platform = EPlatformHandler.GNOME;
114                                 } else {
115                                         MimeIconEngine.LargeIcons.Images.Clear ();
116                                         MimeIconEngine.SmallIcons.Images.Clear ();
117                                         platformMimeHandler = new PlatformDefaultHandler ();
118                                         platformMimeHandler.Start ();
119                                 }
120                         } else {
121                                 SmallIcons.ImageSize = new Size (16, 16);
122                                 LargeIcons.ImageSize = new Size (48, 48);
123                                 
124                                 platformMimeHandler = new PlatformDefaultHandler ();
125                                 platformMimeHandler.Start ();
126                         }
127                 }
128                 
129                 public static int GetIconIndexForFile (string full_filename)
130                 {
131                         lock (lock_object) {
132                                 string mime_type = Mime.GetMimeTypeForFile (full_filename);
133                                 
134                                 if (platform == EPlatformHandler.Default) {
135                                         if (mime_type == "inode/directory") {
136                                                 return (int)MimeIconIndex ["inode/directory"];
137                                         } else {
138                                                 return (int)MimeIconIndex ["unknown/unknown"];
139                                         }
140                                 }
141                                 
142                                 object oindex = GetIconIndex (mime_type);
143                                 
144                                 // not found, add it
145                                 if (oindex == null) {
146                                         int index = full_filename.IndexOf (':');
147                                         
148                                         if (index > 1) {
149                                                 oindex = MimeIconIndex ["unknown/unknown"];
150                                                 
151                                         } else {
152                                                 oindex = platformMimeHandler.AddAndGetIconIndex (full_filename, mime_type);
153                                                 
154                                                 // sanity check
155                                                 if (oindex == null)
156                                                         oindex = MimeIconIndex ["unknown/unknown"];
157                                         }
158                                 }
159                                 
160                                 return (int)oindex;
161                         }
162                 }
163                 
164                 public static int GetIconIndexForMimeType (string mime_type)
165                 {
166                         lock (lock_object) {
167                                 if (platform == EPlatformHandler.Default) {
168                                         if (mime_type == "inode/directory") {
169                                                 return (int)MimeIconIndex ["inode/directory"];
170                                         } else {
171                                                 return (int)MimeIconIndex ["unknown/unknown"];
172                                         }
173                                 }
174                                 
175                                 object oindex = GetIconIndex (mime_type);
176                                 
177                                 // not found, add it
178                                 if (oindex == null) {
179                                         oindex = platformMimeHandler.AddAndGetIconIndex (mime_type);
180                                         
181                                         // sanity check
182                                         if (oindex == null)
183                                                 oindex = MimeIconIndex ["unknown/unknown"];
184                                 }
185                                 
186                                 return (int)oindex;
187                         }
188                 }
189                 
190                 public static Image GetIconForMimeTypeAndSize (string mime_type, Size size)
191                 {
192                         lock (lock_object) {
193                                 object oindex = GetIconIndex (mime_type);
194                                 
195                                 Bitmap bmp = new Bitmap (LargeIcons.Images [(int)oindex], size);
196                                 
197                                 return bmp;
198                         }
199                 }
200                 
201                 internal static void AddIconByImage (string mime_type, Image image)
202                 {
203                         int index = SmallIcons.Images.Add (image, Color.Transparent);
204                         LargeIcons.Images.Add (image, Color.Transparent);
205                         
206                         MimeIconIndex.Add (mime_type, index);
207                 }
208                 
209                 private static object GetIconIndex (string mime_type)
210                 {
211                         object oindex = null;
212                         
213                         if (mime_type != null) {
214                                 // first check if mime_type is available in the mimetype/icon hashtable
215                                 oindex = MimeIconIndex [mime_type];
216                                 
217                                 if (oindex == null) {
218                                         // it is not available, check if an alias exist for mime_type
219                                         string alias = Mime.GetMimeAlias (mime_type);
220                                         
221                                         if (alias != null) {
222                                                 string[] split = alias.Split (new char [] { ',' });
223                                                 
224                                                 for (int i = 0; i < split.Length; i++) {
225                                                         oindex = MimeIconIndex [split [i]];
226                                                         
227                                                         if (oindex != null)
228                                                                 return oindex;
229                                                 }
230                                         }
231                                         
232                                         // if oindex is still null check if mime_type is a sub class of an other mime type
233                                         string sub_class = Mime.SubClasses [mime_type];
234                                         
235                                         if (sub_class != null) {
236                                                 oindex = MimeIconIndex [sub_class];
237                                                 
238                                                 if (oindex != null)
239                                                         return oindex;
240                                         }
241                                         
242                                         // last check, see if we find an entry for the main mime type class
243                                         string mime_class_main = mime_type.Substring (0, mime_type.IndexOf ('/'));
244                                         return MimeIconIndex [mime_class_main];
245                                 }
246                         }
247                         
248                         return oindex;
249                 }
250         }
251         
252         internal abstract class PlatformMimeIconHandler
253         {
254                 protected MimeExtensionHandlerStatus mimeExtensionHandlerStatus = MimeExtensionHandlerStatus.OK;
255                 
256                 public MimeExtensionHandlerStatus MimeExtensionHandlerStatus {
257                         get {
258                                 return mimeExtensionHandlerStatus;
259                         }
260                 }
261                 
262                 public abstract MimeExtensionHandlerStatus Start ();
263                 
264                 public virtual object AddAndGetIconIndex (string filename, string mime_type)
265                 {
266                         return null;
267                 }
268                 
269                 public virtual object AddAndGetIconIndex (string mime_type)
270                 {
271                         return null;
272                 }
273         }
274         
275         internal class PlatformDefaultHandler : PlatformMimeIconHandler
276         {
277                 public override MimeExtensionHandlerStatus Start ()
278                 {
279                         MimeIconEngine.AddIconByImage ("inode/directory",  ResourceImageLoader.Get ("folder.png"));
280                         MimeIconEngine.AddIconByImage ("unknown/unknown",  ResourceImageLoader.Get ("text-x-generic.png"));
281                         MimeIconEngine.AddIconByImage ("desktop/desktop",  ResourceImageLoader.Get ("user-desktop.png"));
282                         MimeIconEngine.AddIconByImage ("directory/home",  ResourceImageLoader.Get ("user-home.png"));
283                         
284                         // fix
285                         MimeIconEngine.AddIconByImage ("network/network",  ResourceImageLoader.Get ("document-open.png"));
286                         MimeIconEngine.AddIconByImage ("recently/recently",  ResourceImageLoader.Get ("document-open.png"));
287                         MimeIconEngine.AddIconByImage ("workplace/workplace",  ResourceImageLoader.Get ("document-open.png"));
288                         
289                         return MimeExtensionHandlerStatus.OK; // return always ok
290                 }
291         }
292         
293         internal class GnomeHandler : PlatformMimeIconHandler
294         {
295                 public override MimeExtensionHandlerStatus Start ()
296                 {
297                         CreateUIIcons ();
298                         
299                         return MimeExtensionHandlerStatus.OK;
300                 }
301                 
302                 private void CreateUIIcons ()
303                 {
304                         AddGnomeIcon ("unknown/unknown", "gnome-fs-regular");
305                         AddGnomeIcon ("inode/directory", "gnome-fs-directory");
306                         AddGnomeIcon ("directory/home", "gnome-fs-home");
307                         AddGnomeIcon ("desktop/desktop", "gnome-fs-desktop");
308                         AddGnomeIcon ("recently/recently", "gnome-fs-directory-accept");
309                         AddGnomeIcon ("workplace/workplace", "gnome-fs-client");
310                         
311                         AddGnomeIcon ("network/network", "gnome-fs-network");
312                         AddGnomeIcon ("nfs/nfs", "gnome-fs-nfs");
313                         AddGnomeIcon ("smb/smb", "gnome-fs-smb");
314                         
315                         AddGnomeIcon ("harddisk/harddisk", "gnome-dev-harddisk");
316                         AddGnomeIcon ("cdrom/cdrom", "gnome-dev-cdrom");
317                         AddGnomeIcon ("removable/removable", "gnome-dev-removable");
318                 }
319                 
320                 private void AddGnomeIcon (string internal_mime_type, string name)
321                 {
322                         int index = -1;
323                         
324                         if (MimeIconEngine.MimeIconIndex.ContainsKey (internal_mime_type)) {
325                                 return;
326                         }
327                         
328                         Image image = GnomeUtil.GetIcon (name, 48);
329                         
330                         index = MimeIconEngine.SmallIcons.Images.Add (image, Color.Transparent);
331                         MimeIconEngine.LargeIcons.Images.Add (image, Color.Transparent);
332                         
333                         MimeIconEngine.MimeIconIndex.Add (internal_mime_type, index);
334                 }
335                 
336                 public override object AddAndGetIconIndex (string filename, string mime_type)
337                 {
338                         int index = -1;
339                         
340                         Image image = GnomeUtil.GetIcon (filename, mime_type, 48);
341                         
342                         index = MimeIconEngine.SmallIcons.Images.Add (image, Color.Transparent);
343                         MimeIconEngine.LargeIcons.Images.Add (image, Color.Transparent);
344                         
345                         MimeIconEngine.MimeIconIndex.Add (mime_type, index);
346                         
347                         return index;
348                 }
349                 
350                 public override object AddAndGetIconIndex (string mime_type)
351                 {
352                         int index = -1;
353                         
354                         Image image = GnomeUtil.GetIcon (mime_type, 48);
355                         
356                         index = MimeIconEngine.SmallIcons.Images.Add (image, Color.Transparent);
357                         MimeIconEngine.LargeIcons.Images.Add (image, Color.Transparent);
358                         
359                         MimeIconEngine.MimeIconIndex.Add (mime_type, index);
360                         
361                         return index;
362                 }
363         }
364         
365         internal class GnomeUtil
366         {
367                 [DllImport("librsvg-2.so")]
368                 static extern IntPtr rsvg_pixbuf_from_file_at_size (string file_name, int  width, int  height, out IntPtr error);
369                 
370                 [DllImport("libgdk-x11-2.0.so.0")]
371                 static extern bool gdk_pixbuf_save_to_buffer (IntPtr pixbuf, out IntPtr buffer, out UIntPtr buffer_size, string type, out IntPtr error, IntPtr option_dummy);
372                 
373                 [DllImport("libglib-2.0.so")]
374                 static extern void g_free (IntPtr mem);
375                 
376                 [DllImport("libgdk-x11-2.0.so.0")]
377                 static extern bool gdk_init_check (IntPtr argc, IntPtr argv);
378                 
379                 [DllImport("libgobject-2.0.so")]
380                 static extern void g_object_unref (IntPtr nativeObject);
381                 
382                 [DllImport("libgnomeui-2.so.0")]
383                 static extern string gnome_icon_lookup (IntPtr icon_theme, IntPtr thumbnail_factory, string file_uri, string custom_icon, IntPtr file_info, string mime_type, GnomeIconLookupFlags flags, IntPtr result);
384                 
385                 [DllImport("libgtk-x11-2.0.so")]
386                 static extern IntPtr gtk_icon_theme_get_default ();
387                 
388                 [DllImport("libgtk-x11-2.0.so")]
389                 static extern IntPtr gtk_icon_theme_load_icon (IntPtr icon_theme, string icon_name, int size, GtkIconLookupFlags flags, out IntPtr error);
390                 
391                 [DllImport("libgtk-x11-2.0.so")]
392                 static extern bool gtk_icon_theme_has_icon (IntPtr icon_theme, string icon_name);
393                 
394                 enum GnomeIconLookupFlags
395                 {
396                         GNOME_ICON_LOOKUP_FLAGS_NONE = 0,
397                         GNOME_ICON_LOOKUP_FLAGS_EMBEDDING_TEXT = 1<<0,
398                         GNOME_ICON_LOOKUP_FLAGS_SHOW_SMALL_IMAGES_AS_THEMSELVES = 1<<1,
399                         GNOME_ICON_LOOKUP_FLAGS_ALLOW_SVG_AS_THEMSELVES = 1<<2
400                 };
401                 
402                 enum GtkIconLookupFlags
403                 {
404                         GTK_ICON_LOOKUP_NO_SVG = 1 << 0,
405                         GTK_ICON_LOOKUP_FORCE_SVG = 1 << 1,
406                         GTK_ICON_LOOKUP_USE_BUILTIN = 1 << 2
407                 };
408                 
409                 static bool inited = false;
410                 
411                 static IntPtr default_icon_theme = IntPtr.Zero;
412                 
413                 static void Init ()
414                 {
415                         gdk_init_check (IntPtr.Zero, IntPtr.Zero);
416                         
417                         inited = true;
418                         
419                         default_icon_theme = gtk_icon_theme_get_default ();
420                 }
421                 
422                 public static Image GetIcon (string file_name, string mime_type, int size)
423                 {
424                         if (!inited)
425                                 Init ();
426                         
427                         Uri uri = new Uri (file_name);
428                         
429                         string icon = gnome_icon_lookup (default_icon_theme, IntPtr.Zero, uri.AbsoluteUri,
430                                                          null, IntPtr.Zero, mime_type,
431                                                          GnomeIconLookupFlags.GNOME_ICON_LOOKUP_FLAGS_NONE, IntPtr.Zero);
432                         
433                         IntPtr error = IntPtr.Zero;
434                         IntPtr pixbuf = gtk_icon_theme_load_icon (default_icon_theme, icon, size,
435                                                                   GtkIconLookupFlags.GTK_ICON_LOOKUP_USE_BUILTIN, out error);
436                         
437                         if (error != IntPtr.Zero)
438                                 return null;
439                         
440                         return GdkPixbufToImage (pixbuf);
441                 }
442                 
443                 public static Image GetIcon (string icon, int size)
444                 {
445                         if (!inited)
446                                 Init ();
447                         
448                         IntPtr error = IntPtr.Zero;
449                         IntPtr pixbuf = gtk_icon_theme_load_icon (default_icon_theme, icon, size,
450                                                                   GtkIconLookupFlags.GTK_ICON_LOOKUP_USE_BUILTIN, out error);
451                         
452                         if (error != IntPtr.Zero)
453                                 return null;
454                         
455                         return GdkPixbufToImage (pixbuf);
456                 }
457                 
458                 public static Image GdkPixbufToImage (IntPtr pixbuf)
459                 {
460                         IntPtr error = IntPtr.Zero;
461                         IntPtr buffer;
462                         UIntPtr buffer_size_as_ptr;
463                         string type = "png";
464                         
465                         bool saved = gdk_pixbuf_save_to_buffer (pixbuf, out buffer, out buffer_size_as_ptr, type, out error, IntPtr.Zero);
466                         
467                         if (!saved)
468                                 return null;
469                         
470                         int buffer_size = (int) (uint) buffer_size_as_ptr;
471                         byte[] result = new byte [buffer_size];
472                         Marshal.Copy (buffer, result, 0, (int) buffer_size);
473                         g_free (buffer);
474                         g_object_unref (pixbuf);
475                         
476                         Image image = null;
477                         using (MemoryStream s = new MemoryStream (result))
478                                 image = Image.FromStream (s);
479                         
480                         return image;
481                 }
482                 
483                 public static Image GetSVGasImage (string filename, int width, int height)
484                 {
485                         if (!inited)
486                                 Init ();
487                         
488                         if (!File.Exists (filename))
489                                 return null;
490                         IntPtr error = IntPtr.Zero;
491                         IntPtr pixbuf = rsvg_pixbuf_from_file_at_size (filename, width, height, out error);
492                         
493                         if (error != IntPtr.Zero)
494                                 return null;
495                         
496                         return GdkPixbufToImage (pixbuf);
497                 }
498                 
499                 public static bool HasImage (string name)
500                 {
501                         if (!inited)
502                                 Init ();
503                         
504                         return gtk_icon_theme_has_icon (default_icon_theme, name);
505                 }
506         }
507 }
508