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