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:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
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.
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
24 // Alexander Olk xenomorph2@onlinehome.de
27 // short "how to" if you want to add an other platform handler, etc:
28 // - first add mime type names and icon names (best is without extension) to MimeIconEngine, for example:
29 // MimeIconEngine.AddMimeTypeAndIconName( "inode/directory", "gnome-fs-directory" );
30 // - next add the icon name (the same as used in AddMimeTypeAndIconName) and the full filename, for example:
31 // MimeIconEngine.AddIcon( "gnome-fs-directory", "/opt/gnome/share/icons/gnome/48x48/filesystems/gnome-fs-directory.png" );
32 // AddIcon adds the icon to the image lists SmallIconList and LargeIconList
33 // - provide always a "unknown/unknown" 'mime type' with a default icon for unkown mime types,
34 // "desktop/desktop" 'mime type' for the desktop icon, "directory/home" 'mime type for the home dir of the user and so on
35 // (look at the default platform handler)
38 // public static int GetIconIndexForFile( string full_filename )
39 // public static int GetIconIndexForMimeType( string mime_type )
40 // to get the image index in MimeIconEngine.SmallIcons and MimeIconEngine.LargeIcons
42 // public static Image GetIconForMimeTypeAndSize( string mime_type, Size size )
43 // to get the image itself for a mime type with a specific size
47 using System.Collections;
48 using System.Collections.Specialized;
51 using System.Runtime.InteropServices;
53 namespace System.Windows.Forms
55 internal enum MimeExtensionHandlerStatus
64 internal enum EPlatformHandler
72 internal class MimeIconEngine
74 public static ImageList SmallIcons = new ImageList();
75 public static ImageList LargeIcons = new ImageList();
77 private static PlatformMimeIconHandler platformMimeHandler = null;
79 private static EPlatformHandler platform = EPlatformHandler.Default;
81 private static Hashtable MimeTypeIconIndexHash = new Hashtable();
83 private static NameValueCollection IconNameMimeTypeNameValueCollection = new NameValueCollection();
85 private static StringCollection added_icons = new StringCollection();
87 private static object lock_object = new Object();
89 static MimeIconEngine( )
91 // add some more aliases, kde for example uses other mime type names for some mime types...
92 MimeGenerated.Aliases.Add( "application/x-compressed-tar", "application/x-tgz" );
93 MimeGenerated.Aliases.Add( "application/x-bzip-compressed-tar", "application/x-tbz" );
94 MimeGenerated.Aliases.Add( "application/zip", "application/x-zip" );
95 MimeGenerated.Aliases.Add( "text/x-patch", "text/x-diff" );
97 SmallIcons.ColorDepth = ColorDepth.Depth32Bit;
98 SmallIcons.TransparentColor = Color.Transparent;
99 LargeIcons.ColorDepth = ColorDepth.Depth32Bit;
100 LargeIcons.TransparentColor = Color.Transparent;
102 string session = Environment.GetEnvironmentVariable( "DESKTOP_SESSION" );
104 if ( session != null )
106 session = session.ToUpper( );
108 if ( session == "DEFAULT" )
110 string helper = Environment.GetEnvironmentVariable( "KDE_FULL_SESSION" );
112 if ( helper != null )
116 helper = Environment.GetEnvironmentVariable( "GNOME_DESKTOP_SESSION_ID" );
118 if ( helper != null )
126 //Console.WriteLine( "Desktop session is: " + session );
128 if ( session == "KDE" )
130 SmallIcons.ImageSize = new Size( 24, 24 );
131 LargeIcons.ImageSize = new Size( 48, 48 );
133 platformMimeHandler = new KdeHandler( );
134 if ( platformMimeHandler.Start( ) == MimeExtensionHandlerStatus.OK )
136 Console.WriteLine( "Kde icons ready..." );
137 platform = EPlatformHandler.KDE;
139 else // fallback to default
141 MimeIconEngine.LargeIcons.Images.Clear( );
142 MimeIconEngine.SmallIcons.Images.Clear( );
143 platformMimeHandler = new PlatformDefaultHandler( );
144 platformMimeHandler.Start( );
148 if ( session == "GNOME" )
150 SmallIcons.ImageSize = new Size( 24, 24 );
151 LargeIcons.ImageSize = new Size( 48, 48 );
153 platformMimeHandler = new GnomeHandler( );
154 if ( platformMimeHandler.Start( ) == MimeExtensionHandlerStatus.OK )
156 Console.WriteLine( "Gnome icons ready..." );
157 platform = EPlatformHandler.GNOME;
159 else // fallback to default
161 MimeIconEngine.LargeIcons.Images.Clear( );
162 MimeIconEngine.SmallIcons.Images.Clear( );
163 platformMimeHandler = new PlatformDefaultHandler( );
164 platformMimeHandler.Start( );
169 SmallIcons.ImageSize = new Size( 16, 16 );
170 LargeIcons.ImageSize = new Size( 48, 48 );
172 platformMimeHandler = new PlatformDefaultHandler( );
173 platformMimeHandler.Start( );
176 IconNameMimeTypeNameValueCollection = null;
180 public static int GetIconIndexForFile( string full_filename )
184 string mime_type = Mime.GetMimeTypeForFile( full_filename );
186 if ( platform == EPlatformHandler.Default )
188 if ( mime_type == "inode/directory" )
190 return (int)MimeTypeIconIndexHash[ "inode/directory" ];
194 return (int)MimeTypeIconIndexHash[ "unknown/unknown" ];
198 object oindex = GetIconIndex( mime_type );
200 if ( oindex == null )
201 oindex = MimeTypeIconIndexHash[ "unknown/unknown" ];
207 public static int GetIconIndexForMimeType( string mime_type )
211 if ( platform == EPlatformHandler.Default )
213 if ( mime_type == "inode/directory" )
215 return (int)MimeTypeIconIndexHash[ "inode/directory" ];
219 return (int)MimeTypeIconIndexHash[ "unknown/unknown" ];
223 object oindex = GetIconIndex( mime_type );
225 if ( oindex == null )
226 oindex = MimeTypeIconIndexHash[ "unknown/unknown" ];
232 public static Image GetIconForMimeTypeAndSize( string mime_type, Size size )
236 object oindex = GetIconIndex( mime_type );
238 if ( oindex == null )
239 oindex = MimeTypeIconIndexHash[ "unknown/unknown" ];
241 Bitmap bmp = new Bitmap( LargeIcons.Images[ (int)oindex ], size );
247 internal static void AddIcon( string name, string fullname )
249 if ( !CheckIfIconIsNeeded( name ) )
252 if ( added_icons.Contains( name ) )
255 added_icons.Add( name );
257 Bitmap bmp = new Bitmap( fullname );
259 int index = SmallIcons.Images.Add( bmp, Color.Transparent );
260 LargeIcons.Images.Add( bmp, Color.Transparent );
262 AddMimeTypeIconIndexHash( name, index );
265 internal static void AddSVGIcon( string name, string fullname )
267 if ( !CheckIfIconIsNeeded( name ) )
270 if ( added_icons.Contains( name ) )
273 added_icons.Add( name );
275 Image image = SVGUtil.GetSVGasImage (fullname, 24, 24);
277 int index = SmallIcons.Images.Add( image, Color.Transparent );
278 image = SVGUtil.GetSVGasImage (fullname, 48, 48);
279 LargeIcons.Images.Add( image, Color.Transparent );
281 AddMimeTypeIconIndexHash( name, index );
284 private static bool CheckIfIconIsNeeded( string name )
286 string mime_types = IconNameMimeTypeNameValueCollection[ name ];
288 if ( mime_types != null )
294 internal static void AddMimeTypeIconIndexHash( string name, int index )
296 string mime_type = IconNameMimeTypeNameValueCollection[ name ];
298 if ( mime_type == null )
301 string[] split = mime_type.Split( new char[] { ',' } );
303 foreach ( string s in split )
305 if ( MimeTypeIconIndexHash.ContainsKey( s ) )
308 MimeTypeIconIndexHash.Add( s, index );
312 internal static void AddIconByImage( string name, Image image )
314 int index = SmallIcons.Images.Add( image, Color.Transparent );
315 LargeIcons.Images.Add( image, Color.Transparent );
317 AddMimeTypeIconIndexHash( name, index );
320 internal static void AddMimeTypeAndIconName( string mimetype, string iconname )
322 if ( iconname.Equals( String.Empty ) )
325 IconNameMimeTypeNameValueCollection.Add( iconname, mimetype );
328 private static object GetIconIndex( string mime_type )
330 object oindex = null;
332 if ( mime_type != null )
334 // first check if mime_type is available in the mimetype/icon hashtable
335 oindex = MimeTypeIconIndexHash[ mime_type ];
337 if ( oindex == null )
339 // it is not available, check if an alias exist for mime_type
340 string alias = Mime.GetMimeAlias( mime_type );
344 string[] split = alias.Split( new char[] { ',' } );
346 foreach ( string s in split )
348 oindex = MimeTypeIconIndexHash[ s ];
350 if ( oindex != null )
355 // if oindex is still null check if mime_type is a sub class of an other mime type
356 string sub_class = MimeGenerated.SubClasses[ mime_type ];
358 if ( sub_class != null )
359 return MimeTypeIconIndexHash[ sub_class ];
361 // last check, see if we find an entry for the main mime type class
362 string mime_class_main = mime_type.Substring( 0, mime_type.IndexOf( '/' ) );
363 return MimeTypeIconIndexHash[ mime_class_main ];
371 internal abstract class PlatformMimeIconHandler
373 protected StringCollection mime_paths = new StringCollection();
375 protected StringCollection icon_paths = new StringCollection();
377 protected string icon_theme = "";
379 protected MimeExtensionHandlerStatus mimeExtensionHandlerStatus = MimeExtensionHandlerStatus.OK;
381 public MimeExtensionHandlerStatus MimeExtensionHandlerStatus
384 return mimeExtensionHandlerStatus;
388 public abstract MimeExtensionHandlerStatus Start( );
390 // check, if icon, mime, etc., directories exist
391 protected virtual bool CheckPlatformDirectories( )
397 internal class PlatformDefaultHandler : PlatformMimeIconHandler
399 public override MimeExtensionHandlerStatus Start( )
401 MimeIconEngine.AddMimeTypeAndIconName( "unknown/unknown", "paper" );
402 MimeIconEngine.AddMimeTypeAndIconName( "inode/directory", "folder" );
403 MimeIconEngine.AddMimeTypeAndIconName( "desktop/desktop", "desktop" );
404 MimeIconEngine.AddMimeTypeAndIconName( "directory/home", "folder_with_paper" );
405 MimeIconEngine.AddMimeTypeAndIconName( "network/network", "monitor-planet" );
406 MimeIconEngine.AddMimeTypeAndIconName( "recently/recently", "last_open" );
407 MimeIconEngine.AddMimeTypeAndIconName( "workplace/workplace", "monitor-computer" );
409 MimeIconEngine.AddIconByImage( "folder", (Image)Locale.GetResource( "folder" ) );
410 MimeIconEngine.AddIconByImage( "paper", (Image)Locale.GetResource( "paper" ) );
411 MimeIconEngine.AddIconByImage( "desktop", (Image)Locale.GetResource( "desktop" ) );
412 MimeIconEngine.AddIconByImage( "folder_with_paper", (Image)Locale.GetResource( "folder_with_paper" ) );
413 MimeIconEngine.AddIconByImage( "monitor-planet", (Image)Locale.GetResource( "monitor-planet" ) );
414 MimeIconEngine.AddIconByImage( "last_open", (Image)Locale.GetResource( "last_open" ) );
415 MimeIconEngine.AddIconByImage( "monitor-computer", (Image)Locale.GetResource( "monitor-computer" ) );
417 return MimeExtensionHandlerStatus.OK; // return always ok
421 internal class KdeHandler : PlatformMimeIconHandler
423 string full_kdegloabals_filename = Environment.GetFolderPath( Environment.SpecialFolder.Personal )
425 + ".kde/share/config/kdeglobals";
427 public override MimeExtensionHandlerStatus Start( )
429 if ( !ReadKdeglobals( ) )
430 return mimeExtensionHandlerStatus;
432 if ( !CheckPlatformDirectories( ) )
433 return mimeExtensionHandlerStatus;
435 // check if the theme is svg only
436 // if true, use theme "default.kde"
437 // don't know if that is available in every linux distribution
438 // MWF has no svg support yet (cairo's libsvg!?!)
440 icon_theme = "default.kde";
442 // check if there is a /48x48 directory
444 icon_theme = "default.kde";
450 return mimeExtensionHandlerStatus;
453 private bool SVGOnly( )
455 // check only the first path in icon_paths
456 if ( icon_paths.Count > 0 )
458 string icon_path = icon_paths[ 0 ] + icon_theme;
459 string[] dirs = Directory.GetDirectories( icon_path );
461 if ( dirs.Length == 1 && dirs[ 0 ] == "scalable" )
468 private bool No48x48( )
470 // check only the first path in icon_paths
471 if ( icon_paths.Count > 0 )
473 string icon_path = icon_paths[ 0 ] + icon_theme;
474 string[] dirs = Directory.GetDirectories( icon_path );
476 foreach( string path in dirs )
478 if ( path.EndsWith( "48x48" ) )
486 protected override bool CheckPlatformDirectories( )
488 bool icons_found = false;
491 if ( Directory.Exists( "/opt/kde3/share/icons/default.kde" ) )
493 icon_paths.Add( "/opt/kde3/share/icons" + "/" );
497 if ( Directory.Exists( "/usr/share/icons/default.kde" ) )
499 icon_paths.Add( "/usr/share/icons" + "/" );
503 if ( Directory.Exists( "/usr/local/share/icons/default.kde" ) )
505 icon_paths.Add( "/usr/local/share/icons" + "/" );
511 mimeExtensionHandlerStatus = MimeExtensionHandlerStatus.NO_ICONS;
515 bool mimelnk_found = false;
517 if ( Directory.Exists( "/usr/share/mimelnk" ) )
519 mime_paths.Add( "/usr/share/mimelnk" + "/" );
520 mimelnk_found = true;
523 if ( Directory.Exists( "/usr/local/share/mimelnk" ) )
525 mime_paths.Add( "/usr/local/share/mimelnk" + "/" );
526 mimelnk_found = true;
529 if ( Directory.Exists( "/opt/kde3/share/mimelnk" ) )
531 mime_paths.Add( "/opt/kde3/share/mimelnk" + "/" );
532 mimelnk_found = true;
535 if ( !mimelnk_found )
537 mimeExtensionHandlerStatus = MimeExtensionHandlerStatus.NO_MIMELNK;
544 private void ReadIcons( )
546 foreach ( string icon_path_in in icon_paths )
548 string icon_path = icon_path_in + icon_theme + "/48x48";
550 string[] directories = Directory.GetDirectories( icon_path );
552 foreach ( string d in directories )
554 DirectoryInfo di = new DirectoryInfo( d );
556 FileInfo[] fileinfo = di.GetFiles( );
558 foreach ( FileInfo fi in fileinfo )
560 string name = Path.GetFileNameWithoutExtension( fi.Name );
562 MimeIconEngine.AddIcon( name, fi.FullName );
568 private void ReadMimetypes( )
570 MimeIconEngine.AddMimeTypeAndIconName( "unknown/unknown", "unknown" );
571 MimeIconEngine.AddMimeTypeAndIconName( "desktop/desktop", "desktop" );
572 MimeIconEngine.AddMimeTypeAndIconName( "directory/home", "folder_home" );
573 MimeIconEngine.AddMimeTypeAndIconName( "network/network", "network" );
574 MimeIconEngine.AddMimeTypeAndIconName( "recently/recently", "folder_man" );
575 MimeIconEngine.AddMimeTypeAndIconName( "workplace/workplace", "system" );
577 foreach ( string mime_path in mime_paths )
579 string[] directories = Directory.GetDirectories( mime_path );
581 foreach ( string d in directories )
583 string[] files = Directory.GetFiles( d );
585 foreach ( string f in files )
590 // Ignore errors if the file can not be read.
597 private void ReadDotDesktop( string filename )
599 StreamReader sr = new StreamReader( filename );
601 string line = sr.ReadLine( );
603 string icon_name = "";
605 string mime_type = "";
607 bool have_icon = false;
608 bool have_mimetype = false;
610 while ( line != null )
614 if ( line.StartsWith( "Icon" ) )
616 icon_name = line.Substring( line.IndexOf( '=' ) + 1 );
617 icon_name = icon_name.Trim( );
623 if ( line.StartsWith( "MimeType" ) )
625 mime_type = line.Substring( line.IndexOf( '=' ) + 1 );
626 mime_type = mime_type.Trim( );
629 have_mimetype = true;
632 line = sr.ReadLine( );
637 MimeIconEngine.AddMimeTypeAndIconName( mime_type, icon_name );
640 private bool ReadKdeglobals( )
642 if ( !File.Exists( full_kdegloabals_filename ) )
644 mimeExtensionHandlerStatus = MimeExtensionHandlerStatus.NO_KDEGLOBALS;
649 StreamReader sr = new StreamReader( full_kdegloabals_filename );
651 string line = sr.ReadLine( );
653 while ( line != null )
655 if ( line.IndexOf( "[Icons]" ) != -1 )
657 line = sr.ReadLine( );
659 if ( line != null && line.IndexOf( "Theme" ) != -1 )
663 icon_theme = line.Substring( line.IndexOf( '=' ) + 1 );
665 icon_theme = icon_theme.Trim( );
671 line = sr.ReadLine( );
680 // GnomeHandler uses the default gnome icon theme (many others are svg only)
681 internal class GnomeHandler : PlatformMimeIconHandler
683 public override MimeExtensionHandlerStatus Start( )
685 if ( !CheckPlatformDirectories( ) )
686 return mimeExtensionHandlerStatus;
688 CreateMimeTypeFromIconName( );
692 return MimeExtensionHandlerStatus.OK;
695 protected override bool CheckPlatformDirectories( )
697 // add more directories ???
698 if ( Directory.Exists( "/opt/gnome/share/icons/gnome/48x48" ) )
700 icon_paths.Add( "/opt/gnome/share/icons/gnome/48x48/" );
703 if ( Directory.Exists( "/usr/share/icons/gnome/48x48" ) )
705 icon_paths.Add( "/usr/share/icons/gnome/48x48/" );
708 if ( Directory.Exists( "/usr/local/share/icons/gnome/48x48" ) )
710 icon_paths.Add( "/usr/local/share/icons/gnome/48x48/" );
714 mimeExtensionHandlerStatus = MimeExtensionHandlerStatus.NO_ICONS;
721 private void CreateMimeTypeFromIconName( )
723 MimeIconEngine.AddMimeTypeAndIconName( "inode/directory", "gnome-fs-directory" );
724 MimeIconEngine.AddMimeTypeAndIconName( "unknown/unknown", "gnome-fs-regular" );
725 MimeIconEngine.AddMimeTypeAndIconName( "desktop/desktop", "gnome-fs-desktop" );
726 MimeIconEngine.AddMimeTypeAndIconName( "directory/home", "gnome-fs-home" );
727 MimeIconEngine.AddMimeTypeAndIconName( "network/network", "gnome-fs-network" );
728 MimeIconEngine.AddMimeTypeAndIconName( "recently/recently", "gnome-fs-directory-accept" );
729 MimeIconEngine.AddMimeTypeAndIconName( "workplace/workplace", "gnome-fs-client" );
731 foreach ( string ip in icon_paths )
733 string[] files = Directory.GetFiles( ip + "mimetypes" );
735 foreach ( string file in files )
737 string extension = Path.GetExtension( file );
739 if ( extension != ".png" )
742 string file_name = Path.GetFileNameWithoutExtension( file );
744 if ( !file_name.StartsWith( "gnome-mime-" ) )
747 StringBuilder mime_type = new StringBuilder( file_name.Replace( "gnome-mime-", "" ) );
749 for ( int i = 0; i < mime_type.Length; i++ )
750 if ( mime_type[ i ] == '-' )
752 mime_type[ i ] = '/';
756 MimeIconEngine.AddMimeTypeAndIconName( mime_type.ToString( ), file_name );
761 private void ReadIcons( )
763 foreach ( string icon_path in icon_paths )
765 string[] directories = Directory.GetDirectories( icon_path );
767 foreach ( string directory in directories )
769 DirectoryInfo di = new DirectoryInfo( directory );
771 FileInfo[] fileinfo = di.GetFiles( );
773 foreach ( FileInfo fi in fileinfo )
775 if ( fi.Extension != ".png" )
778 string name = Path.GetFileNameWithoutExtension( fi.Name );
780 MimeIconEngine.AddIcon( name, fi.FullName );
787 internal class SVGUtil {
788 [DllImport("librsvg-2.so")]
789 static extern IntPtr rsvg_pixbuf_from_file_at_size (string file_name, int width, int height, out IntPtr error);
791 [DllImport("libgdk-x11-2.0.so")]
792 static extern bool gdk_pixbuf_save_to_buffer (IntPtr pixbuf, out IntPtr buffer, out uint buffer_size, string type, out IntPtr error, IntPtr option_dummy);
794 [DllImport("libglib-2.0.so")]
795 static extern void g_free (IntPtr mem);
797 [DllImport("libgdk-x11-2.0.so")]
798 static extern bool gdk_init_check(out int argc, string argv);
800 [DllImport("libgobject-2.0.so")]
801 static extern void g_object_unref (IntPtr nativeObject);
803 static bool inited = false;
805 static void Init () {
809 gdk_init_check (out argc, argv);
814 public static Image GetSVGasImage (string filename, int width, int height) {
818 if (!File.Exists (filename))
820 IntPtr error = IntPtr.Zero;
821 IntPtr pixbuf = rsvg_pixbuf_from_file_at_size (filename, width, height, out error);
823 if (error != IntPtr.Zero)
831 bool saved = gdk_pixbuf_save_to_buffer (pixbuf, out buffer, out buffer_size, type, out error, IntPtr.Zero);
836 byte[] result = new byte [buffer_size];
837 Marshal.Copy (buffer, result, 0, (int) buffer_size);
839 g_object_unref (pixbuf);
842 using (MemoryStream s = new MemoryStream (result))
843 image = Image.FromStream (s);