winemenubuilder: Write truecolor icons as PNGs

Frank Richter frank.richter at gmail.com
Wed Dec 6 08:56:24 CST 2006


When libpng is available, support for writing out 24 and 32bpp icons is
added, which are written out as PNGs. Also changed wineshelllink to
support both xpm and png extensions for icons.

Some parts based on an older patch by Vitaliy Margolen.

-------------- next part --------------
>From e3644b14f8f200500356c194887a2834f1b37283 Mon Sep 17 00:00:00 2001
From: frank.richter at gmail.com <frank.richter at gmail.com>
Date: Wed, 6 Dec 2006 15:40:56 +0100
Subject: [PATCH] winemenubuilder: Write truecolor icons as PNGs

---
 configure.ac                               |   20 +
 include/config.h.in                        |    9 -
 programs/winemenubuilder/Makefile.in       |    3 
 programs/winemenubuilder/winemenubuilder.c |  383 +++++++++++++++++++++-------
 tools/wineshelllink                        |   16 +
 5 files changed, 330 insertions(+), 101 deletions(-)

diff --git a/configure.ac b/configure.ac
index 04f75fc..f4c01d1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -722,6 +722,26 @@ then
   AC_SUBST(FONTSSUBDIRS,"fonts")
 fi
 
+dnl **** Check for libpng ****
+
+AC_SUBST(PNGLIBS,"")
+AC_SUBST(PNGINCL,"")
+if test "$PKG_CONFIG" != "false"
+then
+    ac_save_CPPFLAGS="$CPPFLAGS"
+    ac_png_libs="`$PKG_CONFIG --libs libpng 2>/dev/null`"
+    ac_png_cflags="`$PKG_CONFIG --cflags libpng 2>/dev/null`"
+    CPPFLAGS="$CPPFLAGS $ac_xml_cflags"
+    AC_CHECK_HEADERS(png.h,
+        [AC_CHECK_LIB(png,  png_create_read_struct,
+            [AC_DEFINE(HAVE_LIBPNG, 1, [Define if you have the libpng library])
+             PNGLIBS="$ac_png_libs"
+             PNGINCL="$ac_png_cflags"],,$ac_png_libs)
+        ])
+    CPPFLAGS="$ac_save_CPPFLAGS"
+fi
+
+
 dnl **** Check for parport (currently Linux only) ****
 AC_CACHE_CHECK([for parport header/ppdev.h], ac_cv_c_ppdev,
  AC_TRY_COMPILE(
diff --git a/programs/winemenubuilder/Makefile.in b/programs/winemenubuilder/Makefile.in
index 8eeca86..1898a68 100644
--- a/programs/winemenubuilder/Makefile.in
+++ b/programs/winemenubuilder/Makefile.in
@@ -5,7 +5,8 @@ VPATH     = @srcdir@
 MODULE    = winemenubuilder.exe
 APPMODE   = -mwindows
 IMPORTS   = shell32 ole32 user32 advapi32 kernel32
-EXTRALIBS = -luuid
+EXTRALIBS = -luuid @PNGLIBS@
+EXTRAINCL = @PNGINCL@
 
 C_SRCS = \
 	winemenubuilder.c
diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c
index 078365c..5cebc75 100644
--- a/programs/winemenubuilder/winemenubuilder.c
+++ b/programs/winemenubuilder/winemenubuilder.c
@@ -64,6 +64,9 @@ #include <unistd.h>
 #endif
 #include <errno.h>
 #include <stdarg.h>
+#ifdef HAVE_PNG_H
+#include <png.h>
+#endif
 
 #define COBJMACROS
 
@@ -143,6 +146,126 @@ typedef struct
  * FIXME: should not use stdio
  */
 
+static inline BOOL MaskPixelSet (const BYTE* pAND, int col)
+{
+    if (!pAND) return FALSE;
+    
+    return (pAND[col / 8] & (1 << (7 - col % 8)));
+}
+
+
+#ifdef HAVE_PNG_H
+static BOOL SaveIconResAsPNG(const BITMAPINFO *pIcon, const char *szPNGFileName)
+{
+    FILE *fPNGFile;
+    png_structp png_ptr;
+    png_infop info_ptr;
+    int nXORWidthBytes, nANDWidthBytes, i, j;
+    BYTE *pXOR, *row, *newXOR = NULL;
+    const BYTE *pAND = NULL;
+    int nWidth  = pIcon->bmiHeader.biWidth;
+    int nHeight = pIcon->bmiHeader.biHeight;
+    int nBpp    = pIcon->bmiHeader.biBitCount;
+
+    WINE_TRACE("(%s)\n", szPNGFileName);
+
+    if (!(fPNGFile = fopen(szPNGFileName, "w")))
+    {
+        WINE_ERR("unable to open '%s' for writing: %s\n", szPNGFileName, strerror(errno));
+        return FALSE;
+    }
+    
+    nXORWidthBytes = 4 * ((nWidth * nBpp + 31) / 32);
+    nANDWidthBytes = 4 * ((nWidth + 31 ) / 32);
+    pXOR = (BYTE*) pIcon + sizeof(BITMAPINFOHEADER) + pIcon->bmiHeader.biClrUsed * sizeof(RGBQUAD);
+    if (nHeight > nWidth)
+    {
+        nHeight /= 2;
+        pAND = pXOR + nHeight * nXORWidthBytes;
+    }
+
+    if (nBpp < 24) 
+    {
+        WINE_ERR("Can only write icons with >=24bpp to PNGs.\n");
+        return FALSE;
+    }
+
+    /* Fill alpha channel from mask */
+    if (nBpp < 32)
+    {
+        const BYTE* andRow = pAND;
+        BYTE* newRow;
+        
+        newXOR = HeapAlloc (GetProcessHeap(), 0, nWidth * nHeight * 4);
+        newRow = newXOR;
+    
+        row = pXOR;
+        /* top left corner */
+        for (i = 0; i < nHeight; i++)
+        {
+            BYTE* rowPos = row;
+            BYTE* newRowPos = newRow;
+            
+            for (j = 0; j < nWidth; j++)
+            {
+                *newRowPos++ = *rowPos++;
+                *newRowPos++ = *rowPos++;
+                *newRowPos++ = *rowPos++;
+                *newRowPos++ = MaskPixelSet (andRow, j) ? 0 : 0xff;
+            }
+            row += nXORWidthBytes;
+            newRow += nWidth * 4;
+            if (andRow != NULL) andRow += nANDWidthBytes;
+        }
+        
+        pXOR = newXOR;
+        nXORWidthBytes = nWidth * 4;
+    }
+
+    if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) ||
+        !(info_ptr = png_create_info_struct(png_ptr)))
+        goto error;
+
+    if (setjmp(png_jmpbuf(png_ptr)))
+    {
+        /* All future errors jump here */
+        WINE_ERR("png error\n");
+        goto error;
+    }
+
+    png_init_io(png_ptr, fPNGFile);
+    png_set_IHDR(png_ptr, info_ptr, nWidth, nHeight, 8,
+                 PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA,
+                 PNG_INTERLACE_NONE,
+                 PNG_COMPRESSION_TYPE_DEFAULT,
+                 PNG_FILTER_TYPE_DEFAULT);
+
+    png_write_info(png_ptr, info_ptr);
+    png_set_bgr(png_ptr);
+    for (i = nHeight - 1; i >= 0 ; i--)
+        png_write_row(png_ptr, (png_bytep)pXOR + nXORWidthBytes * i);
+    png_write_end(png_ptr, info_ptr);
+
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+    if (png_ptr) png_destroy_write_struct(&png_ptr, NULL);
+    HeapFree (GetProcessHeap(), 0, newXOR);
+    fclose(fPNGFile);
+    return TRUE;
+
+ error:
+    if (png_ptr) png_destroy_write_struct(&png_ptr, NULL);
+    HeapFree (GetProcessHeap(), 0, newXOR);
+    fclose(fPNGFile);
+    unlink(szPNGFileName);
+    return FALSE;
+}
+#else
+static BOOL SaveIconResAsPNG(const BITMAPINFO *pIcon, const char *szPNGFileName)
+{
+    return TRUE;
+}
+#endif
+
 static BOOL SaveIconResAsXPM(const BITMAPINFO *pIcon, const char *szXPMFileName, LPCWSTR commentW)
 {
     FILE *fXPMFile;
@@ -158,6 +281,8 @@ static BOOL SaveIconResAsXPM(const BITMA
     int i,j;
     char *comment;
 
+    WINE_TRACE("(%s, %s)\n", szXPMFileName, wine_dbgstr_w (commentW));
+
     if (!((pIcon->bmiHeader.biBitCount == 4) || (pIcon->bmiHeader.biBitCount == 8)))
     {
         WINE_FIXME("Unsupported color depth %d-bit\n", pIcon->bmiHeader.biBitCount);
@@ -261,7 +386,16 @@ static BOOL CALLBACK EnumResNameProc(HMO
         return TRUE;
 }
 
-static BOOL extract_icon32(LPCWSTR szFileName, int nIndex, const char *szXPMFileName)
+static BOOL icon_depth_supported (int depth)
+{
+    return (depth <= 8)
+#ifdef HAVE_PNG_H
+        || (depth >= 24)
+#endif
+        ;
+}
+
+static BOOL extract_icon32(LPCWSTR szFileName, int nIndex, const char *szXPMFileName, const char *szPNGFileName)
 {
     HMODULE hModule;
     HRSRC hResInfo;
@@ -309,7 +443,8 @@ static BOOL extract_icon32(LPCWSTR szFil
             {
                 for (i = 0; i < pIconDir->idCount; i++)
                 {
-		    if ((pIconDir->idEntries[i].wBitCount >= nMaxBits) && (pIconDir->idEntries[i].wBitCount <= 8))
+		    if (icon_depth_supported (pIconDir->idEntries[i].wBitCount)
+		        && (pIconDir->idEntries[i].wBitCount >= nMaxBits))
 		    {
 			nMaxBits = pIconDir->idEntries[i].wBitCount;
 
@@ -318,8 +453,8 @@ static BOOL extract_icon32(LPCWSTR szFil
 			    lpName = MAKEINTRESOURCEW(pIconDir->idEntries[i].nID);
 			    nMax = pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth;
 			}
-		    }		    
-                }
+		    }
+		}
             }
 
             FreeResource(hResData);
@@ -338,8 +473,10 @@ static BOOL extract_icon32(LPCWSTR szFil
         {
             if ((pIcon = LockResource(hResData)))
             {
-                if(SaveIconResAsXPM(pIcon, szXPMFileName, szFileName))
-                    ret = TRUE;
+                if (nMaxBits >= 24)
+                    ret = SaveIconResAsPNG(pIcon, szPNGFileName);
+		else
+		    ret = SaveIconResAsXPM(pIcon, szXPMFileName, szFileName);
             }
 
             FreeResource(hResData);
@@ -350,24 +487,38 @@ static BOOL extract_icon32(LPCWSTR szFil
     return ret;
 }
 
-static BOOL ExtractFromEXEDLL(LPCWSTR szFileName, int nIndex, const char *szXPMFileName)
+static char* build_filename (const char* dir, const char* base, const char* ext)
 {
-    if (!extract_icon32(szFileName, nIndex, szXPMFileName) /*&&
-        !extract_icon16(szFileName, szXPMFileName)*/)
-        return FALSE;
-    return TRUE;
+    char* str = HeapAlloc (GetProcessHeap(), 0, strlen (dir)+1+strlen (base)+strlen (ext)+1);
+    sprintf (str, "%s/%s%s", dir, base, ext);
+    return str;
 }
 
-static int ExtractFromICO(LPCWSTR szFileName, const char *szXPMFileName)
+static BOOL ExtractFromEXEDLL(LPCWSTR szFileName, int nIndex, const char *szIcoPath, const char *szIcoBaseName)
+{
+    BOOL ret = FALSE;
+
+    char* xpm_path = build_filename (szIcoPath, szIcoBaseName, ".xpm");
+    char* png_path = build_filename (szIcoPath, szIcoBaseName, ".png");
+    
+    ret = (extract_icon32(szFileName, nIndex, xpm_path, png_path) /*||
+        extract_icon16(szFileName, xpm_path)*/);
+        
+    HeapFree (GetProcessHeap(), 0, xpm_path);
+    HeapFree (GetProcessHeap(), 0, png_path);
+    return ret;
+}
+
+static int ExtractFromICO(LPCWSTR szFileName, const char *szIcoPath, const char *szIcoBaseName)
 {
     FILE *fICOFile;
     ICONDIR iconDir;
     ICONDIRENTRY *pIconDirEntry;
     int nMax = 0, nMaxBits = 0;
-    int nIndex = 0;
-    void *pIcon;
+    int nIndex = -1;
+    void *pIcon = NULL;
     int i;
-    char *filename;
+    char *filename, *xpm_path, *png_path;
 
     filename = wine_get_unix_file_name(szFileName);
     if (!(fICOFile = fopen(filename, "r")))
@@ -389,29 +540,54 @@ static int ExtractFromICO(LPCWSTR szFile
         goto error3;
 
     for (i = 0; i < iconDir.idCount; i++)
-        if (pIconDirEntry[i].wBitCount <= 8 && pIconDirEntry[i].wBitCount >= nMaxBits &&
-            (pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth) >= nMax)
-        {
-            nIndex = i;
-            nMax = pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth;
-            nMaxBits = pIconDirEntry[i].wBitCount;
-        }
-    if ((pIcon = HeapAlloc(GetProcessHeap(), 0, pIconDirEntry[nIndex].dwBytesInRes)) == NULL)
-        goto error3;
-    if (fseek(fICOFile, pIconDirEntry[nIndex].dwImageOffset, SEEK_SET))
-        goto error4;
-    if (fread(pIcon, pIconDirEntry[nIndex].dwBytesInRes, 1, fICOFile) != 1)
-        goto error4;
-
-    if(!SaveIconResAsXPM(pIcon, szXPMFileName, szFileName))
-        goto error4;
+    {
+	if (icon_depth_supported (pIconDirEntry[i].wBitCount) &&
+	    pIconDirEntry[i].wBitCount >= nMaxBits &&
+	    (pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth) >= nMax)
+	{
+	    nIndex = i;
+	    nMax = pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth;
+	    nMaxBits = pIconDirEntry[i].wBitCount;
+	}
+    }
+    if (nIndex >= 0)
+    {
+        if ((pIcon = HeapAlloc(GetProcessHeap(), 0, pIconDirEntry[nIndex].dwBytesInRes)) == NULL)
+            goto error3;
+        if (fseek(fICOFile, pIconDirEntry[nIndex].dwImageOffset, SEEK_SET))
+            goto error4;
+        if (fread(pIcon, pIconDirEntry[nIndex].dwBytesInRes, 1, fICOFile) != 1)
+            goto error4;
+    }
 
+    xpm_path = build_filename (szIcoPath, szIcoBaseName, ".xpm");
+    png_path = build_filename (szIcoPath, szIcoBaseName, ".png");
+    
+    if (pIcon != NULL)
+    {
+        if (nMaxBits >= 24)
+        {
+	    if(!SaveIconResAsPNG(pIcon, png_path))
+		goto error5;
+	}
+	else
+	{
+	    if(!SaveIconResAsXPM(pIcon, xpm_path, szFileName))
+		goto error5;
+	}
+    }
+    
+    HeapFree(GetProcessHeap(), 0, png_path);
+    HeapFree(GetProcessHeap(), 0, xpm_path);
     HeapFree(GetProcessHeap(), 0, pIcon);
     HeapFree(GetProcessHeap(), 0, pIconDirEntry);
     fclose(fICOFile);
     HeapFree(GetProcessHeap(), 0, filename);
     return 1;
 
+ error5:
+    HeapFree(GetProcessHeap(), 0, xpm_path);
+    HeapFree(GetProcessHeap(), 0, png_path);
  error4:
     HeapFree(GetProcessHeap(), 0, pIcon);
  error3:
@@ -466,57 +642,20 @@ static unsigned short crc16(const char* 
 }
 
 /* extract an icon from an exe or icon file; helper for IPersistFile_fnSave */
-static char *extract_icon( LPCWSTR path, int index)
+static char *extract_icon( char* iconsdir, LPCWSTR path, int index)
 {
     int nodefault = 1;
     unsigned short crc;
-    char *iconsdir, *ico_path, *ico_name, *xpm_path;
+    char *ico_path, *ico_name, *base_name;
     char* s;
-    HKEY hkey;
     int n;
 
     /* Where should we save the icon? */
     WINE_TRACE("path=[%s] index=%d\n", wine_dbgstr_w(path), index);
-    iconsdir=NULL;  /* Default is no icon */
-    /* @@ Wine registry key: HKCU\Software\Wine\WineMenuBuilder */
-    if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\WineMenuBuilder", &hkey ))
-    {
-        static const WCHAR IconsDirW[] = {'I','c','o','n','s','D','i','r',0};
-        LPWSTR iconsdirW;
-        DWORD size = 0;
-
-        if (!RegQueryValueExW(hkey, IconsDirW, 0, NULL, NULL, &size))
-        {
-            iconsdirW = HeapAlloc(GetProcessHeap(), 0, size);
-            RegQueryValueExW(hkey, IconsDirW, 0, NULL, (LPBYTE)iconsdirW, &size);
-
-            if (!(iconsdir = wine_get_unix_file_name(iconsdirW)))
-            {
-                int n = WideCharToMultiByte(CP_UNIXCP, 0, iconsdirW, -1, NULL, 0, NULL, NULL);
-                iconsdir = HeapAlloc(GetProcessHeap(), 0, n);
-                WideCharToMultiByte(CP_UNIXCP, 0, iconsdirW, -1, iconsdir, n, NULL, NULL);
-            }
-            HeapFree(GetProcessHeap(), 0, iconsdirW);
-        }
-        RegCloseKey( hkey );
-    }
-
-    if (!iconsdir)
-    {
-        WCHAR path[MAX_PATH];
-        if (GetTempPathW(MAX_PATH, path))
-            iconsdir = wine_get_unix_file_name(path);
-        if (!iconsdir)
-        {
-            WINE_TRACE("no IconsDir\n");
-            return NULL;  /* No icon created */
-        }
-    }
     
     if (!*iconsdir)
     {
         WINE_TRACE("icon generation disabled\n");
-        HeapFree(GetProcessHeap(), 0, iconsdir);
         return NULL;  /* No icon created */
     }
 
@@ -547,28 +686,35 @@ static char *extract_icon( LPCWSTR path,
 
     /* Compute the source-path hash */
     crc=crc16(ico_path);
+    
+    base_name = HeapAlloc (GetProcessHeap(), 0, 5+4+1+strlen (ico_name)+1+12+1);
+    sprintf(base_name, "wine-%04x_%s.%d", crc, ico_name, index);
 
     /* Try to treat the source file as an exe */
-    xpm_path=HeapAlloc(GetProcessHeap(), 0, strlen(iconsdir)+1+4+1+strlen(ico_name)+1+12+1+3);
-    sprintf(xpm_path,"%s/%04x_%s.%d.xpm",iconsdir,crc,ico_name,index);
-    if (ExtractFromEXEDLL( path, index, xpm_path ))
+    if (ExtractFromEXEDLL( path, index, iconsdir, base_name ))
         goto end;
 
     /* Must be something else, ignore the index in that case */
-    sprintf(xpm_path,"%s/%04x_%s.xpm",iconsdir,crc,ico_name);
-    if (ExtractFromICO( path, xpm_path))
+    sprintf(base_name, "wine-%04x_%s", crc, ico_name);
+    if (ExtractFromICO( path, iconsdir, base_name ))
         goto end;
     if (!nodefault)
-        if (create_default_icon( xpm_path, ico_path ))
-            goto end;
+    {
+        char* xpm_path = build_filename (iconsdir, base_name, ".xpm");
+        BOOL result;
+        
+        result = create_default_icon( xpm_path, ico_path );
+        
+        HeapFree (GetProcessHeap(), 0, xpm_path);
+	if (result) goto end;
+    }
 
-    HeapFree( GetProcessHeap(), 0, xpm_path );
-    xpm_path=NULL;
+    HeapFree( GetProcessHeap(), 0, base_name );
+    base_name=NULL;
 
  end:
-    HeapFree(GetProcessHeap(), 0, iconsdir);
     HeapFree(GetProcessHeap(), 0, ico_path);
-    return xpm_path;
+    return base_name;
 }
 
 static BOOL DeferToRunOnce(LPWSTR link)
@@ -644,16 +790,17 @@ static LPSTR escape(LPCWSTR arg)
 
 static int fork_and_wait( const char *linker, const char *link_name, const char *path,
                           int desktop, const char *args, const char *icon_name,
-                          const char *workdir, const char *description )
+                          const char* icon_dir, const char *workdir, const char *description )
 {
     int pos = 0;
     const char *argv[20];
     int retcode;
 
     WINE_TRACE( "linker app='%s' link='%s' mode=%s "
-        "path='%s' args='%s' icon='%s' workdir='%s' descr='%s'\n",
+        "path='%s' args='%s' icon='%s' icondir='%s' workdir='%s' "
+        "descr='%s'\n",
         linker, link_name, desktop ? "desktop" : "menu",
-        path, args, icon_name, workdir, description  );
+        path, args, icon_name, icon_dir, workdir, description  );
 
     argv[pos++] = linker ;
     argv[pos++] = "--link";
@@ -670,6 +817,11 @@ static int fork_and_wait( const char *li
     {
         argv[pos++] = "--icon";
         argv[pos++] = icon_name;
+	if (icon_dir)
+	{
+	    argv[pos++] = "--icondir";
+	    argv[pos++] = icon_dir;
+	}
     }
     if (workdir && strlen(workdir))
     {
@@ -897,11 +1049,53 @@ static HRESULT get_cmdline( IShellLinkW 
     return hr;
 }
 
+static char* get_icons_dir ()
+{
+    char* iconsdir=NULL;  /* Default is no icon */
+    HKEY hkey;
+    
+    /* @@ Wine registry key: HKCU\Software\Wine\WineMenuBuilder */
+    if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\WineMenuBuilder", &hkey ))
+    {
+        static const WCHAR IconsDirW[] = {'I','c','o','n','s','D','i','r',0};
+        LPWSTR iconsdirW;
+        DWORD size = 0;
+
+        if (!RegQueryValueExW(hkey, IconsDirW, 0, NULL, NULL, &size))
+        {
+            iconsdirW = HeapAlloc(GetProcessHeap(), 0, size);
+            RegQueryValueExW(hkey, IconsDirW, 0, NULL, (LPBYTE)iconsdirW, &size);
+
+            if (!(iconsdir = wine_get_unix_file_name(iconsdirW)))
+            {
+                int n = WideCharToMultiByte(CP_UNIXCP, 0, iconsdirW, -1, NULL, 0, NULL, NULL);
+                iconsdir = HeapAlloc(GetProcessHeap(), 0, n);
+                WideCharToMultiByte(CP_UNIXCP, 0, iconsdirW, -1, iconsdir, n, NULL, NULL);
+            }
+            HeapFree(GetProcessHeap(), 0, iconsdirW);
+        }
+        RegCloseKey( hkey );
+    }
+
+    if (!iconsdir)
+    {
+        WCHAR path[MAX_PATH];
+        if (GetTempPathW(MAX_PATH, path))
+            iconsdir = wine_get_unix_file_name(path);
+        if (!iconsdir)
+        {
+            WINE_TRACE("no IconsDir\n");
+        }
+    }
+    
+    return iconsdir;
+}
+
 static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bAgain )
 {
     static const WCHAR startW[] = {'\\','c','o','m','m','a','n','d',
                                    '\\','s','t','a','r','t','.','e','x','e',0};
-    char *link_name = NULL, *icon_name = NULL, *work_dir = NULL;
+    char *link_name = NULL, *icon_name = NULL, *work_dir = NULL, *iconsdir;
     char *escaped_path = NULL, *escaped_args = NULL, *escaped_description = NULL;
     WCHAR szDescription[INFOTIPSIZE], szPath[MAX_PATH], szWorkDir[MAX_PATH];
     WCHAR szArgs[INFOTIPSIZE], szIconPath[MAX_PATH];
@@ -950,11 +1144,16 @@ static BOOL InvokeShellLinker( IShellLin
             WINE_TRACE("pidl path  : %s\n", wine_dbgstr_w(szPath));
     }
 
-    /* extract the icon */
-    if( szIconPath[0] )
-        icon_name = extract_icon( szIconPath , iIconId );
-    else
-        icon_name = extract_icon( szPath, iIconId );
+    iconsdir = get_icons_dir();
+    
+    if (iconsdir != NULL)
+    {
+        /* extract the icon */
+        if( szIconPath[0] )
+            icon_name = extract_icon( iconsdir, szIconPath , iIconId );
+        else
+            icon_name = extract_icon( iconsdir, szPath, iIconId );
+    }
 
     /* fail - try once again at reboot time */
     if( !icon_name )
@@ -1017,9 +1216,11 @@ static BOOL InvokeShellLinker( IShellLin
 
     r = fork_and_wait("wineshelllink", link_name, escaped_path,
                       in_desktop_dir(csidl), escaped_args, icon_name,
-                      work_dir ? work_dir : "", escaped_description);
+                      iconsdir, work_dir ? work_dir : "", 
+                      escaped_description);
 
 cleanup:
+    HeapFree( GetProcessHeap(), 0, iconsdir );
     HeapFree( GetProcessHeap(), 0, icon_name );
     HeapFree( GetProcessHeap(), 0, work_dir );
     HeapFree( GetProcessHeap(), 0, link_name );
diff --git a/tools/wineshelllink b/tools/wineshelllink
index 07334dc..da963e7 100755
--- a/tools/wineshelllink
+++ b/tools/wineshelllink
@@ -46,6 +46,7 @@ options:
   --link xx     name of link to create, including path
   --args xx     command-line arguments for the application
   --icon xx     icon to display
+  --icondir xx  directory from which to copy the icon
   --workdir xx  working directory for the application
   --descr xx    application description
 
@@ -66,6 +67,7 @@ do
     --link)    link="$2"; shift 2 ;;
     --args)    args="$2"; shift 2 ;;
     --icon)    icon="$2"; shift 2 ;;
+    --icondir) icondir="$2"; shift 2 ;;
     --descr)   descr="$2"; shift 2 ;;
     --workdir) workdir="$2"; shift 2 ;;
     *) usage ;;
@@ -113,15 +115,17 @@ EOF
 # copy the icon file to a specified dir and set xpmicon to the resulting path
 copy_icon()
 {
-    if [ -f "$icon" ]
+    if [ -f "$icondir/$icon.xpm" ]
     then
-        xpmicon=`basename "$icon" .xpm`
-
         mkdir -p "$1"
-        cp "$icon" "$1/$xpmicon.xpm"
-    else
-        xpmicon=""
+        mv "$icondir/$icon.xpm" "$1"
+    fi
+    if [ -f "$icondir/$icon.png" ]
+    then
+        mkdir -p "$1"
+        mv "$icondir/$icon.png" "$1"
     fi
+    xpmicon="$icon"
 }
 
 # XDG
-- 
1.4.2.4



More information about the wine-patches mailing list