Find more libraries via dllmap (#4451)
[mono.git] / mcs / class / System.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) 2006 Alexander Olk
21 //
22 // Authors:
23 //
24 //  Alexander Olk       alex.olk@googlemail.com
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.IO;
37 using System.Text;
38 using System.Runtime.InteropServices;
39 using System.Xml;
40
41 namespace System.Windows.Forms
42 {
43         internal enum MimeExtensionHandlerStatus
44         {
45                 OK,
46                 ERROR
47         }
48         
49         internal enum EPlatformHandler
50         {
51                 Default,
52                 GNOME
53         }
54         
55         internal class ResourceImageLoader
56         {
57                 static Assembly assembly = typeof (ResourceImageLoader).Assembly;
58                 
59                 static internal Bitmap Get (string name)
60                 {
61                         Stream stream = assembly.GetManifestResourceStream (name);
62
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                 static internal Icon GetIcon (string name)
72                 {
73                         Stream stream = assembly.GetManifestResourceStream (name);
74
75                         if (stream == null) {
76                                 Console.WriteLine ("Failed to read {0}", name);
77                                 return null;
78                         }
79
80                         return new Icon (stream);
81                 }
82         }
83         
84         internal class MimeIconEngine
85         {
86                 public static ImageList SmallIcons = new ImageList();
87                 public static ImageList LargeIcons = new ImageList();
88                 
89                 private static EPlatformHandler platform = EPlatformHandler.Default;
90                 
91                 internal static Hashtable MimeIconIndex = new Hashtable ();
92                 
93                 private static PlatformMimeIconHandler platformMimeHandler = null;
94                 
95                 private static object lock_object = new Object();
96                 
97                 static MimeIconEngine ()
98                 {
99                         SmallIcons.ColorDepth = ColorDepth.Depth32Bit;
100                         SmallIcons.TransparentColor = Color.Transparent;
101                         LargeIcons.ColorDepth = ColorDepth.Depth32Bit;
102                         LargeIcons.TransparentColor = Color.Transparent;
103                         
104                         string session =  Environment.GetEnvironmentVariable ("DESKTOP_SESSION");
105                         
106                         if (session != null) {
107                                 session = session.ToUpper ();
108                                 
109                                 if (session == "DEFAULT") {
110                                         string helper = Environment.GetEnvironmentVariable ("GNOME_DESKTOP_SESSION_ID");
111                                         
112                                         if (helper != null)
113                                                 session = "GNOME";
114                                 }
115                         } else
116                                 session = String.Empty;
117                         
118                         if (Mime.MimeAvailable && session == "GNOME") {
119                                 SmallIcons.ImageSize = new Size (24, 24);
120                                 LargeIcons.ImageSize = new Size (48, 48);
121                                 
122                                 platformMimeHandler = new GnomeHandler ();
123                                 if (platformMimeHandler.Start () == MimeExtensionHandlerStatus.OK) {
124                                         platform = EPlatformHandler.GNOME;
125                                 } else {
126                                         MimeIconEngine.LargeIcons.Images.Clear ();
127                                         MimeIconEngine.SmallIcons.Images.Clear ();
128                                         platformMimeHandler = new PlatformDefaultHandler ();
129                                         platformMimeHandler.Start ();
130                                 }
131                         } else {
132                                 SmallIcons.ImageSize = new Size (16, 16);
133                                 LargeIcons.ImageSize = new Size (48, 48);
134                                 
135                                 platformMimeHandler = new PlatformDefaultHandler ();
136                                 platformMimeHandler.Start ();
137                         }
138                 }
139                 
140                 public static int GetIconIndexForFile (string full_filename)
141                 {
142                         lock (lock_object) {
143                                 if (platform == EPlatformHandler.Default) {
144                                         return (int)MimeIconIndex ["unknown/unknown"];
145                                 }
146                                 
147                                 string mime_type = Mime.GetMimeTypeForFile (full_filename);
148                                 
149                                 object oindex = GetIconIndex (mime_type);
150                                 
151                                 // not found, add it
152                                 if (oindex == null) {
153                                         int index = full_filename.IndexOf (':');
154                                         
155                                         if (index > 1) {
156                                                 oindex = MimeIconIndex ["unknown/unknown"];
157                                                 
158                                         } else {
159                                                 oindex = platformMimeHandler.AddAndGetIconIndex (full_filename, mime_type);
160                                                 
161                                                 // sanity check
162                                                 if (oindex == null)
163                                                         oindex = MimeIconIndex ["unknown/unknown"];
164                                         }
165                                 }
166                                 
167                                 return (int)oindex;
168                         }
169                 }
170                 
171                 public static int GetIconIndexForMimeType (string mime_type)
172                 {
173                         lock (lock_object) {
174                                 if (platform == EPlatformHandler.Default) {
175                                         if (mime_type == "inode/directory") {
176                                                 return (int)MimeIconIndex ["inode/directory"];
177                                         } else {
178                                                 return (int)MimeIconIndex ["unknown/unknown"];
179                                         }
180                                 }
181                                 
182                                 object oindex = GetIconIndex (mime_type);
183                                 
184                                 // not found, add it
185                                 if (oindex == null) {
186                                         oindex = platformMimeHandler.AddAndGetIconIndex (mime_type);
187                                         
188                                         // sanity check
189                                         if (oindex == null)
190                                                 oindex = MimeIconIndex ["unknown/unknown"];
191                                 }
192                                 
193                                 return (int)oindex;
194                         }
195                 }
196                 
197                 public static Image GetIconForMimeTypeAndSize (string mime_type, Size size)
198                 {
199                         lock (lock_object) {
200                                 object oindex = GetIconIndex (mime_type);
201                                 
202                                 Bitmap bmp = new Bitmap (LargeIcons.Images [(int)oindex], size);
203                                 
204                                 return bmp;
205                         }
206                 }
207                 
208                 internal static void AddIconByImage (string mime_type, Image image)
209                 {
210                         int index = SmallIcons.Images.Add (image, Color.Transparent);
211                         LargeIcons.Images.Add (image, Color.Transparent);
212                         
213                         MimeIconIndex.Add (mime_type, index);
214                 }
215                 
216                 private static object GetIconIndex (string mime_type)
217                 {
218                         object oindex = null;
219                         
220                         if (mime_type != null) {
221                                 // first check if mime_type is available in the mimetype/icon hashtable
222                                 oindex = MimeIconIndex [mime_type];
223                                 
224                                 if (oindex == null) {
225                                         // it is not available, check if an alias exist for mime_type
226                                         string alias = Mime.GetMimeAlias (mime_type);
227                                         
228                                         if (alias != null) {
229                                                 string[] split = alias.Split (new char [] { ',' });
230                                                 
231                                                 for (int i = 0; i < split.Length; i++) {
232                                                         oindex = MimeIconIndex [split [i]];
233                                                         
234                                                         if (oindex != null)
235                                                                 return oindex;
236                                                 }
237                                         }
238                                         
239                                         // if oindex is still null check if mime_type is a sub class of an other mime type
240                                         string sub_class = Mime.SubClasses [mime_type];
241                                         
242                                         if (sub_class != null) {
243                                                 oindex = MimeIconIndex [sub_class];
244                                                 
245                                                 if (oindex != null)
246                                                         return oindex;
247                                         }
248                                         
249                                         // last check, see if we find an entry for the main mime type class
250                                         string mime_class_main = mime_type.Substring (0, mime_type.IndexOf ('/'));
251                                         return MimeIconIndex [mime_class_main];
252                                 }
253                         }
254                         
255                         return oindex;
256                 }
257         }
258         
259         internal abstract class PlatformMimeIconHandler
260         {
261                 protected MimeExtensionHandlerStatus mimeExtensionHandlerStatus = MimeExtensionHandlerStatus.OK;
262                 
263                 public MimeExtensionHandlerStatus MimeExtensionHandlerStatus {
264                         get {
265                                 return mimeExtensionHandlerStatus;
266                         }
267                 }
268                 
269                 public abstract MimeExtensionHandlerStatus Start ();
270                 
271                 public virtual object AddAndGetIconIndex (string filename, string mime_type)
272                 {
273                         return null;
274                 }
275                 
276                 public virtual object AddAndGetIconIndex (string mime_type)
277                 {
278                         return null;
279                 }
280         }
281         
282         internal class PlatformDefaultHandler : PlatformMimeIconHandler
283         {
284                 public override MimeExtensionHandlerStatus Start ()
285                 {
286                         MimeIconEngine.AddIconByImage ("inode/directory",  ResourceImageLoader.Get ("folder.png"));
287                         MimeIconEngine.AddIconByImage ("unknown/unknown",  ResourceImageLoader.Get ("text-x-generic.png"));
288                         MimeIconEngine.AddIconByImage ("desktop/desktop",  ResourceImageLoader.Get ("user-desktop.png"));
289                         MimeIconEngine.AddIconByImage ("directory/home",  ResourceImageLoader.Get ("user-home.png"));
290                         
291                         MimeIconEngine.AddIconByImage ("network/network",  ResourceImageLoader.Get ("folder-remote.png"));
292                         MimeIconEngine.AddIconByImage ("recently/recently",  ResourceImageLoader.Get ("document-open.png"));
293                         MimeIconEngine.AddIconByImage ("workplace/workplace",  ResourceImageLoader.Get ("computer.png"));
294                         
295                         return MimeExtensionHandlerStatus.OK; // return always ok
296                 }
297         }
298         
299         internal class GnomeHandler : PlatformMimeIconHandler
300         {
301                 public override MimeExtensionHandlerStatus Start ()
302                 {
303                         CreateUIIcons ();
304                         
305                         return MimeExtensionHandlerStatus.OK;
306                 }
307                 
308                 private void CreateUIIcons ()
309                 {
310                         AddGnomeIcon ("unknown/unknown", "gnome-fs-regular");
311                         AddGnomeIcon ("inode/directory", "gnome-fs-directory");
312                         AddGnomeIcon ("directory/home", "gnome-fs-home");
313                         AddGnomeIcon ("desktop/desktop", "gnome-fs-desktop");
314                         AddGnomeIcon ("recently/recently", "gnome-fs-directory-accept");
315                         AddGnomeIcon ("workplace/workplace", "gnome-fs-client");
316                         
317                         AddGnomeIcon ("network/network", "gnome-fs-network");
318                         AddGnomeIcon ("nfs/nfs", "gnome-fs-nfs");
319                         AddGnomeIcon ("smb/smb", "gnome-fs-smb");
320                         
321                         AddGnomeIcon ("harddisk/harddisk", "gnome-dev-harddisk");
322                         AddGnomeIcon ("cdrom/cdrom", "gnome-dev-cdrom");
323                         AddGnomeIcon ("removable/removable", "gnome-dev-removable");
324                 }
325                 
326                 private void AddGnomeIcon (string internal_mime_type, string name)
327                 {
328                         int index = -1;
329                         
330                         if (MimeIconEngine.MimeIconIndex.ContainsKey (internal_mime_type)) {
331                                 return;
332                         }
333                         
334                         Image image = GnomeUtil.GetIcon (name, 48);
335                         
336                         if (image == null) {
337                                 if (internal_mime_type == "unknown/unknown")
338                                         image = ResourceImageLoader.Get ("text-x-generic.png");
339                                 else
340                                 if (internal_mime_type == "inode/directory")
341                                         image = ResourceImageLoader.Get ("folder.png");
342                                 else
343                                 if (internal_mime_type == "directory/home")
344                                         image = ResourceImageLoader.Get ("user-home.png");
345                                 else
346                                 if (internal_mime_type == "desktop/desktop")
347                                         image = ResourceImageLoader.Get ("user-desktop.png");
348                                 else
349                                 if (internal_mime_type == "recently/recently")
350                                         image = ResourceImageLoader.Get ("document-open.png");
351                                 else
352                                 if (internal_mime_type == "workplace/workplace")
353                                         image = ResourceImageLoader.Get ("computer.png");
354                                 else
355                                 if (internal_mime_type == "network/network" || internal_mime_type == "nfs/nfs" || internal_mime_type == "smb/smb")
356                                         image = ResourceImageLoader.Get ("folder-remote.png");
357                                 else
358                                 if (internal_mime_type == "harddisk/harddisk" || internal_mime_type == "cdrom/cdrom" || internal_mime_type == "removable/removable")
359                                         image = ResourceImageLoader.Get ("text-x-generic.png");
360                         }
361
362                         if (image != null) {
363                                 index = MimeIconEngine.SmallIcons.Images.Add (image, Color.Transparent);
364                                 MimeIconEngine.LargeIcons.Images.Add (image, Color.Transparent);
365                                 MimeIconEngine.MimeIconIndex.Add (internal_mime_type, index);
366                         }
367                 }
368                 
369                 public override object AddAndGetIconIndex (string filename, string mime_type)
370                 {
371                         int index = -1;
372                         
373                         Image image = GnomeUtil.GetIcon (filename, mime_type, 48);
374                         if (image != null) {
375                                 index = MimeIconEngine.SmallIcons.Images.Add (image, Color.Transparent);
376                                 MimeIconEngine.LargeIcons.Images.Add (image, Color.Transparent);
377                                 MimeIconEngine.MimeIconIndex.Add (mime_type, index);
378                         }
379                         
380                         return index;
381                 }
382                 
383                 public override object AddAndGetIconIndex (string mime_type)
384                 {
385                         int index = -1;
386                         
387                         Image image = GnomeUtil.GetIcon (mime_type, 48);
388                         if (image != null) {
389                                 index = MimeIconEngine.SmallIcons.Images.Add (image, Color.Transparent);
390                                 MimeIconEngine.LargeIcons.Images.Add (image, Color.Transparent);
391                                 MimeIconEngine.MimeIconIndex.Add (mime_type, index);
392                         }
393                         
394                         return index;
395                 }
396         }
397         
398         internal class GnomeUtil
399         {
400                 const string libgdk = "libgdk-x11-2.0";
401                 const string libgdk_pixbuf = "libgdk_pixbuf-2.0";
402                 const string libgtk = "libgtk-x11-2.0";
403                 const string libglib = "libglib-2.0";
404                 const string libgobject = "libgobject-2.0";
405                 const string libgnomeui = "libgnomeui-2";
406                 const string librsvg = "librsvg-2";
407                 
408                 [DllImport(librsvg)]
409                 static extern IntPtr rsvg_pixbuf_from_file_at_size (string file_name, int  width, int  height, out IntPtr error);
410                 
411                 [DllImport(libgdk_pixbuf)]
412                 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);
413                 
414                 [DllImport(libglib)]
415                 static extern void g_free (IntPtr mem);
416                 
417                 [DllImport(libgdk)]
418                 static extern bool gdk_init_check (IntPtr argc, IntPtr argv);
419                 
420                 [DllImport(libgobject)]
421                 static extern void g_object_unref (IntPtr nativeObject);
422                 
423                 [DllImport(libgnomeui)]
424                 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);
425                 
426                 [DllImport(libgtk)]
427                 static extern IntPtr gtk_icon_theme_get_default ();
428                 
429                 [DllImport(libgtk)]
430                 static extern IntPtr gtk_icon_theme_load_icon (IntPtr icon_theme, string icon_name, int size, GtkIconLookupFlags flags, out IntPtr error);
431                 
432                 [DllImport(libgtk)]
433                 static extern bool gtk_icon_theme_has_icon (IntPtr icon_theme, string icon_name);
434                 
435                 enum GnomeIconLookupFlags
436                 {
437                         GNOME_ICON_LOOKUP_FLAGS_NONE = 0,
438                         GNOME_ICON_LOOKUP_FLAGS_EMBEDDING_TEXT = 1<<0,
439                         GNOME_ICON_LOOKUP_FLAGS_SHOW_SMALL_IMAGES_AS_THEMSELVES = 1<<1,
440                         GNOME_ICON_LOOKUP_FLAGS_ALLOW_SVG_AS_THEMSELVES = 1<<2
441                 };
442                 
443                 enum GtkIconLookupFlags
444                 {
445                         GTK_ICON_LOOKUP_NO_SVG = 1 << 0,
446                         GTK_ICON_LOOKUP_FORCE_SVG = 1 << 1,
447                         GTK_ICON_LOOKUP_USE_BUILTIN = 1 << 2
448                 };
449                 
450                 static bool inited = false;
451                 
452                 static IntPtr default_icon_theme = IntPtr.Zero;
453                 
454                 static void Init ()
455                 {
456                         gdk_init_check (IntPtr.Zero, IntPtr.Zero);
457                         
458                         inited = true;
459                         
460                         default_icon_theme = gtk_icon_theme_get_default ();
461                 }
462                 
463                 public static Image GetIcon (string file_name, string mime_type, int size)
464                 {
465                         if (!inited)
466                                 Init ();
467                         
468                         Uri uri = new Uri (file_name);
469         
470                         string icon;
471
472                         try {
473                                 icon = gnome_icon_lookup (default_icon_theme, IntPtr.Zero, uri.AbsoluteUri,
474                                                           null, IntPtr.Zero, mime_type,
475                                                           GnomeIconLookupFlags.GNOME_ICON_LOOKUP_FLAGS_NONE, IntPtr.Zero);
476                         } catch {
477                                 // If libgnomeui is not installed, in preparation for Gnome 3
478                                 return null;
479                         }
480                         
481                         IntPtr error = IntPtr.Zero;
482                         IntPtr pixbuf = gtk_icon_theme_load_icon (default_icon_theme, icon, size,
483                                                                   GtkIconLookupFlags.GTK_ICON_LOOKUP_USE_BUILTIN, out error);
484                         
485                         if (error != IntPtr.Zero)
486                                 return null;
487                         
488                         return GdkPixbufToImage (pixbuf);
489                 }
490                 
491                 public static Image GetIcon (string icon, int size)
492                 {
493                         if (!inited)
494                                 Init ();
495                         
496                         IntPtr error = IntPtr.Zero;
497                         IntPtr pixbuf = gtk_icon_theme_load_icon (default_icon_theme, icon, size,
498                                                                   GtkIconLookupFlags.GTK_ICON_LOOKUP_USE_BUILTIN, out error);
499                         
500                         if (error != IntPtr.Zero)
501                                 return null;
502                         
503                         return GdkPixbufToImage (pixbuf);
504                 }
505                 
506                 public static Image GdkPixbufToImage (IntPtr pixbuf)
507                 {
508                         IntPtr error = IntPtr.Zero;
509                         IntPtr buffer;
510                         UIntPtr buffer_size_as_ptr;
511                         string type = "png";
512                         
513                         bool saved = gdk_pixbuf_save_to_buffer (pixbuf, out buffer, out buffer_size_as_ptr, type, out error, IntPtr.Zero);
514                         
515                         if (!saved)
516                                 return null;
517                         
518                         int buffer_size = (int) (uint) buffer_size_as_ptr;
519                         byte[] result = new byte [buffer_size];
520                         Marshal.Copy (buffer, result, 0, (int) buffer_size);
521                         g_free (buffer);
522                         g_object_unref (pixbuf);
523                         
524                         Image image = null;
525                         MemoryStream s = new MemoryStream (result);
526                         image = Image.FromStream (s);
527                         
528                         return image;
529                 }
530                 
531                 public static Image GetSVGasImage (string filename, int width, int height)
532                 {
533                         if (!inited)
534                                 Init ();
535                         
536                         if (!File.Exists (filename))
537                                 return null;
538                         IntPtr error = IntPtr.Zero;
539                         IntPtr pixbuf = rsvg_pixbuf_from_file_at_size (filename, width, height, out error);
540                         
541                         if (error != IntPtr.Zero)
542                                 return null;
543                         
544                         return GdkPixbufToImage (pixbuf);
545                 }
546                 
547                 public static bool HasImage (string name)
548                 {
549                         if (!inited)
550                                 Init ();
551                         
552                         return gtk_icon_theme_has_icon (default_icon_theme, name);
553                 }
554         }
555 }
556