2
0
Эх сурвалжийг харах

UPD: Use SHGetFileInfoW function instead of Ansi version.

cobines 15 жил өмнө
parent
commit
47f2d482f5
1 өөрчлөгдсөн 1469 нэмэгдсэн , 1468 устгасан
  1. 1469 1468
      src/platform/upixmapmanager.pas

+ 1469 - 1468
src/platform/upixmapmanager.pas

@@ -1,1468 +1,1469 @@
-{
-   File name: uPixMapManager.pas
-   Date:      2004/04/xx
-   Author:    Radek Cervinka  <[email protected]>
-
-   Fast pixmap memory manager a loader
-
-   Copyright (C) 2004
-   
-   contributors:
-   
-   Copyright (C) 2006-2009  Koblov Alexander ([email protected])
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   in a file called COPYING along with this program; if not, write to
-   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
-   02139, USA.
-}
-
-
-unit uPixMapManager;
-
-{$mode objfpc}{$H+}
-
-interface
-
-{
-  GTK2 is used directly in PixmapManager, because FPC/Lazarus draws bitmaps
-  without alpha channel under GTK2, so bitmaps looks ugly.
-  If this problem will be fixed then GTK2 specific code could be dropped.
-}
-
-uses
-  Classes, SysUtils, Graphics, syncobjs,
-  uOSUtils, uFileSorting, StringHashList, uFile
-  {$IF DEFINED(UNIX)}
-  , uClassesEx
-    {$IF NOT DEFINED(DARWIN)}
-    , contnrs
-      {$IFDEF LCLGTK2}
-      , gtk2
-      {$ELSE}
-      , uIconTheme, uMyIconTheme
-      {$ENDIF}
-    {$ENDIF}
-  {$ENDIF};
-
-type
-  TDriveIconList = class
-    bmMediaFloppy,
-    bmDriveHardDisk,
-    bmMediaFlash,
-    bmMediaOptical,
-    bmDriveNetwork: TBitmap;
-  end;
-
-  { TPixMapManager }
-
-  TPixMapManager = class
-  
-  private
-    {en
-       Maps file extension to index of bitmap (in FPixmapList) for this file extension.
-    }
-    FExtList : TStringHashList;
-    {en
-       Maps icon filename to index of bitmap (in FPixmapList) for this icon.
-       Uses absolute file names.
-    }
-    FPixmapsFileNames : TStringHashList;
-    {en
-       A list of loaded bitmaps.
-       Stores TBitmap objects (on GTK2 it stores PGdkPixbuf pointers).
-    }
-    FPixmapList : TFPList;
-    {en
-       Lock used to synchronize access to PixmapManager storage.
-    }
-    FPixmapsLock: TCriticalSection;
-
-    FDriveIconList : TStringList;
-    FiDirIconID : PtrInt;
-    FiDirLinkIconID : PtrInt;
-    FiLinkIconID : PtrInt;
-    FiEmblemLinkID: PtrInt;
-    FiUpDirIconID : PtrInt;
-    FiDefaultIconID : PtrInt;
-    FiExeIconID : PtrInt;
-    FiArcIconID : PtrInt;
-    FiSortAscID : PtrInt;
-    FiSortDescID : PtrInt;
-    FPixmapSize : String;
-    {$IF DEFINED(MSWINDOWS)}
-    FSysImgList : THandle;
-    {$ELSEIF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
-    {en
-       Maps file extension to MIME icon name(s).
-    }
-    FExtToMimeIconName: TFPDataHashTable;
-    {en
-       Maps mime icon name to index of bitmap (in FPixmapList) for this icon.
-    }
-    FThemePixmapsFileNames: TStringHashList;
-    {$IFDEF LCLGTK2}
-    FIconTheme: PGtkIconTheme;
-    {$ELSE}
-    FIconTheme: TIconTheme;
-    {$ENDIF}
-    {$ENDIF}
-  protected
-    function LoadBitmap(AIconFileName: String; out ABitmap: TBitmap): Boolean;
-    function CheckLoadPixmap(const AIconName: String; bUsePixmapPath : Boolean = True) : TBitmap;
-    function CheckAddPixmap(AIconName: String; IconSize : Integer = 0; bUsePixmapPath : Boolean = True): PtrInt;
-  {$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
-    procedure CreateIconTheme;
-    procedure DestroyIconTheme;
-    {en
-       Loads MIME icons names and creates a mapping: file extension -> MIME icon name.
-       Doesn't need to be synchronized as long as it's only called from Load().
-    }
-    procedure LoadMimeIconNames;
-    {en
-       Loads a theme icon with a specific MIME icon name.
-       This function should only be called under FPixmapLock.
-    }
-    function LoadIconThemeIcon(AIconName: String; AIconSize: Integer): PtrInt;
-    {en
-       Retrieves index of a theme icon based on file extension.
-       Loads the icon if it is not yet loaded into PixmapManager.
-       This function should only be called under FPixmapLock.
-    }
-    function GetMimeIcon(AFileExt: String; AIconSize: Integer): PtrInt;
-    {en
-       It is synchronized in GetIconByName->CheckAddPixmap.
-    }
-    function GetIconByDesktopFile(sFileName: UTF8String; iDefaultIcon: PtrInt): PtrInt;
-  {$ENDIF}
-    function GetBuiltInDriveIcon(Drive : PDrive; IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
-  public
-    constructor Create;
-    destructor Destroy; override;
-    procedure Load(const sFileName : String);
-    function GetBitmap(iIndex : PtrInt; BkColor : TColor) : TBitmap; // Always returns new copy.
-    function DrawBitmap(iIndex: PtrInt; Canvas : TCanvas; X, Y: Integer) : Boolean;
-    {en
-       Draws bitmap stretching it if needed to Width x Height.
-       If Width is 0 then full bitmap width is used.
-       If Height is 0 then full bitmap height is used.
-       @param(iIndex
-              Index of pixmap manager's bitmap.)
-    }
-    function DrawBitmap(iIndex: PtrInt; Canvas : TCanvas; X, Y, Width, Height: Integer) : Boolean;
-    function DrawBitmap(iIndex: PtrInt; AFile: TFile; DirectAccess: Boolean; Canvas : TCanvas; X, Y: Integer) : Boolean;
-    function GetIconBySortingDirection(SortingDirection: TSortDirection): PtrInt;
-    function GetIconByFile(AFile: TFile; DirectAccess: Boolean): PtrInt;
-    function GetIconByName(const AIconName: UTF8String): PtrInt;
-    function GetDriveIcon(Drive : PDrive; IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
-    function GetDefaultDriveIcon(IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
-    function GetArchiveIcon(IconSize: Integer; clBackColor : TColor) : Graphics.TBitmap;
-  end;
-
-function StretchBitmap(var bmBitmap : Graphics.TBitmap; iIconSize : Integer;
-                       clBackColor : TColor; bFreeAtEnd : Boolean = False) : Graphics.TBitmap;
-function LoadBitmapFromFile(sFileName : String; iIconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
-
-var
-  PixMapManager:TPixMapManager = nil;
-
-procedure LoadPixMapManager;
-
-implementation
-
-uses
-  GraphType, LCLIntf, LCLType, LCLProc, Forms, FileUtil, uGlobsPaths, WcxPlugin,
-  uGlobs, uDCUtils, uFileSystemFile, uReSample
-  {$IFDEF LCLGTK2}
-    , uPixMapGtk, gtkdef, gdk2pixbuf, gdk2, glib2
-  {$ENDIF}
-  {$IFDEF MSWINDOWS}
-    , CommCtrl, ShellAPI, Windows, uIcoFiles, uGdiPlus, IntfGraphics, uShlObjAdditional
-  {$ELSE}
-    , StrUtils
-  {$ENDIF}
-  ;
-
-function StretchBitmap(var bmBitmap : Graphics.TBitmap; iIconSize : Integer;
-                       clBackColor : TColor; bFreeAtEnd : Boolean = False) : Graphics.TBitmap;
-var
-  memstream: TMemoryStream;
-begin
-  Result := Graphics.TBitMap.Create;
-  Result.SetSize(iIconSize, iIconSize);
-  if bmBitmap.RawImage.Description.AlphaPrec <> 0 then // if bitmap has alpha channel
-    Stretch(bmBitmap, Result, ResampleFilters[2].Filter, ResampleFilters[2].Width)
-  else
-    with Result do
-    begin
-      Canvas.Brush.Color := clBackColor;
-      Canvas.FillRect(Canvas.ClipRect);
-      Canvas.StretchDraw(Canvas.ClipRect, bmBitmap);
-      { For drawing color transparent bitmaps }
-      memstream := TMemoryStream.Create;
-      try
-        SaveToStream(memstream);
-        memstream.position := 0;
-        LoadFromStream(memstream);
-      finally
-        memstream.free;
-      end;
-      Transparent := True;
-      if bmBitmap.RawImage.Description.MaskBitsPerPixel = 0 then
-        TransparentColor := clBackColor;
-    end; //  with
-  if bFreeAtEnd then
-    FreeAndNil(bmBitmap);
-end;
-
-function LoadBitmapFromFile(sFileName : String; iIconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
-var
-{$IFDEF MSWINDOWS}
-  iPos,
-  iIconIndex,
-  iIconLarge,
-  iIconSmall: Integer;
-  phIcon: HICON = INVALID_HANDLE_VALUE;
-  phIconLarge,
-  phIconSmall : HICON;
-  Icon : TIcon = nil;
-{$ENDIF}
-  AFile: TFileSystemFile;
-  iIndex : PtrInt;
-  sExtFilter,
-  sGraphicFilter : String;
-  bFreeAtEnd : Boolean;
-  bmStandartBitmap : Graphics.TBitMap = nil;
-  {$IFDEF LCLGTK2}
-  pbPicture : PGdkPixbuf;
-  {$ENDIF}
-begin
-  Result := nil;
-
-  sFileName:= mbExpandFileName(sFileName);
-{$IFDEF MSWINDOWS}
-  iIconIndex := -1;
-  iPos :=Pos(',', sFileName);
-  if iPos <> 0 then
-    begin
-      iIconIndex := StrToIntDef(Copy(sFileName, iPos + 1, Length(sFileName) - iPos), 0);
-      sFileName := Copy(sFileName, 1, iPos - 1);
-    end;
-
-  if FileIsExeLib(sFileName) then
-    begin
-      if iIconIndex < 0 then iIconIndex := 0;
-      ExtractIconExW(PWChar(UTF8Decode(sFileName)), iIconIndex, phIconLarge, phIconSmall, 1);
-      // Get system metrics
-      iIconSmall:= GetSystemMetrics(SM_CXSMICON);
-      iIconLarge:= GetSystemMetrics(SM_CXICON);
-      if (iIconSize = 16) and (iIconSmall = 16) then
-        phIcon:= phIconSmall    // Use small icon
-      else if (iIconSize = 32) and (iIconLarge = 32) then
-        phIcon:= phIconLarge;   // Use large icon
-
-      if phIcon <> INVALID_HANDLE_VALUE then // standart icon size
-        try
-          Result:= Graphics.TBitMap.Create;
-          Icon:= CreateIconFromHandle(phIcon);
-          Result.Assign(Icon);
-        finally
-          FreeThenNil(Icon);
-        end
-      else // non standart icon size
-        try
-          bmStandartBitmap := Graphics.TBitMap.Create;
-          if iIconSize > iIconSmall then
-            phicon := phIconLarge // Use large icon
-          else
-            phicon := phIconSmall; // Use small icon
-          Icon:= CreateIconFromHandle(phIcon);
-          bmStandartBitmap.Assign(Icon);
-          Result:= StretchBitmap(bmStandartBitmap, iIconSize, clBackColor, True);
-        finally
-          FreeThenNil(Icon)
-        end;  // non standart size
-      DestroyIcon(phIconLarge);
-      DestroyIcon(phIconSmall);
-    end  // IsExecutable
-  else
-{$ENDIF}
-    begin
-      bFreeAtEnd := True;
-      sExtFilter := UTF8LowerCase(ExtractFileExt(sFileName)) + ';';
-      sGraphicFilter := GraphicFilter(TGraphic);
-      // if file is graphic
-      if (Pos(sExtFilter, sGraphicFilter) <> 0) and mbFileExists(sFileName) then
-      begin
-        {$IFDEF LCLGTK2}
-        pbPicture := gdk_pixbuf_new_from_file(PChar(sFileName), nil);
-        if pbPicture <> nil then
-        begin
-          bmStandartBitmap:= PixBufToBitmap(pbPicture);
-          gdk_pixmap_unref(pbPicture);
-        end
-        else // Try loading the standard way.
-        {$ELSE}
-        if not PixMapManager.LoadBitmap(sFileName, bmStandartBitmap) then
-          Exit;
-        {$ENDIF}
-      end
-      else // get file icon by ext
-        begin
-          if mbFileExists(sFileName) or mbDirectoryExists(sFileName) then
-            begin
-              AFile := TFileSystemFile.Create(sFileName);
-              iIndex := PixMapManager.GetIconByFile(AFile, True);
-              bmStandartBitmap := PixMapManager.GetBitmap(iIndex, clBackColor);
-              FreeAndNil(AFile);
-            end
-          else  // file not found
-            begin
-              Exit(nil);
-            end;
-        end;
-
-      // if need stretch icon
-      if  (iIconSize <> bmStandartBitmap.Height) or (iIconSize <> bmStandartBitmap.Width) then
-        Result := StretchBitmap(bmStandartBitmap, iIconSize, clBackColor, bFreeAtEnd)
-      else
-        Result := bmStandartBitmap;
-    end;  // IsExecutable else
-end;
-
-{ TPixMapManager }
-
-function TPixMapManager.LoadBitmap(AIconFileName: String; out ABitmap: Graphics.TBitmap): Boolean;
-var
-  Picture: TPicture;
-begin
-  Result:= False;
-  ABitmap:= nil;
-  try
-    Picture := TPicture.Create;
-    try
-      Picture.LoadFromFile(AIconFileName);
-      //Picture.Graphic.Transparent := True;
-
-      ABitmap := Graphics.TBitmap.Create;
-      ABitmap.Assign(Picture.Bitmap);
-
-      // if unsupported BitsPerPixel then exit
-      if ABitmap.RawImage.Description.BitsPerPixel > 32 then
-        raise EInvalidGraphic.Create('Unsupported bits per pixel');
-
-      Result:= True;
-    finally
-      FreeAndNil(Picture);
-    end;
-  except
-    on e: Exception do
-      begin
-        if Assigned(ABitmap) then
-          FreeAndNil(ABitmap);
-        DebugLn(Format('Error: Cannot load pixmap [%s] : %s',[AIconFileName, e.Message]));
-      end;
-  end;
-end;
-
-function TPixMapManager.CheckLoadPixmap(const AIconName: String; bUsePixmapPath : Boolean = True): Graphics.TBitmap;
-var
-  sFileName: String;
-begin
-  Result:= nil;
-
-  if bUsePixmapPath then
-    sFileName:= gpPixmapPath + FPixmapSize + AIconName
-  else
-    sFileName:= AIconName;
-    
-  if not mbFileExists(sFileName) then
-    begin
-      DebugLn(Format('Warning: pixmap [%s] not exists!',[sFileName]));
-      Exit;
-    end;
-  LoadBitmap(sFileName, Result);
-end;
-
-function TPixMapManager.CheckAddPixmap(AIconName: String; IconSize : Integer; bUsePixmapPath : Boolean): PtrInt;
-var
-  fileIndex: PtrInt;
-  {$IFDEF LCLGTK2}
-  pbPicture : PGdkPixbuf;
-  {$ELSE}
-  bmpBitmap: Graphics.TBitmap;
-  {$ENDIF}
-begin
-  Result:= -1;
-  if AIconName = EmptyStr then Exit;
-
-  if IconSize = 0 then IconSize:= gIconsSize;
-
-  FPixmapsLock.Acquire;
-  try
-    if bUsePixmapPath or (GetPathType(AIconName) = ptAbsolute) then
-      begin
-        if bUsePixmapPath then
-          AIconName := gpPixmapPath + FPixmapSize + AIconName;
-
-        // Determine if this file is already loaded.
-        fileIndex := FPixmapsFileNames.Find(AIconName);
-        if fileIndex < 0 then
-          begin
-            if not mbFileExists(AIconName) then
-              begin
-                DebugLn(Format('Warning: pixmap [%s] not exists!', [AIconName]));
-                Exit;
-              end;
-        {$IFDEF LCLGTK2}
-            pbPicture := gdk_pixbuf_new_from_file_at_size(PChar(AIconName), IconSize, IconSize, nil);
-            if Assigned(pbPicture) then
-              begin
-                Result := FPixmapList.Add(pbPicture);
-                FPixmapsFileNames.Add(AIconName, Pointer(Result));
-              end
-            else
-              DebugLn(Format('Error: pixmap [%s] not loaded!', [AIconName]));
-        {$ELSE}
-            if LoadBitmap(AIconName, bmpBitmap) then
-            begin
-              // Shrink big bitmaps before putting them into PixmapManager,
-              // to speed up later drawing.
-              //
-              // Note: Transparent bitmaps may lose transparency, because
-              // they must drawn onto a background, so we allow smaller bitmaps
-              // up to 48x48 (icons for example) to load in full size and they
-              // are resized upon drawing.
-              //
-              // TODO:
-              // This should resize any non-transparent,
-              // non-alpha channel bitmaps to gIconsSize
-              // (so if Width<>gIconsSize or Height<>gIconsSize then Resize).
-              if (bmpBitmap.Width > 48) or (bmpBitmap.Height > 48) then
-              begin
-                bmpBitmap := StretchBitmap(bmpBitmap, IconSize, clBlack, True);
-              end;
-              Result := FPixmapList.Add(bmpBitmap);
-              FPixmapsFileNames.Add(AIconName, Pointer(Result));
-            end;
-        {$ENDIF}
-          end
-        else
-          begin
-            Result:= PtrInt(FPixmapsFileNames.List[fileIndex]^.Data);
-          end;
-      end
-  {$IF DEFINED(UNIX) and NOT DEFINED(DARWIN)}
-    else  // Load theme icon
-      begin
-        Result := LoadIconThemeIcon(AIconName, IconSize);
-      end;
-  {$ENDIF}
-  finally
-    FPixmapsLock.Release;
-  end;
-end;
-
-{$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
-
-procedure TPixMapManager.CreateIconTheme;
-{$IFDEF LCLGTK2}
-begin
-  // get current gtk theme
-  FIconTheme:= gtk_icon_theme_get_for_screen(gdk_screen_get_default);
-  { // load custom theme
-  FIconTheme:= gtk_icon_theme_new;
-  gtk_icon_theme_set_custom_theme(FIconTheme, 'oxygen');
-  }
-end;
-{$ELSE}
-begin
-  FIconTheme:= TIconTheme.Create(GetCurrentIconTheme);
-end;
-{$ENDIF}
-
-procedure TPixMapManager.DestroyIconTheme;
-{$IFDEF LCLGTK2}
-begin
-  FIconTheme:= nil;
-end;
-{$ELSE}
-begin
-  if Assigned(FIconTheme) then
-    FreeAndNil(FIconTheme);
-end;
-{$ENDIF}
-
-procedure TPixMapManager.LoadMimeIconNames;
-const
-  mime_globs = '/usr/share/mime/globs';
-  mime_generic_icons = '/usr/share/mime/generic-icons';
-  pixmaps_cache = 'pixmaps.cache';
-  cache_signature: DWord = $44435043; // 'DCPC'
-  cache_version: DWord = 1;
-var
-  I, J, K: Integer;
-  globs: TStringListEx = nil;
-  generic_icons: TStringListEx = nil;
-  cache: TFileStreamEx = nil;
-  mTime: LongInt;
-  sMimeType,
-  sMimeIconName,
-  sExtension: String;
-  node: THTDataNode = nil;
-  iconsList: TStringList;
-  EntriesCount, IconsCount: Cardinal;
-  nodeList: TFPObjectList;
-begin
-  try
-    // Try to load from cache.
-    mTime:= mbFileAge(mime_globs);
-    if (mbFileAge(gpIniDir + pixmaps_cache) = mTime) and
-       (mbFileAccess(gpIniDir + pixmaps_cache, fmOpenRead)) and
-       (mbFileSize(gpIniDir + pixmaps_cache) > SizeOf(DWord) * 2) then
-    begin
-      cache := TFileStreamEx.Create(gpIniDir + pixmaps_cache, fmOpenRead);
-      if (cache.ReadDWord <> NtoBE(cache_signature)) or
-         (cache.ReadDWord <> cache_version) then
-      begin
-        FreeAndNil(cache);
-      end;
-    end;
-
-    if Assigned(cache) then
-      begin
-        EntriesCount := cache.ReadDWord;
-        FExtToMimeIconName.HashTableSize := EntriesCount;
-
-        // Each entry is a file extension with a list of icon names.
-        for I := 0 to EntriesCount - 1 do
-        begin
-          sExtension := cache.ReadAnsiString;
-          IconsCount := cache.ReadDWord;
-          iconsList := TStringList.Create;
-          FExtToMimeIconName.Add(sExtension, iconsList);
-          iconsList.Capacity := IconsCount;
-          for J := 0 to IconsCount - 1 do
-            iconsList.Add(cache.ReadAnsiString);
-        end;
-      end
-    else if mbFileAccess(mime_globs, fmOpenRead) then
-      begin
-        // Load mapping: MIME type -> file extension.
-        globs:= TStringListEx.Create;
-        globs.NameValueSeparator:= ':';
-        globs.LoadFromFile(mime_globs);
-
-        // Try to load mapping: MIME type -> generic MIME icon name.
-        if mbFileExists(mime_generic_icons) then
-          begin
-            generic_icons:= TStringListEx.Create;
-            generic_icons.NameValueSeparator:= ':';
-            generic_icons.LoadFromFile(mime_generic_icons);
-          end;
-
-        EntriesCount := 0;
-        // Create mapping: file extension -> list of MIME icon names.
-        for I:= 0 to globs.Count - 1 do
-          if (globs.Strings[I]    <> '') and   // bypass empty lines
-             (globs.Strings[I][1] <> '#') then // and comments
-          begin
-            sMimeType := globs.Names[I];
-            sMimeIconName:= StringReplace(sMimeType, '/', '-', []);
-            sExtension:= ExtractFileExt(globs.ValueFromIndex[I]);
-
-            // Support only extensions, not full file name masks.
-            if (sExtension <> '') and (sExtension <> '.*') then
-            begin
-              Delete(sExtension, 1, 1);
-
-              node := THTDataNode(FExtToMimeIconName.Find(sExtension));
-              if not Assigned(node) then
-                begin
-                  iconsList := TStringList.Create;
-                  FExtToMimeIconName.Add(sExtension, iconsList);
-                  Inc(EntriesCount);
-                end
-              else
-                iconsList := TStringList(node.Data);
-
-              if iconsList.IndexOf(sMimeIconName) < 0 then
-                iconsList.Add(sMimeIconName);
-
-              // Shared-mime-info spec says:
-              // "If [generic-icon] is not specified then the mimetype is used to generate the
-              // generic icon by using the top-level media type (e.g. "video" in "video/ogg")
-              // and appending "-x-generic" (i.e. "video-x-generic" in the previous example)."
-              if Assigned(generic_icons) then
-                begin
-                  J := generic_icons.IndexOfName(sMimeType);
-                  if J <> -1 then
-                    sMimeIconName := generic_icons.ValueFromIndex[J] // found generic icon
-                  else
-                    sMimeIconName := Copy2Symb(sMimeIconName, '-') + '-x-generic';
-                end
-              else
-                sMimeIconName := Copy2Symb(sMimeIconName, '-') + '-x-generic';
-
-              if iconsList.IndexOf(sMimeIconName) < 0 then
-                iconsList.Add(sMimeIconName);
-            end;
-          end;
-
-        // save to cache
-        cache := TFileStreamEx.Create(gpIniDir + pixmaps_cache, fmCreate);
-        cache.WriteDWord(NtoBE(cache_signature));
-        cache.WriteDWord(cache_version);
-        cache.WriteDWord(EntriesCount);
-        for I := 0 to FExtToMimeIconName.HashTable.Count - 1 do
-          begin
-            nodeList := TFPObjectList(FExtToMimeIconName.HashTable.Items[I]);
-            if Assigned(nodeList) then
-              for J := 0 to nodeList.Count - 1 do
-                begin
-                  node := THtDataNode(nodeList.Items[J]);
-                  iconsList := TStringList(node.Data);
-                  cache.WriteAnsiString(node.Key);
-                  cache.WriteDWord(iconsList.Count);
-                  for K := 0 to iconsList.Count - 1 do
-                    cache.WriteAnsiString(iconsList.Strings[K]);
-                end;
-          end;
-        FreeAndNil(cache); // Close file
-        mbFileSetTime(gpIniDir + pixmaps_cache, mTime, 0, 0);
-      end;
-
-  finally
-    if Assigned(globs) then
-      FreeAndNil(globs);
-    if Assigned(generic_icons) then
-      FreeAndNil(generic_icons);
-    if Assigned(cache) then
-      FreeAndNil(cache);
-  end;
-end;
-
-function TPixMapManager.GetMimeIcon(AFileExt: String; AIconSize: Integer): PtrInt;
-var
-  I: Integer;
-  node: THTDataNode;
-  iconList: TStringList;
-begin
-  // This function is called under FPixmapsLock.
-
-  Result := -1;
-
-  // Search for an icon for this file extension.
-  node := THTDataNode(FExtToMimeIconName.Find(AFileExt));
-  if Assigned(node) then
-    begin
-      iconList := TStringList(node.Data);
-      // Try to load one of the icons in the list.
-      for I := 0 to iconList.Count - 1 do
-        begin
-          Result := LoadIconThemeIcon(iconList.Strings[I], AIconSize);
-          if Result <> -1 then break;
-        end;
-    end;
-end;
-
-function TPixMapManager.LoadIconThemeIcon(AIconName: String; AIconSize: Integer): PtrInt;
-var
-  fileIndex: PtrInt;
-{$IFDEF LCLGTK2}
-  pbPicture: PGdkPixbuf;
-  pgcIconName: Pgchar;
-{$ELSE}
-  sIconFileName: UTF8String;
-  bmpBitmap: Graphics.TBitmap;
-{$ENDIF}
-begin
-  // This function is called under FPixmapsLock.
-
-  fileIndex := FThemePixmapsFileNames.Find(AIconName);
-  if fileIndex < 0 then
-    begin
-{$IFDEF LCLGTK2}
-      pgcIconName:= Pgchar(AIconName);
-      pbPicture:= gtk_icon_theme_load_icon(FIconTheme, pgcIconName, AIconSize, GTK_ICON_LOOKUP_NO_SVG, nil);
-      if pbPicture <> nil then
-        begin
-          Result := FPixmapList.Add(pbPicture);
-          FThemePixmapsFileNames.Add(AIconName, Pointer(Result));
-        end
-      else
-        Result := -1;
-{$ELSE}
-      sIconFileName:= FIconTheme.FindIcon(AIconName, AIconSize);
-      if sIconFileName <> EmptyStr then
-        begin
-          bmpBitmap := CheckLoadPixmap(sIconFileName, False);
-          if Assigned(bmpBitmap) then
-            begin
-              Result := FPixmapList.Add(bmpBitmap); // add to list
-              FThemePixmapsFileNames.Add(AIconName, Pointer(Result));
-            end;
-        end
-      else
-        Result := -1;
-{$ENDIF}
-    end
-  else
-    Result := PtrInt(FThemePixmapsFileNames.List[fileIndex]^.Data);
-end;
-
-function TPixMapManager.GetIconByDesktopFile(sFileName: UTF8String; iDefaultIcon: PtrInt): PtrInt;
-var
-  I: PtrInt;
-  iniDesktop: TIniFileEx;
-  sIconName: UTF8String;
-begin
-  iniDesktop:= TIniFileEx.Create(sFileName, fmOpenRead);
-  try
-    sIconName:= iniDesktop.ReadString('Desktop Entry', 'Icon', EmptyStr);
-  finally
-    FreeThenNil(iniDesktop);
-  end;
-
-  I:= GetIconByName(sIconName);
-  if I < 0 then
-    Result:= iDefaultIcon
-  else
-    Result:= I;
-end;
-
-{$ENDIF} // Unix
-
-constructor TPixMapManager.Create;
-{$IFDEF MSWINDOWS}
-var
-  FileInfo : TSHFileInfoW;
-  iIconSize : Integer;
-{$ENDIF}
-begin
-  FExtList := TStringHashList.Create(True);
-  FPixmapsFileNames := TStringHashList.Create(True);
-  FPixmapList := TFPList.Create;
-  FDriveIconList := TStringList.Create;
-
-  {$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
-  FExtToMimeIconName := TFPDataHashTable.Create;
-  FThemePixmapsFileNames := TStringHashList.Create(True);
-  CreateIconTheme;
-  {$ENDIF}
-
-  {$IFDEF MSWINDOWS}
-  if gIconsSize = 16 then
-    iIconSize := SHGFI_SMALLICON
-  else
-    iIconSize := SHGFI_LARGEICON;
-
-  FSysImgList := SHGetFileInfoW(PWideChar(UTF8Decode(mbGetCurrentDir)),
-                                0,
-                                FileInfo,
-                                SizeOf(FileInfo),
-                                SHGFI_SYSICONINDEX or iIconSize);
-  {$ENDIF}
-
-  FPixmapsLock := syncobjs.TCriticalSection.Create;
-end;
-
-destructor TPixMapManager.Destroy;
-var
-  I : Integer;
-{$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
-  J : Integer;
-  nodeList: TFPObjectList;
-{$ENDIF}
-begin
-  if Assigned(FPixmapList) then
-  begin
-    for I := 0 to FPixmapList.Count - 1 do
-      if Assigned(FPixmapList.Items[I]) then
-  {$IFDEF LCLGTK2}
-        g_object_unref(PGdkPixbuf(FPixmapList.Items[I]));
-  {$ELSE}
-        Graphics.TBitmap(FPixmapList.Items[I]).Free;
-  {$ENDIF}
-    FreeAndNil(FPixmapList);
-  end;
-
-  if Assigned(FExtList) then
-    FreeAndNil(FExtList);
-  if Assigned(FPixmapsFileNames) then
-    FreeAndNil(FPixmapsFileNames);
-
-  if Assigned(FDriveIconList) then
-  begin
-    for I := 0 to FDriveIconList.Count - 1 do
-      with FDriveIconList.Objects[I] as TDriveIconList do
-      begin
-        if Assigned(bmMediaFloppy) then FreeAndNil(bmMediaFloppy);
-        if Assigned(bmDriveHardDisk) then FreeAndNil(bmDriveHardDisk);
-        if Assigned(bmMediaFlash) then FreeAndNil(bmMediaFlash);
-        if Assigned(bmMediaOptical) then FreeAndNil(bmMediaOptical);
-        if Assigned(bmDriveNetwork) then FreeAndNil(bmDriveNetwork);
-        Free;
-      end;
-    FreeAndNil(FDriveIconList);
-  end;
-
-  {$IF DEFINED(MSWINDOWS)}
-  ImageList_Destroy(FSysImgList);
-  {$ELSEIF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
-  DestroyIconTheme;
-
-  for I := 0 to FExtToMimeIconName.HashTable.Count - 1 do
-    begin
-      nodeList := TFPObjectList(FExtToMimeIconName.HashTable.Items[I]);
-      if Assigned(nodeList) then
-        for J := 0 to nodeList.Count - 1 do
-          TStringList(THtDataNode(nodeList.Items[J]).Data).Free;
-    end;
-
-  FreeThenNil(FExtToMimeIconName);
-  FreeThenNil(FThemePixmapsFileNames);
-  {$ENDIF}
-
-  FreeThenNil(FPixmapsLock);
-
-  inherited Destroy;
-end;
-
-procedure TPixMapManager.Load(const sFileName: String);
-var
-  slPixmapList: TStringList;
-  s:String;
-  sExt, sPixMap:String;
-  iekv:integer;
-  iPixMap:PtrInt;
-  sPixMapSize : String;
-  I : Integer;
-  Plugins : TStringList;
-  sCurrentPlugin : String;
-  iCurPlugCaps : Integer;
-begin
-  // This function doesn't need to be synchronized
-  // as long as it is called before creating the main form
-  // (via LoadPixMapManager in doublecmd.lpr).
-
-  //  load all drive icons
-  FDriveIconList.AddObject('16x16', TDriveIconList.Create);
-  FDriveIconList.AddObject('22x22', TDriveIconList.Create);
-  FDriveIconList.AddObject('32x32', TDriveIconList.Create);
-
-  sPixMapSize := FPixmapSize;  // save icon size path
-  for I:= 0 to FDriveIconList.Count - 1 do
-    with FDriveIconList.Objects[I] as TDriveIconList do
-    begin
-      FPixmapSize := FDriveIconList.Strings[I] + PathDelim;
-      bmMediaFloppy := CheckLoadPixmap('devices' + PathDelim + 'media-floppy.png');
-      bmDriveHardDisk := CheckLoadPixmap('devices' + PathDelim + 'drive-harddisk.png');
-      bmMediaFlash := CheckLoadPixmap('devices' + PathDelim + 'media-flash.png');
-      bmMediaOptical := CheckLoadPixmap('devices' + PathDelim + 'media-optical.png');
-      bmDriveNetwork:= CheckLoadPixmap('devices' + PathDelim + 'network-wired.png');
-    end;
-  // load emblems
-  if gIconsSize = 22 then
-    I:= 16
-  else
-    I:= gIconsSize div 2;
-  FPixmapSize := IntToStr(I) + 'x' + IntToStr(I) + PathDelim;
-  FiEmblemLinkID:= CheckAddPixmap('emblems' + PathDelim + 'emblem-symbolic-link.png', gIconsSize div 2);
-  FPixmapSize := sPixMapSize;  // restore icon size path
-
-  // add some standard icons
-  FiDefaultIconID:=CheckAddPixmap('mimetypes' + PathDelim + 'unknown.png');
-  FiDirIconID:=CheckAddPixmap('filesystems' + PathDelim + 'folder.png');
-  FiDirLinkIconID:=CheckAddPixmap('filesystems' + PathDelim + 'folder-link.png');
-  FiLinkIconID:=CheckAddPixmap('filesystems' + PathDelim + 'link.png');
-  FiUpDirIconID:=CheckAddPixmap('actions' + PathDelim + 'go-up.png');
-  FiArcIconID := CheckAddPixmap('mimetypes' + PathDelim + 'package-x-generic.png');
-  FiExeIconID:= CheckAddPixmap('mimetypes' + PathDelim + 'application-x-executable.png');
-  FiSortAscID := CheckAddPixmap('actions' + PathDelim + 'view-sort-ascending.png');
-  FiSortDescID := CheckAddPixmap('actions' + PathDelim + 'view-sort-descending.png');
-
-  { Load icons from doublecmd.ext }
-  for I := 0 to gExts.Count - 1 do
-    begin
-      gExts.Items[I].IconIndex:= FiDefaultIconID;
-      sPixMap := gExts.Items[I].Icon;
-      if mbFileExists(sPixMap) then
-        begin
-          iPixMap:= CheckAddPixmap(sPixMap, gIconsSize, False);
-          if iPixMap < 0 then Continue;
-          gExts.Items[I].IconIndex:= iPixMap;
-          //DebugLn('sPixMap = ',sPixMap, ' Index = ', IntToStr(iPixMap));
-
-          // set pixmap index for all extensions
-          for iekv := 0 to gExts.Items[I].Extensions.Count - 1 do
-            begin
-              sExt := gExts.Items[I].Extensions[iekv];
-              if FExtList.Find(sExt) < 0 then
-                FExtList.Add(sExt, TObject(iPixMap));
-            end;
-        end;
-    end;
-  {/ Load icons from doublecmd.ext }  
-  
-  if mbFileExists(sFileName) then
-  begin
-    slPixmapList:= TStringList.Create;
-    slPixmapList.LoadFromFile(sFileName);
-    try
-      for I:= 0 to slPixmapList.Count - 1 do
-      begin
-        s:= slPixmapList.Strings[I];
-        s:=Trim(lowercase(s));
-        iekv:=Pos('=',s);
-        if iekv=0 then
-          Continue;
-        sExt:=Copy(s,1, iekv-1);
-        sPixMap:=Copy(s, iekv+1, length(s)-iekv);
-        iPixMap:=CheckAddPixmap('mimetypes' + PathDelim + sPixMap);
-        if iPixMap<0 then
-          Continue;
-
-        if FExtList.Find(sExt)<0 then
-          FExtList.Add(sExt, TObject(iPixMap));
-      end;
-    finally
-      slPixmapList.Free;
-    end;
-  end;
-
-  (* Set archive icons *)
-  
-  Plugins := TStringList.Create;
-  gIni.ReadSectionRaw('PackerPlugins', Plugins);
-  
-  for I:=0 to Plugins.Count - 1 do
-        begin
-          sCurrentPlugin := Plugins.ValueFromIndex[I];
-          sExt := Plugins.Names[I];
-          if (Length(sExt) > 0) and (sExt[1] <> '#') then // if plugin not disabled
-            begin
-          iCurPlugCaps := StrToInt(Copy(sCurrentPlugin, 1, Pos(',',sCurrentPlugin) - 1));
-          if (iCurPlugCaps and PK_CAPS_HIDE) <> PK_CAPS_HIDE then
-            begin
-                if FExtList.Find(sExt) < 0 then
-                  FExtList.Add(sExt, TObject(FiArcIconID));
-            end;
-            end;
-        end; //for
-  Plugins.Free;
-  
-  (* /Set archive icons *)
-
-  {$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
-  if (gShowIcons <> sim_none) and (gShowIcons <> sim_standart) then
-    begin
-      LoadMimeIconNames;
-      {$IFNDEF LCLGTK2}
-      FIconTheme.Load;
-      {$ENDIF}
-    end;
-  {$ENDIF}
-end;
-
-function TPixMapManager.GetBitmap(iIndex: PtrInt; BkColor : TColor): Graphics.TBitmap;
-var
-  PPixmap: Pointer;
-  PixmapFromList: Boolean = False;
-{$IFDEF MSWINDOWS}
-  hicn: HICON;
-  Icon: TIcon = nil;
-{$ENDIF}
-begin
-  FPixmapsLock.Acquire;
-  try
-    if (iIndex >= 0) and (iIndex < FPixmapList.Count) then
-    begin
-      PPixmap := FPixmapList[iIndex];
-      PixmapFromList := True;
-    end;
-  finally
-    FPixmapsLock.Release;
-  end;
-
-  if PixmapFromList then
-  begin
-{$IFDEF LCLGTK2}
-    Result:= PixBufToBitmap(PGdkPixbuf(PPixmap));
-{$ELSE}
-    // Make a new copy.
-    Result := Graphics.TBitmap.Create;
-    Result.Assign(Graphics.TBitmap(PPixmap));
-{$ENDIF}
-  end
-  else
-{$IFDEF MSWINDOWS}
-  if iIndex >= $1000 then
-    begin
-      Result:= nil;
-      hicn:= ImageList_GetIcon(FSysImgList, iIndex - $1000, ILD_NORMAL);
-      if hicn <> 0 then
-        try
-          Icon := CreateIconFromHandle(hicn);
-          Result := Graphics.TBitmap.Create;
-          Result.Assign(Icon);
-        finally
-          FreeThenNil(Icon);
-          DestroyIcon(hicn);
-        end
-    end;
-{$ELSE}
-  Result:= nil;
-{$ENDIF}
-end;
-
-function TPixMapManager.DrawBitmap(iIndex: PtrInt; Canvas : TCanvas; X, Y: Integer) : Boolean;
-begin
-  Result := DrawBitmap(iIndex, Canvas, X, Y, gIconsSize, gIconsSize); // X, Y, 0, 0 - No bitmap stretching.
-end;
-
-function TPixMapManager.DrawBitmap(iIndex: PtrInt; Canvas: TCanvas; X, Y, Width, Height: Integer): Boolean;
-
-  procedure TrySetSize(aWidth, aHeight: Integer);
-  begin
-    if Width = 0 then
-      Width := aWidth;
-    if Height = 0 then
-      Height := aHeight;
-  end;
-
-var
-  PPixmap: Pointer;
-  PixmapFromList: Boolean = False;
-{$IFDEF MSWINDOWS}
-  hicn: HICON;
-  cx, cy: Integer;
-{$ENDIF}
-{$IFDEF LCLGTK2}
-  pbPicture : PGdkPixbuf;
-  iPixbufWidth : Integer;
-  iPixbufHeight : Integer;
-{$ELSE}
-  Bitmap: Graphics.TBitmap;
-  aRect: TRect;
-{$ENDIF}
-begin
-  Result := True;
-
-  FPixmapsLock.Acquire;
-  try
-    if (iIndex >= 0) and (iIndex < FPixmapList.Count) then
-    begin
-      PPixmap := FPixmapList[iIndex];
-      PixmapFromList := True;
-    end;
-  finally
-    FPixmapsLock.Release;
-  end;
-
-  if PixmapFromList then
-  begin
-  {$IFDEF LCLGTK2}
-    pbPicture := PGdkPixbuf(PPixmap);
-    iPixbufWidth :=  gdk_pixbuf_get_width(pbPicture);
-    iPixbufHeight :=  gdk_pixbuf_get_height(pbPicture);
-    TrySetSize(iPixbufWidth, iPixbufHeight);
-    DrawPixbufAtCanvas(Canvas, pbPicture, 0, 0, X, Y, Width, Height);
-  {$ELSE}
-    Bitmap := Graphics.TBitmap(PPixmap);
-    TrySetSize(Bitmap.Width, Bitmap.Height);
-    aRect := Classes.Bounds(X, Y, Width, Height);
-    Canvas.StretchDraw(aRect, Bitmap);
-  {$ENDIF}
-  end
-  else
-  {$IFDEF MSWINDOWS}
-  if iIndex >= $1000 then
-    try
-      if ImageList_GetIconSize(FSysImgList, @cx, @cy) then
-        TrySetSize(cx, cy)
-      else
-        TrySetSize(gIconsSize, gIconsSize);
-
-      if (Height in [16, 32]) and (cx = Width) and (cy = Height) then
-        // for transparent
-        ImageList_Draw(FSysImgList, iIndex - $1000, Canvas.Handle, X, Y, ILD_TRANSPARENT)
-      else
-      begin
-        hicn:= ImageList_GetIcon(FSysImgList, iIndex - $1000, ILD_NORMAL);
-        try
-          if IsGdiPlusLoaded then
-            Result:= GdiPlusStretchDraw(hicn, Canvas.Handle, X, Y, Width, Height)
-          else
-            Result:= DrawIconEx(Canvas.Handle, X, Y, hicn, Width, Height, 0, 0, DI_NORMAL);
-        finally
-          DestroyIcon(hicn);
-        end;
-      end;
-    except
-      Result:= False;
-    end;
-
-  {$ELSE}
-    Result:= False;
-  {$ENDIF}
-end;
-
-function TPixMapManager.DrawBitmap(iIndex: PtrInt; AFile: TFile; DirectAccess: Boolean; Canvas: TCanvas; X, Y: Integer): Boolean;
-var
-  I: Integer;
-begin
-  Result:= DrawBitmap(iIndex, Canvas, X, Y);
-
-  if gIconOverlays then
-    begin
-    {$IFDEF MSWINDOWS}
-      if DirectAccess then
-      begin
-        I:= SHGetOverlayIconIndex(AFile.Path, AFile.Name);
-        if I >= 0 then
-          Result:= DrawBitmap(I + $1000, Canvas, X, Y);
-      end;
-    {$ELSE}
-      if AFile.IsLink then
-        begin
-          I:= gIconsSize div 2;
-          Result:= DrawBitmap(FiEmblemLinkID, Canvas, X, Y + I, I, I);
-        end;
-    {$ENDIF}
-    end;
-end;
-
-function TPixMapManager.GetIconBySortingDirection(SortingDirection: TSortDirection): PtrInt;
-begin
-  case SortingDirection of
-    sdDescending:
-      begin
-        Result := FiSortDescID;
-      end;
-    sdAscending:
-      begin
-        Result := FiSortAscID;
-      end;
-    else
-      Result := -1;
-  end;
-end;
-
-function TPixMapManager.GetIconByFile(AFile: TFile; DirectAccess: Boolean): PtrInt;
-var
-  Ext: String;
-{$IFDEF MSWINDOWS}
-  sFileName: String;
-  FileInfo: TSHFileInfoW;
-  dwFileAttributes: DWORD;
-  uFlags: UINT;
-{$ENDIF}
-begin
-  Result := -1;
-  if not Assigned(AFile) then Exit;
-
-  with AFile do
-  begin
-    if Name = '..' then
-    begin
-      Result := FiUpDirIconID;
-      Exit;
-    end;
-
-    if IsLinkToDirectory then
-    begin
-    {$IFDEF UNIX}
-      if gIconOverlays then
-        Result:= FiDirIconID
-      else
-    {$ENDIF}
-      Result := FiDirLinkIconID;
-      Exit;
-    end;
-
-    if IsDirectory then
-    begin
-      {$IF DEFINED(MSWINDOWS)}
-      if (gShowIcons = sim_standart) or
-         (not (DirectAccess and mbFileExists(Path + Name + '\desktop.ini'))) or
-         (GetDeviceCaps(Application.MainForm.Canvas.Handle, BITSPIXEL) < 16) then
-      {$ELSEIF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
-      if (gShowIcons = sim_all_and_exe) and
-         (DirectAccess and mbFileExists(Path + Name + '/.directory')) then
-        begin
-          Result:= GetIconByDesktopFile(Path + Name + '/.directory', FiDirIconID);
-          Exit;
-        end
-      else
-      {$ENDIF}
-        begin
-          Exit(FiDirIconID);
-        end;
-    end
-    else // not directory
-    begin
-      if IsLink and not gIconOverlays then
-        Exit(FiLinkIconID);
-
-      if (Extension = '') then
-        Exit(FiDefaultIconID);
-
-      Ext := UTF8LowerCase(Extension);
-
-      {$IF DEFINED(MSWINDOWS)}
-      if gShowIcons <> sim_all_and_exe then
-        begin
-          if Ext = 'exe' then
-            Exit(FiExeIconID)
-          else if Ext = 'lnk' then
-            Exit(FiLinkIconID)
-          else if Ext = 'ico' then
-            Exit(FiDefaultIconID)
-        end;
-      {$ELSEIF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
-      if gShowIcons = sim_all_and_exe then
-        begin
-          if DirectAccess and (Ext = 'desktop') then
-            begin
-              Result:= GetIconByDesktopFile(Path + Name, FiDefaultIconID);
-              Exit;
-            end;
-        end;
-      {$ENDIF}
-
-      FPixmapsLock.Acquire;
-      try
-        Result := FExtList.Find(Ext);
-        if Result >= 0 then
-          Exit(PtrInt(FExtList.List[Result]^.Data));
-
-        if gShowIcons = sim_standart then
-          Exit(FiDefaultIconID);
-
-        {$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
-
-        Result := GetMimeIcon(Ext, gIconsSize);
-        if Result < 0 then
-          Result := FiDefaultIconID;
-
-        // Default icon should also be associated with the extension
-        // because it will be faster to find next time.
-        FExtList.Add(Ext, Pointer(Result));
-
-        {$ENDIF}
-
-      finally
-        FPixmapsLock.Release;
-      end;
-    end;
-
-    {$IF DEFINED(MSWINDOWS)}
-
-    if DirectAccess then
-      begin
-        dwFileAttributes := 0;
-        uFlags := SHGFI_SYSICONINDEX;
-        sFileName := Path + Name;
-      end
-    else
-      begin
-        dwFileAttributes := FILE_ATTRIBUTE_NORMAL;
-        uFlags := SHGFI_SYSICONINDEX or SHGFI_USEFILEATTRIBUTES;
-        sFileName := Name;
-      end;
-
-    if gIconsSize = 16 then
-      uFlags := uFlags or SHGFI_SMALLICON
-    else
-      uFlags := uFlags or SHGFI_LARGEICON;
-
-    if (SHGetFileInfoW(PWideChar(UTF8Decode(sFileName)),
-                       dwFileAttributes,
-                       FileInfo,
-                       SizeOf(FileInfo),
-                       uFlags) = 0) then
-    begin
-      // Could not retrieve icon.
-      if IsDirectory then
-        Result := FiDirIconID
-      else
-        Result := FiDefaultIconID;
-    end
-    else
-    begin
-      Result := FileInfo.iIcon + $1000;
-
-      if (not IsDirectory) and
-         (Ext <> 'exe') and
-         (Ext <> 'ico') and
-         (Ext <> 'lnk') then
-      begin
-        FPixmapsLock.Acquire;
-        try
-          FExtList.Add(Ext, Pointer(Result));
-        finally
-          FPixmapsLock.Release;
-        end;
-      end;
-    end;
-
-    {$ENDIF}
-  end;
-end;
-
-function TPixMapManager.GetIconByName(const AIconName: UTF8String): PtrInt;
-begin
-  Result := CheckAddPixmap(AIconName, gIconsSize, False);
-end;
-
-function TPixMapManager.GetDriveIcon(Drive : PDrive; IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
-{$IFDEF MSWINDOWS}
-var
-  SFI: TSHFileInfo;
-  Icon: TIcon = nil;
-  uFlags: UINT;
-  iIconSmall,
-  iIconLarge: Integer;
-{$ENDIF}
-begin
-  Result := nil;
-{$IFDEF MSWINDOWS}
-  if GetDeviceCaps(Application.MainForm.Canvas.Handle, BITSPIXEL) < 15 then Exit;
-  if (not gCustomDriveIcons) and (GetDeviceCaps(Application.MainForm.Canvas.Handle, BITSPIXEL) > 16) then
-    begin
-      SFI.hIcon := 0;
-      Result := Graphics.TBitMap.Create;
-      iIconSmall:= GetSystemMetrics(SM_CXSMICON);
-      iIconLarge:= GetSystemMetrics(SM_CXICON);
-
-      if (IconSize = 16) and (iIconSmall = 16) then // standart small icon
-        uFlags := SHGFI_SMALLICON // Use small icon
-      else if (IconSize = 32) and (iIconLarge = 32) then // standart large icon
-        uFlags := SHGFI_LARGEICON // Use large icon
-      else if IconSize > iIconSmall then
-        uFlags := SHGFI_LARGEICON // Use large icon
-      else
-        uFlags := SHGFI_SMALLICON; // Use small icon
-
-      if (SHGetFileInfo(PChar(Drive^.Path), 0, SFI, SizeOf(SFI), uFlags or SHGFI_ICON) <> 0) and
-          (SFI.hIcon <> 0) then
-        begin
-          if (IconSize = iIconSmall) or (IconSize = iIconLarge) then // standart icon size
-            try
-              Icon := CreateIconFromHandle(SFI.hIcon);
-              Result.Assign(Icon);
-            finally
-              FreeThenNil(Icon);
-              DestroyIcon(SFI.hIcon);
-            end
-          else // non standart icon size
-            try
-              Icon := CreateIconFromHandle(SFI.hIcon);
-              Result.Assign(Icon);
-              Result := StretchBitmap(Result, IconSize, clBackColor, True);
-            finally
-              FreeThenNil(Icon);
-              DestroyIcon(SFI.hIcon);
-            end
-        end;
-    end // not gCustomDriveIcons
-  else
-{$ENDIF}
-    begin
-      Result := GetBuiltInDriveIcon(Drive, IconSize, clBackColor);
-    end;
-end;
-
-function TPixMapManager.GetBuiltInDriveIcon(Drive : PDrive; IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
-var
-  DriveIconListIndex: Integer;
-  Bitmap: Graphics.TBitmap;
-begin
-{$IFDEF MSWINDOWS}
-  if GetDeviceCaps(Application.MainForm.Canvas.Handle, BITSPIXEL) < 15 then Exit(nil);
-{$ENDIF}
-  case IconSize of
-  16: // Standart 16x16 icon size
-    DriveIconListIndex := 0;
-  22:  // Standart 22x22 icon size
-    DriveIconListIndex := 1;
-  32:  // Standart 32x32 icon size
-    DriveIconListIndex := 2;
-  else  // for non standart icon size use more large icon for stretch
-    DriveIconListIndex := 2;
-  end;
-  with FDriveIconList.Objects[DriveIconListIndex] as TDriveIconList do
-  case Drive^.DriveType of
-  dtFloppy:
-    Bitmap := bmMediaFloppy;
-  dtFixed:
-    Bitmap := bmDriveHardDisk;
-  dtFlash:
-    Bitmap := bmMediaFlash;
-  dtCDROM:
-    Bitmap := bmMediaOptical;
-  dtNetwork:
-    Bitmap := bmDriveNetwork;
-  else
-    Bitmap := bmDriveHardDisk;
-  end;
-  //  if need stretch icon
-  if (IconSize <> 16) and (IconSize <> 22) and (IconSize <> 32) then
-    begin
-      Result := StretchBitmap(Bitmap, IconSize, clBackColor, False);
-    end
-  else
-    begin
-      Result := Graphics.TBitmap.Create;
-      Result.Assign(Bitmap);
-    end;
-  // 'Bitmap' should not be freed, because it only points to DriveIconList.
-end;
-
-function TPixMapManager.GetDefaultDriveIcon(IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
-var
-  Drive: TDrive = (Name: ''; Path: ''; DriveLabel: ''; DriveType: dtFixed);
-begin
-  Result := GetBuiltInDriveIcon(@Drive, IconSize, clBackColor);
-end;
-
-function TPixMapManager.GetArchiveIcon(IconSize: Integer; clBackColor : TColor) : Graphics.TBitmap;
-begin
-  Result := GetBitmap(FiArcIconID, clBackColor);
-  if Assigned(Result) then
-  begin
-    //  if need stretch icon
-    if (IconSize <> gIconsSize) then
-      begin
-        Result := StretchBitmap(Result, IconSize, clBackColor, True);
-      end;
-  end;
-end;
-
-procedure LoadPixMapManager;
-begin
-  PixMapManager:=TPixMapManager.Create;
-  PixMapManager.FPixmapSize:= IntToStr(gIconsSize) + 'x' + IntToStr(gIconsSize) + PathDelim;
-  PixMapManager.Load(gpIniDir+'pixmaps.txt');
-end;
-
-initialization
-
-finalization
-
-  if Assigned(PixMapManager) then
-    FreeAndNil(PixMapManager);
-
-end.
-
+{
+   File name: uPixMapManager.pas
+   Date:      2004/04/xx
+   Author:    Radek Cervinka  <[email protected]>
+
+   Fast pixmap memory manager a loader
+
+   Copyright (C) 2004
+   
+   contributors:
+   
+   Copyright (C) 2006-2009  Koblov Alexander ([email protected])
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   in a file called COPYING along with this program; if not, write to
+   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
+   02139, USA.
+}
+
+
+unit uPixMapManager;
+
+{$mode objfpc}{$H+}
+
+interface
+
+{
+  GTK2 is used directly in PixmapManager, because FPC/Lazarus draws bitmaps
+  without alpha channel under GTK2, so bitmaps looks ugly.
+  If this problem will be fixed then GTK2 specific code could be dropped.
+}
+
+uses
+  Classes, SysUtils, Graphics, syncobjs,
+  uOSUtils, uFileSorting, StringHashList, uFile
+  {$IF DEFINED(UNIX)}
+  , uClassesEx
+    {$IF NOT DEFINED(DARWIN)}
+    , contnrs
+      {$IFDEF LCLGTK2}
+      , gtk2
+      {$ELSE}
+      , uIconTheme, uMyIconTheme
+      {$ENDIF}
+    {$ENDIF}
+  {$ENDIF};
+
+type
+  TDriveIconList = class
+    bmMediaFloppy,
+    bmDriveHardDisk,
+    bmMediaFlash,
+    bmMediaOptical,
+    bmDriveNetwork: TBitmap;
+  end;
+
+  { TPixMapManager }
+
+  TPixMapManager = class
+  
+  private
+    {en
+       Maps file extension to index of bitmap (in FPixmapList) for this file extension.
+    }
+    FExtList : TStringHashList;
+    {en
+       Maps icon filename to index of bitmap (in FPixmapList) for this icon.
+       Uses absolute file names.
+    }
+    FPixmapsFileNames : TStringHashList;
+    {en
+       A list of loaded bitmaps.
+       Stores TBitmap objects (on GTK2 it stores PGdkPixbuf pointers).
+    }
+    FPixmapList : TFPList;
+    {en
+       Lock used to synchronize access to PixmapManager storage.
+    }
+    FPixmapsLock: TCriticalSection;
+
+    FDriveIconList : TStringList;
+    FiDirIconID : PtrInt;
+    FiDirLinkIconID : PtrInt;
+    FiLinkIconID : PtrInt;
+    FiEmblemLinkID: PtrInt;
+    FiUpDirIconID : PtrInt;
+    FiDefaultIconID : PtrInt;
+    FiExeIconID : PtrInt;
+    FiArcIconID : PtrInt;
+    FiSortAscID : PtrInt;
+    FiSortDescID : PtrInt;
+    FPixmapSize : String;
+    {$IF DEFINED(MSWINDOWS)}
+    FSysImgList : THandle;
+    {$ELSEIF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
+    {en
+       Maps file extension to MIME icon name(s).
+    }
+    FExtToMimeIconName: TFPDataHashTable;
+    {en
+       Maps mime icon name to index of bitmap (in FPixmapList) for this icon.
+    }
+    FThemePixmapsFileNames: TStringHashList;
+    {$IFDEF LCLGTK2}
+    FIconTheme: PGtkIconTheme;
+    {$ELSE}
+    FIconTheme: TIconTheme;
+    {$ENDIF}
+    {$ENDIF}
+  protected
+    function LoadBitmap(AIconFileName: String; out ABitmap: TBitmap): Boolean;
+    function CheckLoadPixmap(const AIconName: String; bUsePixmapPath : Boolean = True) : TBitmap;
+    function CheckAddPixmap(AIconName: String; IconSize : Integer = 0; bUsePixmapPath : Boolean = True): PtrInt;
+  {$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
+    procedure CreateIconTheme;
+    procedure DestroyIconTheme;
+    {en
+       Loads MIME icons names and creates a mapping: file extension -> MIME icon name.
+       Doesn't need to be synchronized as long as it's only called from Load().
+    }
+    procedure LoadMimeIconNames;
+    {en
+       Loads a theme icon with a specific MIME icon name.
+       This function should only be called under FPixmapLock.
+    }
+    function LoadIconThemeIcon(AIconName: String; AIconSize: Integer): PtrInt;
+    {en
+       Retrieves index of a theme icon based on file extension.
+       Loads the icon if it is not yet loaded into PixmapManager.
+       This function should only be called under FPixmapLock.
+    }
+    function GetMimeIcon(AFileExt: String; AIconSize: Integer): PtrInt;
+    {en
+       It is synchronized in GetIconByName->CheckAddPixmap.
+    }
+    function GetIconByDesktopFile(sFileName: UTF8String; iDefaultIcon: PtrInt): PtrInt;
+  {$ENDIF}
+    function GetBuiltInDriveIcon(Drive : PDrive; IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    procedure Load(const sFileName : String);
+    function GetBitmap(iIndex : PtrInt; BkColor : TColor) : TBitmap; // Always returns new copy.
+    function DrawBitmap(iIndex: PtrInt; Canvas : TCanvas; X, Y: Integer) : Boolean;
+    {en
+       Draws bitmap stretching it if needed to Width x Height.
+       If Width is 0 then full bitmap width is used.
+       If Height is 0 then full bitmap height is used.
+       @param(iIndex
+              Index of pixmap manager's bitmap.)
+    }
+    function DrawBitmap(iIndex: PtrInt; Canvas : TCanvas; X, Y, Width, Height: Integer) : Boolean;
+    function DrawBitmap(iIndex: PtrInt; AFile: TFile; DirectAccess: Boolean; Canvas : TCanvas; X, Y: Integer) : Boolean;
+    function GetIconBySortingDirection(SortingDirection: TSortDirection): PtrInt;
+    function GetIconByFile(AFile: TFile; DirectAccess: Boolean): PtrInt;
+    function GetIconByName(const AIconName: UTF8String): PtrInt;
+    function GetDriveIcon(Drive : PDrive; IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
+    function GetDefaultDriveIcon(IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
+    function GetArchiveIcon(IconSize: Integer; clBackColor : TColor) : Graphics.TBitmap;
+  end;
+
+function StretchBitmap(var bmBitmap : Graphics.TBitmap; iIconSize : Integer;
+                       clBackColor : TColor; bFreeAtEnd : Boolean = False) : Graphics.TBitmap;
+function LoadBitmapFromFile(sFileName : String; iIconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
+
+var
+  PixMapManager:TPixMapManager = nil;
+
+procedure LoadPixMapManager;
+
+implementation
+
+uses
+  GraphType, LCLIntf, LCLType, LCLProc, Forms, FileUtil, uGlobsPaths, WcxPlugin,
+  uGlobs, uDCUtils, uFileSystemFile, uReSample
+  {$IFDEF LCLGTK2}
+    , uPixMapGtk, gtkdef, gdk2pixbuf, gdk2, glib2
+  {$ENDIF}
+  {$IFDEF MSWINDOWS}
+    , CommCtrl, ShellAPI, Windows, uIcoFiles, uGdiPlus, IntfGraphics, uShlObjAdditional
+  {$ELSE}
+    , StrUtils
+  {$ENDIF}
+  ;
+
+function StretchBitmap(var bmBitmap : Graphics.TBitmap; iIconSize : Integer;
+                       clBackColor : TColor; bFreeAtEnd : Boolean = False) : Graphics.TBitmap;
+var
+  memstream: TMemoryStream;
+begin
+  Result := Graphics.TBitMap.Create;
+  Result.SetSize(iIconSize, iIconSize);
+  if bmBitmap.RawImage.Description.AlphaPrec <> 0 then // if bitmap has alpha channel
+    Stretch(bmBitmap, Result, ResampleFilters[2].Filter, ResampleFilters[2].Width)
+  else
+    with Result do
+    begin
+      Canvas.Brush.Color := clBackColor;
+      Canvas.FillRect(Canvas.ClipRect);
+      Canvas.StretchDraw(Canvas.ClipRect, bmBitmap);
+      { For drawing color transparent bitmaps }
+      memstream := TMemoryStream.Create;
+      try
+        SaveToStream(memstream);
+        memstream.position := 0;
+        LoadFromStream(memstream);
+      finally
+        memstream.free;
+      end;
+      Transparent := True;
+      if bmBitmap.RawImage.Description.MaskBitsPerPixel = 0 then
+        TransparentColor := clBackColor;
+    end; //  with
+  if bFreeAtEnd then
+    FreeAndNil(bmBitmap);
+end;
+
+function LoadBitmapFromFile(sFileName : String; iIconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
+var
+{$IFDEF MSWINDOWS}
+  iPos,
+  iIconIndex,
+  iIconLarge,
+  iIconSmall: Integer;
+  phIcon: HICON = INVALID_HANDLE_VALUE;
+  phIconLarge,
+  phIconSmall : HICON;
+  Icon : TIcon = nil;
+{$ENDIF}
+  AFile: TFileSystemFile;
+  iIndex : PtrInt;
+  sExtFilter,
+  sGraphicFilter : String;
+  bFreeAtEnd : Boolean;
+  bmStandartBitmap : Graphics.TBitMap = nil;
+  {$IFDEF LCLGTK2}
+  pbPicture : PGdkPixbuf;
+  {$ENDIF}
+begin
+  Result := nil;
+
+  sFileName:= mbExpandFileName(sFileName);
+{$IFDEF MSWINDOWS}
+  iIconIndex := -1;
+  iPos :=Pos(',', sFileName);
+  if iPos <> 0 then
+    begin
+      iIconIndex := StrToIntDef(Copy(sFileName, iPos + 1, Length(sFileName) - iPos), 0);
+      sFileName := Copy(sFileName, 1, iPos - 1);
+    end;
+
+  if FileIsExeLib(sFileName) then
+    begin
+      if iIconIndex < 0 then iIconIndex := 0;
+      ExtractIconExW(PWChar(UTF8Decode(sFileName)), iIconIndex, phIconLarge, phIconSmall, 1);
+      // Get system metrics
+      iIconSmall:= GetSystemMetrics(SM_CXSMICON);
+      iIconLarge:= GetSystemMetrics(SM_CXICON);
+      if (iIconSize = 16) and (iIconSmall = 16) then
+        phIcon:= phIconSmall    // Use small icon
+      else if (iIconSize = 32) and (iIconLarge = 32) then
+        phIcon:= phIconLarge;   // Use large icon
+
+      if phIcon <> INVALID_HANDLE_VALUE then // standart icon size
+        try
+          Result:= Graphics.TBitMap.Create;
+          Icon:= CreateIconFromHandle(phIcon);
+          Result.Assign(Icon);
+        finally
+          FreeThenNil(Icon);
+        end
+      else // non standart icon size
+        try
+          bmStandartBitmap := Graphics.TBitMap.Create;
+          if iIconSize > iIconSmall then
+            phicon := phIconLarge // Use large icon
+          else
+            phicon := phIconSmall; // Use small icon
+          Icon:= CreateIconFromHandle(phIcon);
+          bmStandartBitmap.Assign(Icon);
+          Result:= StretchBitmap(bmStandartBitmap, iIconSize, clBackColor, True);
+        finally
+          FreeThenNil(Icon)
+        end;  // non standart size
+      DestroyIcon(phIconLarge);
+      DestroyIcon(phIconSmall);
+    end  // IsExecutable
+  else
+{$ENDIF}
+    begin
+      bFreeAtEnd := True;
+      sExtFilter := UTF8LowerCase(ExtractFileExt(sFileName)) + ';';
+      sGraphicFilter := GraphicFilter(TGraphic);
+      // if file is graphic
+      if (Pos(sExtFilter, sGraphicFilter) <> 0) and mbFileExists(sFileName) then
+      begin
+        {$IFDEF LCLGTK2}
+        pbPicture := gdk_pixbuf_new_from_file(PChar(sFileName), nil);
+        if pbPicture <> nil then
+        begin
+          bmStandartBitmap:= PixBufToBitmap(pbPicture);
+          gdk_pixmap_unref(pbPicture);
+        end
+        else // Try loading the standard way.
+        {$ELSE}
+        if not PixMapManager.LoadBitmap(sFileName, bmStandartBitmap) then
+          Exit;
+        {$ENDIF}
+      end
+      else // get file icon by ext
+        begin
+          if mbFileExists(sFileName) or mbDirectoryExists(sFileName) then
+            begin
+              AFile := TFileSystemFile.Create(sFileName);
+              iIndex := PixMapManager.GetIconByFile(AFile, True);
+              bmStandartBitmap := PixMapManager.GetBitmap(iIndex, clBackColor);
+              FreeAndNil(AFile);
+            end
+          else  // file not found
+            begin
+              Exit(nil);
+            end;
+        end;
+
+      // if need stretch icon
+      if  (iIconSize <> bmStandartBitmap.Height) or (iIconSize <> bmStandartBitmap.Width) then
+        Result := StretchBitmap(bmStandartBitmap, iIconSize, clBackColor, bFreeAtEnd)
+      else
+        Result := bmStandartBitmap;
+    end;  // IsExecutable else
+end;
+
+{ TPixMapManager }
+
+function TPixMapManager.LoadBitmap(AIconFileName: String; out ABitmap: Graphics.TBitmap): Boolean;
+var
+  Picture: TPicture;
+begin
+  Result:= False;
+  ABitmap:= nil;
+  try
+    Picture := TPicture.Create;
+    try
+      Picture.LoadFromFile(AIconFileName);
+      //Picture.Graphic.Transparent := True;
+
+      ABitmap := Graphics.TBitmap.Create;
+      ABitmap.Assign(Picture.Bitmap);
+
+      // if unsupported BitsPerPixel then exit
+      if ABitmap.RawImage.Description.BitsPerPixel > 32 then
+        raise EInvalidGraphic.Create('Unsupported bits per pixel');
+
+      Result:= True;
+    finally
+      FreeAndNil(Picture);
+    end;
+  except
+    on e: Exception do
+      begin
+        if Assigned(ABitmap) then
+          FreeAndNil(ABitmap);
+        DebugLn(Format('Error: Cannot load pixmap [%s] : %s',[AIconFileName, e.Message]));
+      end;
+  end;
+end;
+
+function TPixMapManager.CheckLoadPixmap(const AIconName: String; bUsePixmapPath : Boolean = True): Graphics.TBitmap;
+var
+  sFileName: String;
+begin
+  Result:= nil;
+
+  if bUsePixmapPath then
+    sFileName:= gpPixmapPath + FPixmapSize + AIconName
+  else
+    sFileName:= AIconName;
+    
+  if not mbFileExists(sFileName) then
+    begin
+      DebugLn(Format('Warning: pixmap [%s] not exists!',[sFileName]));
+      Exit;
+    end;
+  LoadBitmap(sFileName, Result);
+end;
+
+function TPixMapManager.CheckAddPixmap(AIconName: String; IconSize : Integer; bUsePixmapPath : Boolean): PtrInt;
+var
+  fileIndex: PtrInt;
+  {$IFDEF LCLGTK2}
+  pbPicture : PGdkPixbuf;
+  {$ELSE}
+  bmpBitmap: Graphics.TBitmap;
+  {$ENDIF}
+begin
+  Result:= -1;
+  if AIconName = EmptyStr then Exit;
+
+  if IconSize = 0 then IconSize:= gIconsSize;
+
+  FPixmapsLock.Acquire;
+  try
+    if bUsePixmapPath or (GetPathType(AIconName) = ptAbsolute) then
+      begin
+        if bUsePixmapPath then
+          AIconName := gpPixmapPath + FPixmapSize + AIconName;
+
+        // Determine if this file is already loaded.
+        fileIndex := FPixmapsFileNames.Find(AIconName);
+        if fileIndex < 0 then
+          begin
+            if not mbFileExists(AIconName) then
+              begin
+                DebugLn(Format('Warning: pixmap [%s] not exists!', [AIconName]));
+                Exit;
+              end;
+        {$IFDEF LCLGTK2}
+            pbPicture := gdk_pixbuf_new_from_file_at_size(PChar(AIconName), IconSize, IconSize, nil);
+            if Assigned(pbPicture) then
+              begin
+                Result := FPixmapList.Add(pbPicture);
+                FPixmapsFileNames.Add(AIconName, Pointer(Result));
+              end
+            else
+              DebugLn(Format('Error: pixmap [%s] not loaded!', [AIconName]));
+        {$ELSE}
+            if LoadBitmap(AIconName, bmpBitmap) then
+            begin
+              // Shrink big bitmaps before putting them into PixmapManager,
+              // to speed up later drawing.
+              //
+              // Note: Transparent bitmaps may lose transparency, because
+              // they must drawn onto a background, so we allow smaller bitmaps
+              // up to 48x48 (icons for example) to load in full size and they
+              // are resized upon drawing.
+              //
+              // TODO:
+              // This should resize any non-transparent,
+              // non-alpha channel bitmaps to gIconsSize
+              // (so if Width<>gIconsSize or Height<>gIconsSize then Resize).
+              if (bmpBitmap.Width > 48) or (bmpBitmap.Height > 48) then
+              begin
+                bmpBitmap := StretchBitmap(bmpBitmap, IconSize, clBlack, True);
+              end;
+              Result := FPixmapList.Add(bmpBitmap);
+              FPixmapsFileNames.Add(AIconName, Pointer(Result));
+            end;
+        {$ENDIF}
+          end
+        else
+          begin
+            Result:= PtrInt(FPixmapsFileNames.List[fileIndex]^.Data);
+          end;
+      end
+  {$IF DEFINED(UNIX) and NOT DEFINED(DARWIN)}
+    else  // Load theme icon
+      begin
+        Result := LoadIconThemeIcon(AIconName, IconSize);
+      end;
+  {$ENDIF}
+  finally
+    FPixmapsLock.Release;
+  end;
+end;
+
+{$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
+
+procedure TPixMapManager.CreateIconTheme;
+{$IFDEF LCLGTK2}
+begin
+  // get current gtk theme
+  FIconTheme:= gtk_icon_theme_get_for_screen(gdk_screen_get_default);
+  { // load custom theme
+  FIconTheme:= gtk_icon_theme_new;
+  gtk_icon_theme_set_custom_theme(FIconTheme, 'oxygen');
+  }
+end;
+{$ELSE}
+begin
+  FIconTheme:= TIconTheme.Create(GetCurrentIconTheme);
+end;
+{$ENDIF}
+
+procedure TPixMapManager.DestroyIconTheme;
+{$IFDEF LCLGTK2}
+begin
+  FIconTheme:= nil;
+end;
+{$ELSE}
+begin
+  if Assigned(FIconTheme) then
+    FreeAndNil(FIconTheme);
+end;
+{$ENDIF}
+
+procedure TPixMapManager.LoadMimeIconNames;
+const
+  mime_globs = '/usr/share/mime/globs';
+  mime_generic_icons = '/usr/share/mime/generic-icons';
+  pixmaps_cache = 'pixmaps.cache';
+  cache_signature: DWord = $44435043; // 'DCPC'
+  cache_version: DWord = 1;
+var
+  I, J, K: Integer;
+  globs: TStringListEx = nil;
+  generic_icons: TStringListEx = nil;
+  cache: TFileStreamEx = nil;
+  mTime: LongInt;
+  sMimeType,
+  sMimeIconName,
+  sExtension: String;
+  node: THTDataNode = nil;
+  iconsList: TStringList;
+  EntriesCount, IconsCount: Cardinal;
+  nodeList: TFPObjectList;
+begin
+  try
+    // Try to load from cache.
+    mTime:= mbFileAge(mime_globs);
+    if (mbFileAge(gpIniDir + pixmaps_cache) = mTime) and
+       (mbFileAccess(gpIniDir + pixmaps_cache, fmOpenRead)) and
+       (mbFileSize(gpIniDir + pixmaps_cache) > SizeOf(DWord) * 2) then
+    begin
+      cache := TFileStreamEx.Create(gpIniDir + pixmaps_cache, fmOpenRead);
+      if (cache.ReadDWord <> NtoBE(cache_signature)) or
+         (cache.ReadDWord <> cache_version) then
+      begin
+        FreeAndNil(cache);
+      end;
+    end;
+
+    if Assigned(cache) then
+      begin
+        EntriesCount := cache.ReadDWord;
+        FExtToMimeIconName.HashTableSize := EntriesCount;
+
+        // Each entry is a file extension with a list of icon names.
+        for I := 0 to EntriesCount - 1 do
+        begin
+          sExtension := cache.ReadAnsiString;
+          IconsCount := cache.ReadDWord;
+          iconsList := TStringList.Create;
+          FExtToMimeIconName.Add(sExtension, iconsList);
+          iconsList.Capacity := IconsCount;
+          for J := 0 to IconsCount - 1 do
+            iconsList.Add(cache.ReadAnsiString);
+        end;
+      end
+    else if mbFileAccess(mime_globs, fmOpenRead) then
+      begin
+        // Load mapping: MIME type -> file extension.
+        globs:= TStringListEx.Create;
+        globs.NameValueSeparator:= ':';
+        globs.LoadFromFile(mime_globs);
+
+        // Try to load mapping: MIME type -> generic MIME icon name.
+        if mbFileExists(mime_generic_icons) then
+          begin
+            generic_icons:= TStringListEx.Create;
+            generic_icons.NameValueSeparator:= ':';
+            generic_icons.LoadFromFile(mime_generic_icons);
+          end;
+
+        EntriesCount := 0;
+        // Create mapping: file extension -> list of MIME icon names.
+        for I:= 0 to globs.Count - 1 do
+          if (globs.Strings[I]    <> '') and   // bypass empty lines
+             (globs.Strings[I][1] <> '#') then // and comments
+          begin
+            sMimeType := globs.Names[I];
+            sMimeIconName:= StringReplace(sMimeType, '/', '-', []);
+            sExtension:= ExtractFileExt(globs.ValueFromIndex[I]);
+
+            // Support only extensions, not full file name masks.
+            if (sExtension <> '') and (sExtension <> '.*') then
+            begin
+              Delete(sExtension, 1, 1);
+
+              node := THTDataNode(FExtToMimeIconName.Find(sExtension));
+              if not Assigned(node) then
+                begin
+                  iconsList := TStringList.Create;
+                  FExtToMimeIconName.Add(sExtension, iconsList);
+                  Inc(EntriesCount);
+                end
+              else
+                iconsList := TStringList(node.Data);
+
+              if iconsList.IndexOf(sMimeIconName) < 0 then
+                iconsList.Add(sMimeIconName);
+
+              // Shared-mime-info spec says:
+              // "If [generic-icon] is not specified then the mimetype is used to generate the
+              // generic icon by using the top-level media type (e.g. "video" in "video/ogg")
+              // and appending "-x-generic" (i.e. "video-x-generic" in the previous example)."
+              if Assigned(generic_icons) then
+                begin
+                  J := generic_icons.IndexOfName(sMimeType);
+                  if J <> -1 then
+                    sMimeIconName := generic_icons.ValueFromIndex[J] // found generic icon
+                  else
+                    sMimeIconName := Copy2Symb(sMimeIconName, '-') + '-x-generic';
+                end
+              else
+                sMimeIconName := Copy2Symb(sMimeIconName, '-') + '-x-generic';
+
+              if iconsList.IndexOf(sMimeIconName) < 0 then
+                iconsList.Add(sMimeIconName);
+            end;
+          end;
+
+        // save to cache
+        cache := TFileStreamEx.Create(gpIniDir + pixmaps_cache, fmCreate);
+        cache.WriteDWord(NtoBE(cache_signature));
+        cache.WriteDWord(cache_version);
+        cache.WriteDWord(EntriesCount);
+        for I := 0 to FExtToMimeIconName.HashTable.Count - 1 do
+          begin
+            nodeList := TFPObjectList(FExtToMimeIconName.HashTable.Items[I]);
+            if Assigned(nodeList) then
+              for J := 0 to nodeList.Count - 1 do
+                begin
+                  node := THtDataNode(nodeList.Items[J]);
+                  iconsList := TStringList(node.Data);
+                  cache.WriteAnsiString(node.Key);
+                  cache.WriteDWord(iconsList.Count);
+                  for K := 0 to iconsList.Count - 1 do
+                    cache.WriteAnsiString(iconsList.Strings[K]);
+                end;
+          end;
+        FreeAndNil(cache); // Close file
+        mbFileSetTime(gpIniDir + pixmaps_cache, mTime, 0, 0);
+      end;
+
+  finally
+    if Assigned(globs) then
+      FreeAndNil(globs);
+    if Assigned(generic_icons) then
+      FreeAndNil(generic_icons);
+    if Assigned(cache) then
+      FreeAndNil(cache);
+  end;
+end;
+
+function TPixMapManager.GetMimeIcon(AFileExt: String; AIconSize: Integer): PtrInt;
+var
+  I: Integer;
+  node: THTDataNode;
+  iconList: TStringList;
+begin
+  // This function is called under FPixmapsLock.
+
+  Result := -1;
+
+  // Search for an icon for this file extension.
+  node := THTDataNode(FExtToMimeIconName.Find(AFileExt));
+  if Assigned(node) then
+    begin
+      iconList := TStringList(node.Data);
+      // Try to load one of the icons in the list.
+      for I := 0 to iconList.Count - 1 do
+        begin
+          Result := LoadIconThemeIcon(iconList.Strings[I], AIconSize);
+          if Result <> -1 then break;
+        end;
+    end;
+end;
+
+function TPixMapManager.LoadIconThemeIcon(AIconName: String; AIconSize: Integer): PtrInt;
+var
+  fileIndex: PtrInt;
+{$IFDEF LCLGTK2}
+  pbPicture: PGdkPixbuf;
+  pgcIconName: Pgchar;
+{$ELSE}
+  sIconFileName: UTF8String;
+  bmpBitmap: Graphics.TBitmap;
+{$ENDIF}
+begin
+  // This function is called under FPixmapsLock.
+
+  fileIndex := FThemePixmapsFileNames.Find(AIconName);
+  if fileIndex < 0 then
+    begin
+{$IFDEF LCLGTK2}
+      pgcIconName:= Pgchar(AIconName);
+      pbPicture:= gtk_icon_theme_load_icon(FIconTheme, pgcIconName, AIconSize, GTK_ICON_LOOKUP_NO_SVG, nil);
+      if pbPicture <> nil then
+        begin
+          Result := FPixmapList.Add(pbPicture);
+          FThemePixmapsFileNames.Add(AIconName, Pointer(Result));
+        end
+      else
+        Result := -1;
+{$ELSE}
+      sIconFileName:= FIconTheme.FindIcon(AIconName, AIconSize);
+      if sIconFileName <> EmptyStr then
+        begin
+          bmpBitmap := CheckLoadPixmap(sIconFileName, False);
+          if Assigned(bmpBitmap) then
+            begin
+              Result := FPixmapList.Add(bmpBitmap); // add to list
+              FThemePixmapsFileNames.Add(AIconName, Pointer(Result));
+            end;
+        end
+      else
+        Result := -1;
+{$ENDIF}
+    end
+  else
+    Result := PtrInt(FThemePixmapsFileNames.List[fileIndex]^.Data);
+end;
+
+function TPixMapManager.GetIconByDesktopFile(sFileName: UTF8String; iDefaultIcon: PtrInt): PtrInt;
+var
+  I: PtrInt;
+  iniDesktop: TIniFileEx;
+  sIconName: UTF8String;
+begin
+  iniDesktop:= TIniFileEx.Create(sFileName, fmOpenRead);
+  try
+    sIconName:= iniDesktop.ReadString('Desktop Entry', 'Icon', EmptyStr);
+  finally
+    FreeThenNil(iniDesktop);
+  end;
+
+  I:= GetIconByName(sIconName);
+  if I < 0 then
+    Result:= iDefaultIcon
+  else
+    Result:= I;
+end;
+
+{$ENDIF} // Unix
+
+constructor TPixMapManager.Create;
+{$IFDEF MSWINDOWS}
+var
+  FileInfo : TSHFileInfoW;
+  iIconSize : Integer;
+{$ENDIF}
+begin
+  FExtList := TStringHashList.Create(True);
+  FPixmapsFileNames := TStringHashList.Create(True);
+  FPixmapList := TFPList.Create;
+  FDriveIconList := TStringList.Create;
+
+  {$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
+  FExtToMimeIconName := TFPDataHashTable.Create;
+  FThemePixmapsFileNames := TStringHashList.Create(True);
+  CreateIconTheme;
+  {$ENDIF}
+
+  {$IFDEF MSWINDOWS}
+  if gIconsSize = 16 then
+    iIconSize := SHGFI_SMALLICON
+  else
+    iIconSize := SHGFI_LARGEICON;
+
+  FSysImgList := SHGetFileInfoW(PWideChar(UTF8Decode(mbGetCurrentDir)),
+                                0,
+                                FileInfo,
+                                SizeOf(FileInfo),
+                                SHGFI_SYSICONINDEX or iIconSize);
+  {$ENDIF}
+
+  FPixmapsLock := syncobjs.TCriticalSection.Create;
+end;
+
+destructor TPixMapManager.Destroy;
+var
+  I : Integer;
+{$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
+  J : Integer;
+  nodeList: TFPObjectList;
+{$ENDIF}
+begin
+  if Assigned(FPixmapList) then
+  begin
+    for I := 0 to FPixmapList.Count - 1 do
+      if Assigned(FPixmapList.Items[I]) then
+  {$IFDEF LCLGTK2}
+        g_object_unref(PGdkPixbuf(FPixmapList.Items[I]));
+  {$ELSE}
+        Graphics.TBitmap(FPixmapList.Items[I]).Free;
+  {$ENDIF}
+    FreeAndNil(FPixmapList);
+  end;
+
+  if Assigned(FExtList) then
+    FreeAndNil(FExtList);
+  if Assigned(FPixmapsFileNames) then
+    FreeAndNil(FPixmapsFileNames);
+
+  if Assigned(FDriveIconList) then
+  begin
+    for I := 0 to FDriveIconList.Count - 1 do
+      with FDriveIconList.Objects[I] as TDriveIconList do
+      begin
+        if Assigned(bmMediaFloppy) then FreeAndNil(bmMediaFloppy);
+        if Assigned(bmDriveHardDisk) then FreeAndNil(bmDriveHardDisk);
+        if Assigned(bmMediaFlash) then FreeAndNil(bmMediaFlash);
+        if Assigned(bmMediaOptical) then FreeAndNil(bmMediaOptical);
+        if Assigned(bmDriveNetwork) then FreeAndNil(bmDriveNetwork);
+        Free;
+      end;
+    FreeAndNil(FDriveIconList);
+  end;
+
+  {$IF DEFINED(MSWINDOWS)}
+  ImageList_Destroy(FSysImgList);
+  {$ELSEIF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
+  DestroyIconTheme;
+
+  for I := 0 to FExtToMimeIconName.HashTable.Count - 1 do
+    begin
+      nodeList := TFPObjectList(FExtToMimeIconName.HashTable.Items[I]);
+      if Assigned(nodeList) then
+        for J := 0 to nodeList.Count - 1 do
+          TStringList(THtDataNode(nodeList.Items[J]).Data).Free;
+    end;
+
+  FreeThenNil(FExtToMimeIconName);
+  FreeThenNil(FThemePixmapsFileNames);
+  {$ENDIF}
+
+  FreeThenNil(FPixmapsLock);
+
+  inherited Destroy;
+end;
+
+procedure TPixMapManager.Load(const sFileName: String);
+var
+  slPixmapList: TStringList;
+  s:String;
+  sExt, sPixMap:String;
+  iekv:integer;
+  iPixMap:PtrInt;
+  sPixMapSize : String;
+  I : Integer;
+  Plugins : TStringList;
+  sCurrentPlugin : String;
+  iCurPlugCaps : Integer;
+begin
+  // This function doesn't need to be synchronized
+  // as long as it is called before creating the main form
+  // (via LoadPixMapManager in doublecmd.lpr).
+
+  //  load all drive icons
+  FDriveIconList.AddObject('16x16', TDriveIconList.Create);
+  FDriveIconList.AddObject('22x22', TDriveIconList.Create);
+  FDriveIconList.AddObject('32x32', TDriveIconList.Create);
+
+  sPixMapSize := FPixmapSize;  // save icon size path
+  for I:= 0 to FDriveIconList.Count - 1 do
+    with FDriveIconList.Objects[I] as TDriveIconList do
+    begin
+      FPixmapSize := FDriveIconList.Strings[I] + PathDelim;
+      bmMediaFloppy := CheckLoadPixmap('devices' + PathDelim + 'media-floppy.png');
+      bmDriveHardDisk := CheckLoadPixmap('devices' + PathDelim + 'drive-harddisk.png');
+      bmMediaFlash := CheckLoadPixmap('devices' + PathDelim + 'media-flash.png');
+      bmMediaOptical := CheckLoadPixmap('devices' + PathDelim + 'media-optical.png');
+      bmDriveNetwork:= CheckLoadPixmap('devices' + PathDelim + 'network-wired.png');
+    end;
+  // load emblems
+  if gIconsSize = 22 then
+    I:= 16
+  else
+    I:= gIconsSize div 2;
+  FPixmapSize := IntToStr(I) + 'x' + IntToStr(I) + PathDelim;
+  FiEmblemLinkID:= CheckAddPixmap('emblems' + PathDelim + 'emblem-symbolic-link.png', gIconsSize div 2);
+  FPixmapSize := sPixMapSize;  // restore icon size path
+
+  // add some standard icons
+  FiDefaultIconID:=CheckAddPixmap('mimetypes' + PathDelim + 'unknown.png');
+  FiDirIconID:=CheckAddPixmap('filesystems' + PathDelim + 'folder.png');
+  FiDirLinkIconID:=CheckAddPixmap('filesystems' + PathDelim + 'folder-link.png');
+  FiLinkIconID:=CheckAddPixmap('filesystems' + PathDelim + 'link.png');
+  FiUpDirIconID:=CheckAddPixmap('actions' + PathDelim + 'go-up.png');
+  FiArcIconID := CheckAddPixmap('mimetypes' + PathDelim + 'package-x-generic.png');
+  FiExeIconID:= CheckAddPixmap('mimetypes' + PathDelim + 'application-x-executable.png');
+  FiSortAscID := CheckAddPixmap('actions' + PathDelim + 'view-sort-ascending.png');
+  FiSortDescID := CheckAddPixmap('actions' + PathDelim + 'view-sort-descending.png');
+
+  { Load icons from doublecmd.ext }
+  for I := 0 to gExts.Count - 1 do
+    begin
+      gExts.Items[I].IconIndex:= FiDefaultIconID;
+      sPixMap := gExts.Items[I].Icon;
+      if mbFileExists(sPixMap) then
+        begin
+          iPixMap:= CheckAddPixmap(sPixMap, gIconsSize, False);
+          if iPixMap < 0 then Continue;
+          gExts.Items[I].IconIndex:= iPixMap;
+          //DebugLn('sPixMap = ',sPixMap, ' Index = ', IntToStr(iPixMap));
+
+          // set pixmap index for all extensions
+          for iekv := 0 to gExts.Items[I].Extensions.Count - 1 do
+            begin
+              sExt := gExts.Items[I].Extensions[iekv];
+              if FExtList.Find(sExt) < 0 then
+                FExtList.Add(sExt, TObject(iPixMap));
+            end;
+        end;
+    end;
+  {/ Load icons from doublecmd.ext }  
+  
+  if mbFileExists(sFileName) then
+  begin
+    slPixmapList:= TStringList.Create;
+    slPixmapList.LoadFromFile(sFileName);
+    try
+      for I:= 0 to slPixmapList.Count - 1 do
+      begin
+        s:= slPixmapList.Strings[I];
+        s:=Trim(lowercase(s));
+        iekv:=Pos('=',s);
+        if iekv=0 then
+          Continue;
+        sExt:=Copy(s,1, iekv-1);
+        sPixMap:=Copy(s, iekv+1, length(s)-iekv);
+        iPixMap:=CheckAddPixmap('mimetypes' + PathDelim + sPixMap);
+        if iPixMap<0 then
+          Continue;
+
+        if FExtList.Find(sExt)<0 then
+          FExtList.Add(sExt, TObject(iPixMap));
+      end;
+    finally
+      slPixmapList.Free;
+    end;
+  end;
+
+  (* Set archive icons *)
+  
+  Plugins := TStringList.Create;
+  gIni.ReadSectionRaw('PackerPlugins', Plugins);
+  
+  for I:=0 to Plugins.Count - 1 do
+        begin
+          sCurrentPlugin := Plugins.ValueFromIndex[I];
+          sExt := Plugins.Names[I];
+          if (Length(sExt) > 0) and (sExt[1] <> '#') then // if plugin not disabled
+            begin
+          iCurPlugCaps := StrToInt(Copy(sCurrentPlugin, 1, Pos(',',sCurrentPlugin) - 1));
+          if (iCurPlugCaps and PK_CAPS_HIDE) <> PK_CAPS_HIDE then
+            begin
+                if FExtList.Find(sExt) < 0 then
+                  FExtList.Add(sExt, TObject(FiArcIconID));
+            end;
+            end;
+        end; //for
+  Plugins.Free;
+  
+  (* /Set archive icons *)
+
+  {$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
+  if (gShowIcons <> sim_none) and (gShowIcons <> sim_standart) then
+    begin
+      LoadMimeIconNames;
+      {$IFNDEF LCLGTK2}
+      FIconTheme.Load;
+      {$ENDIF}
+    end;
+  {$ENDIF}
+end;
+
+function TPixMapManager.GetBitmap(iIndex: PtrInt; BkColor : TColor): Graphics.TBitmap;
+var
+  PPixmap: Pointer;
+  PixmapFromList: Boolean = False;
+{$IFDEF MSWINDOWS}
+  hicn: HICON;
+  Icon: TIcon = nil;
+{$ENDIF}
+begin
+  FPixmapsLock.Acquire;
+  try
+    if (iIndex >= 0) and (iIndex < FPixmapList.Count) then
+    begin
+      PPixmap := FPixmapList[iIndex];
+      PixmapFromList := True;
+    end;
+  finally
+    FPixmapsLock.Release;
+  end;
+
+  if PixmapFromList then
+  begin
+{$IFDEF LCLGTK2}
+    Result:= PixBufToBitmap(PGdkPixbuf(PPixmap));
+{$ELSE}
+    // Make a new copy.
+    Result := Graphics.TBitmap.Create;
+    Result.Assign(Graphics.TBitmap(PPixmap));
+{$ENDIF}
+  end
+  else
+{$IFDEF MSWINDOWS}
+  if iIndex >= $1000 then
+    begin
+      Result:= nil;
+      hicn:= ImageList_GetIcon(FSysImgList, iIndex - $1000, ILD_NORMAL);
+      if hicn <> 0 then
+        try
+          Icon := CreateIconFromHandle(hicn);
+          Result := Graphics.TBitmap.Create;
+          Result.Assign(Icon);
+        finally
+          FreeThenNil(Icon);
+          DestroyIcon(hicn);
+        end
+    end;
+{$ELSE}
+  Result:= nil;
+{$ENDIF}
+end;
+
+function TPixMapManager.DrawBitmap(iIndex: PtrInt; Canvas : TCanvas; X, Y: Integer) : Boolean;
+begin
+  Result := DrawBitmap(iIndex, Canvas, X, Y, gIconsSize, gIconsSize); // X, Y, 0, 0 - No bitmap stretching.
+end;
+
+function TPixMapManager.DrawBitmap(iIndex: PtrInt; Canvas: TCanvas; X, Y, Width, Height: Integer): Boolean;
+
+  procedure TrySetSize(aWidth, aHeight: Integer);
+  begin
+    if Width = 0 then
+      Width := aWidth;
+    if Height = 0 then
+      Height := aHeight;
+  end;
+
+var
+  PPixmap: Pointer;
+  PixmapFromList: Boolean = False;
+{$IFDEF MSWINDOWS}
+  hicn: HICON;
+  cx, cy: Integer;
+{$ENDIF}
+{$IFDEF LCLGTK2}
+  pbPicture : PGdkPixbuf;
+  iPixbufWidth : Integer;
+  iPixbufHeight : Integer;
+{$ELSE}
+  Bitmap: Graphics.TBitmap;
+  aRect: TRect;
+{$ENDIF}
+begin
+  Result := True;
+
+  FPixmapsLock.Acquire;
+  try
+    if (iIndex >= 0) and (iIndex < FPixmapList.Count) then
+    begin
+      PPixmap := FPixmapList[iIndex];
+      PixmapFromList := True;
+    end;
+  finally
+    FPixmapsLock.Release;
+  end;
+
+  if PixmapFromList then
+  begin
+  {$IFDEF LCLGTK2}
+    pbPicture := PGdkPixbuf(PPixmap);
+    iPixbufWidth :=  gdk_pixbuf_get_width(pbPicture);
+    iPixbufHeight :=  gdk_pixbuf_get_height(pbPicture);
+    TrySetSize(iPixbufWidth, iPixbufHeight);
+    DrawPixbufAtCanvas(Canvas, pbPicture, 0, 0, X, Y, Width, Height);
+  {$ELSE}
+    Bitmap := Graphics.TBitmap(PPixmap);
+    TrySetSize(Bitmap.Width, Bitmap.Height);
+    aRect := Classes.Bounds(X, Y, Width, Height);
+    Canvas.StretchDraw(aRect, Bitmap);
+  {$ENDIF}
+  end
+  else
+  {$IFDEF MSWINDOWS}
+  if iIndex >= $1000 then
+    try
+      if ImageList_GetIconSize(FSysImgList, @cx, @cy) then
+        TrySetSize(cx, cy)
+      else
+        TrySetSize(gIconsSize, gIconsSize);
+
+      if (Height in [16, 32]) and (cx = Width) and (cy = Height) then
+        // for transparent
+        ImageList_Draw(FSysImgList, iIndex - $1000, Canvas.Handle, X, Y, ILD_TRANSPARENT)
+      else
+      begin
+        hicn:= ImageList_GetIcon(FSysImgList, iIndex - $1000, ILD_NORMAL);
+        try
+          if IsGdiPlusLoaded then
+            Result:= GdiPlusStretchDraw(hicn, Canvas.Handle, X, Y, Width, Height)
+          else
+            Result:= DrawIconEx(Canvas.Handle, X, Y, hicn, Width, Height, 0, 0, DI_NORMAL);
+        finally
+          DestroyIcon(hicn);
+        end;
+      end;
+    except
+      Result:= False;
+    end;
+
+  {$ELSE}
+    Result:= False;
+  {$ENDIF}
+end;
+
+function TPixMapManager.DrawBitmap(iIndex: PtrInt; AFile: TFile; DirectAccess: Boolean; Canvas: TCanvas; X, Y: Integer): Boolean;
+var
+  I: Integer;
+begin
+  Result:= DrawBitmap(iIndex, Canvas, X, Y);
+
+  if gIconOverlays then
+    begin
+    {$IFDEF MSWINDOWS}
+      if DirectAccess then
+      begin
+        I:= SHGetOverlayIconIndex(AFile.Path, AFile.Name);
+        if I >= 0 then
+          Result:= DrawBitmap(I + $1000, Canvas, X, Y);
+      end;
+    {$ELSE}
+      if AFile.IsLink then
+        begin
+          I:= gIconsSize div 2;
+          Result:= DrawBitmap(FiEmblemLinkID, Canvas, X, Y + I, I, I);
+        end;
+    {$ENDIF}
+    end;
+end;
+
+function TPixMapManager.GetIconBySortingDirection(SortingDirection: TSortDirection): PtrInt;
+begin
+  case SortingDirection of
+    sdDescending:
+      begin
+        Result := FiSortDescID;
+      end;
+    sdAscending:
+      begin
+        Result := FiSortAscID;
+      end;
+    else
+      Result := -1;
+  end;
+end;
+
+function TPixMapManager.GetIconByFile(AFile: TFile; DirectAccess: Boolean): PtrInt;
+var
+  Ext: String;
+{$IFDEF MSWINDOWS}
+  sFileName: String;
+  FileInfo: TSHFileInfoW;
+  dwFileAttributes: DWORD;
+  uFlags: UINT;
+{$ENDIF}
+begin
+  Result := -1;
+  if not Assigned(AFile) then Exit;
+
+  with AFile do
+  begin
+    if Name = '..' then
+    begin
+      Result := FiUpDirIconID;
+      Exit;
+    end;
+
+    if IsLinkToDirectory then
+    begin
+    {$IFDEF UNIX}
+      if gIconOverlays then
+        Result:= FiDirIconID
+      else
+    {$ENDIF}
+      Result := FiDirLinkIconID;
+      Exit;
+    end;
+
+    if IsDirectory then
+    begin
+      {$IF DEFINED(MSWINDOWS)}
+      if (gShowIcons = sim_standart) or
+         (not (DirectAccess and mbFileExists(Path + Name + '\desktop.ini'))) or
+         (GetDeviceCaps(Application.MainForm.Canvas.Handle, BITSPIXEL) < 16) then
+      {$ELSEIF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
+      if (gShowIcons = sim_all_and_exe) and
+         (DirectAccess and mbFileExists(Path + Name + '/.directory')) then
+        begin
+          Result:= GetIconByDesktopFile(Path + Name + '/.directory', FiDirIconID);
+          Exit;
+        end
+      else
+      {$ENDIF}
+        begin
+          Exit(FiDirIconID);
+        end;
+    end
+    else // not directory
+    begin
+      if IsLink and not gIconOverlays then
+        Exit(FiLinkIconID);
+
+      if (Extension = '') then
+        Exit(FiDefaultIconID);
+
+      Ext := UTF8LowerCase(Extension);
+
+      {$IF DEFINED(MSWINDOWS)}
+      if gShowIcons <> sim_all_and_exe then
+        begin
+          if Ext = 'exe' then
+            Exit(FiExeIconID)
+          else if Ext = 'lnk' then
+            Exit(FiLinkIconID)
+          else if Ext = 'ico' then
+            Exit(FiDefaultIconID)
+        end;
+      {$ELSEIF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
+      if gShowIcons = sim_all_and_exe then
+        begin
+          if DirectAccess and (Ext = 'desktop') then
+            begin
+              Result:= GetIconByDesktopFile(Path + Name, FiDefaultIconID);
+              Exit;
+            end;
+        end;
+      {$ENDIF}
+
+      FPixmapsLock.Acquire;
+      try
+        Result := FExtList.Find(Ext);
+        if Result >= 0 then
+          Exit(PtrInt(FExtList.List[Result]^.Data));
+
+        if gShowIcons = sim_standart then
+          Exit(FiDefaultIconID);
+
+        {$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
+
+        Result := GetMimeIcon(Ext, gIconsSize);
+        if Result < 0 then
+          Result := FiDefaultIconID;
+
+        // Default icon should also be associated with the extension
+        // because it will be faster to find next time.
+        FExtList.Add(Ext, Pointer(Result));
+
+        {$ENDIF}
+
+      finally
+        FPixmapsLock.Release;
+      end;
+    end;
+
+    {$IF DEFINED(MSWINDOWS)}
+
+    if DirectAccess then
+      begin
+        dwFileAttributes := 0;
+        uFlags := SHGFI_SYSICONINDEX;
+        sFileName := Path + Name;
+      end
+    else
+      begin
+        dwFileAttributes := FILE_ATTRIBUTE_NORMAL;
+        uFlags := SHGFI_SYSICONINDEX or SHGFI_USEFILEATTRIBUTES;
+        sFileName := Name;
+      end;
+
+    if gIconsSize = 16 then
+      uFlags := uFlags or SHGFI_SMALLICON
+    else
+      uFlags := uFlags or SHGFI_LARGEICON;
+
+    if (SHGetFileInfoW(PWideChar(UTF8Decode(sFileName)),
+                       dwFileAttributes,
+                       FileInfo,
+                       SizeOf(FileInfo),
+                       uFlags) = 0) then
+    begin
+      // Could not retrieve icon.
+      if IsDirectory then
+        Result := FiDirIconID
+      else
+        Result := FiDefaultIconID;
+    end
+    else
+    begin
+      Result := FileInfo.iIcon + $1000;
+
+      if (not IsDirectory) and
+         (Ext <> 'exe') and
+         (Ext <> 'ico') and
+         (Ext <> 'lnk') then
+      begin
+        FPixmapsLock.Acquire;
+        try
+          FExtList.Add(Ext, Pointer(Result));
+        finally
+          FPixmapsLock.Release;
+        end;
+      end;
+    end;
+
+    {$ENDIF}
+  end;
+end;
+
+function TPixMapManager.GetIconByName(const AIconName: UTF8String): PtrInt;
+begin
+  Result := CheckAddPixmap(AIconName, gIconsSize, False);
+end;
+
+function TPixMapManager.GetDriveIcon(Drive : PDrive; IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
+{$IFDEF MSWINDOWS}
+var
+  SFI: TSHFileInfoW;
+  Icon: TIcon = nil;
+  uFlags: UINT;
+  iIconSmall,
+  iIconLarge: Integer;
+{$ENDIF}
+begin
+  Result := nil;
+{$IFDEF MSWINDOWS}
+  if GetDeviceCaps(Application.MainForm.Canvas.Handle, BITSPIXEL) < 15 then Exit;
+  if (not gCustomDriveIcons) and (GetDeviceCaps(Application.MainForm.Canvas.Handle, BITSPIXEL) > 16) then
+    begin
+      SFI.hIcon := 0;
+      Result := Graphics.TBitMap.Create;
+      iIconSmall:= GetSystemMetrics(SM_CXSMICON);
+      iIconLarge:= GetSystemMetrics(SM_CXICON);
+
+      if (IconSize = 16) and (iIconSmall = 16) then // standart small icon
+        uFlags := SHGFI_SMALLICON // Use small icon
+      else if (IconSize = 32) and (iIconLarge = 32) then // standart large icon
+        uFlags := SHGFI_LARGEICON // Use large icon
+      else if IconSize > iIconSmall then
+        uFlags := SHGFI_LARGEICON // Use large icon
+      else
+        uFlags := SHGFI_SMALLICON; // Use small icon
+
+      if (SHGetFileInfoW(PWideChar(UTF8Decode(Drive^.Path)), 0, SFI,
+                         SizeOf(SFI), uFlags or SHGFI_ICON) <> 0) and
+         (SFI.hIcon <> 0) then
+        begin
+          if (IconSize = iIconSmall) or (IconSize = iIconLarge) then // standart icon size
+            try
+              Icon := CreateIconFromHandle(SFI.hIcon);
+              Result.Assign(Icon);
+            finally
+              FreeThenNil(Icon);
+              DestroyIcon(SFI.hIcon);
+            end
+          else // non standart icon size
+            try
+              Icon := CreateIconFromHandle(SFI.hIcon);
+              Result.Assign(Icon);
+              Result := StretchBitmap(Result, IconSize, clBackColor, True);
+            finally
+              FreeThenNil(Icon);
+              DestroyIcon(SFI.hIcon);
+            end
+        end;
+    end // not gCustomDriveIcons
+  else
+{$ENDIF}
+    begin
+      Result := GetBuiltInDriveIcon(Drive, IconSize, clBackColor);
+    end;
+end;
+
+function TPixMapManager.GetBuiltInDriveIcon(Drive : PDrive; IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
+var
+  DriveIconListIndex: Integer;
+  Bitmap: Graphics.TBitmap;
+begin
+{$IFDEF MSWINDOWS}
+  if GetDeviceCaps(Application.MainForm.Canvas.Handle, BITSPIXEL) < 15 then Exit(nil);
+{$ENDIF}
+  case IconSize of
+  16: // Standart 16x16 icon size
+    DriveIconListIndex := 0;
+  22:  // Standart 22x22 icon size
+    DriveIconListIndex := 1;
+  32:  // Standart 32x32 icon size
+    DriveIconListIndex := 2;
+  else  // for non standart icon size use more large icon for stretch
+    DriveIconListIndex := 2;
+  end;
+  with FDriveIconList.Objects[DriveIconListIndex] as TDriveIconList do
+  case Drive^.DriveType of
+  dtFloppy:
+    Bitmap := bmMediaFloppy;
+  dtFixed:
+    Bitmap := bmDriveHardDisk;
+  dtFlash:
+    Bitmap := bmMediaFlash;
+  dtCDROM:
+    Bitmap := bmMediaOptical;
+  dtNetwork:
+    Bitmap := bmDriveNetwork;
+  else
+    Bitmap := bmDriveHardDisk;
+  end;
+  //  if need stretch icon
+  if (IconSize <> 16) and (IconSize <> 22) and (IconSize <> 32) then
+    begin
+      Result := StretchBitmap(Bitmap, IconSize, clBackColor, False);
+    end
+  else
+    begin
+      Result := Graphics.TBitmap.Create;
+      Result.Assign(Bitmap);
+    end;
+  // 'Bitmap' should not be freed, because it only points to DriveIconList.
+end;
+
+function TPixMapManager.GetDefaultDriveIcon(IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap;
+var
+  Drive: TDrive = (Name: ''; Path: ''; DriveLabel: ''; DriveType: dtFixed);
+begin
+  Result := GetBuiltInDriveIcon(@Drive, IconSize, clBackColor);
+end;
+
+function TPixMapManager.GetArchiveIcon(IconSize: Integer; clBackColor : TColor) : Graphics.TBitmap;
+begin
+  Result := GetBitmap(FiArcIconID, clBackColor);
+  if Assigned(Result) then
+  begin
+    //  if need stretch icon
+    if (IconSize <> gIconsSize) then
+      begin
+        Result := StretchBitmap(Result, IconSize, clBackColor, True);
+      end;
+  end;
+end;
+
+procedure LoadPixMapManager;
+begin
+  PixMapManager:=TPixMapManager.Create;
+  PixMapManager.FPixmapSize:= IntToStr(gIconsSize) + 'x' + IntToStr(gIconsSize) + PathDelim;
+  PixMapManager.Load(gpIniDir+'pixmaps.txt');
+end;
+
+initialization
+
+finalization
+
+  if Assigned(PixMapManager) then
+    FreeAndNil(PixMapManager);
+
+end.
+