update for HEAD-2003091401
[reactos.git] / lib / user32 / windows / icon.c
index 14ed6f8..6dcb26a 100644 (file)
@@ -19,8 +19,8 @@
 /* $Id$
  *
  * PROJECT:         ReactOS user32.dll
- * FILE:            lib/user32/windows/input.c
- * PURPOSE:         Input
+ * FILE:            lib/user32/windows/icon.c
+ * PURPOSE:         Icon
  * PROGRAMMER:      Casper S. Hornstrup (chorns@users.sourceforge.net)
  * UPDATE HISTORY:
  *      09-05-2001  CSH  Created
 
 #include <windows.h>
 #include <user32.h>
+#include <string.h>
+#include <stdlib.h>
 #include <debug.h>
 
 /* FUNCTIONS *****************************************************************/
 
 HICON
+ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot)
+{
+  HANDLE hXORBitmap;
+  HANDLE hANDBitmap;
+  BITMAPINFO* bwBIH;
+  ICONINFO IconInfo;
+  HICON hIcon;
+
+  //load the XOR bitmap
+  hXORBitmap = CreateDIBitmap(hDC, &IconImage->icHeader, CBM_INIT,
+                              ImageData, (BITMAPINFO*)IconImage, DIB_RGB_COLORS);
+
+  //make ImageData point to the start of the AND image data
+  ImageData = ((PBYTE)ImageData) + (((IconImage->icHeader.biWidth * 
+                                      IconImage->icHeader.biBitCount + 31) & ~31) >> 3) * 
+                                      (IconImage->icHeader.biHeight );
+
+  //create a BITMAPINFO header for the monocrome part of the icon
+  bwBIH = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (BITMAPINFOHEADER)+2*sizeof(RGBQUAD));
+
+  bwBIH->bmiHeader.biBitCount = 1;
+  bwBIH->bmiHeader.biWidth = IconImage->icHeader.biWidth;
+  bwBIH->bmiHeader.biHeight = IconImage->icHeader.biHeight;
+  bwBIH->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+  bwBIH->bmiHeader.biPlanes = 1;
+  bwBIH->bmiHeader.biSizeImage = (((IconImage->icHeader.biWidth * 1 + 31) & ~31) >> 3) * 
+                                    (IconImage->icHeader.biHeight );
+  bwBIH->bmiHeader.biCompression = BI_RGB;
+  bwBIH->bmiHeader.biClrImportant = 0;
+  bwBIH->bmiHeader.biClrUsed = 0;
+  bwBIH->bmiHeader.biXPelsPerMeter = 0;
+  bwBIH->bmiHeader.biYPelsPerMeter = 0;
+
+  bwBIH->bmiColors[0].rgbBlue = 0;
+  bwBIH->bmiColors[0].rgbGreen = 0;
+  bwBIH->bmiColors[0].rgbRed = 0;
+  bwBIH->bmiColors[0].rgbReserved = 0;
+
+  bwBIH->bmiColors[1].rgbBlue = 0xff;
+  bwBIH->bmiColors[1].rgbGreen = 0xff;
+  bwBIH->bmiColors[1].rgbRed = 0xff;
+  bwBIH->bmiColors[1].rgbReserved = 0;
+
+  //load the AND bitmap
+  hANDBitmap = CreateDIBitmap(hDC, &bwBIH->bmiHeader, CBM_INIT,
+                              ImageData, bwBIH, DIB_RGB_COLORS);
+
+  RtlFreeHeap(RtlGetProcessHeap(), 0, bwBIH);
+
+  IconInfo.fIcon = TRUE;
+  IconInfo.xHotspot = xHotspot;
+  IconInfo.yHotspot = yHotspot;
+  IconInfo.hbmColor = hXORBitmap;
+  IconInfo.hbmMask = hANDBitmap;
+
+  //Create the icon based on everything we have so far
+  hIcon = CreateIconIndirect(&IconInfo);
+
+  //clean up
+  DeleteObject(hXORBitmap);
+  DeleteObject(hANDBitmap);
+
+  return hIcon;
+}
+
+
+/*
+ * @implemented
+ */
+HICON
 STDCALL
 CopyIcon(
   HICON hIcon)
 {
-  return (HICON)0;
+  ICONINFO IconInfo;
+  NtUserGetIconInfo(hIcon, &IconInfo.fIcon,
+                           &IconInfo.xHotspot,
+                           &IconInfo.yHotspot,
+                           &IconInfo.hbmMask,
+                           &IconInfo.hbmColor);
+  return CreateIconIndirect(&IconInfo);
 }
+
+
+/*
+ * @implemented
+ */
 HICON
 STDCALL
 CreateIcon(
@@ -52,9 +135,22 @@ CreateIcon(
   CONST BYTE *lpbANDbits,
   CONST BYTE *lpbXORbits)
 {
-  return (HICON)0;
+  DPRINT("hInstance not used in this implementation\n");
+  return NtGdiCreateIcon(TRUE,
+                        nWidth,
+                        nHeight,
+                        cPlanes,
+                        cBitsPixel,
+                        nWidth/2,
+                        nHeight/2,
+                        lpbANDbits,
+                        lpbXORbits);
 }
 
+
+/*
+ * @implemented
+ */
 HICON
 STDCALL
 CreateIconFromResource(
@@ -63,9 +159,13 @@ CreateIconFromResource(
   WINBOOL fIcon,
   DWORD dwVer)
 {
-  return (HICON)0;
+  return CreateIconFromResourceEx( presbits, dwResSize, fIcon, dwVer, 0,0,0);
 }
 
+
+/*
+ * @implemented
+ */
 HICON
 STDCALL
 CreateIconFromResourceEx(
@@ -77,23 +177,109 @@ CreateIconFromResourceEx(
   int cyDesired,
   UINT uFlags)
 {
-  return (HICON)0;
+  ICONIMAGE* SafeIconImage;
+  HICON hIcon;
+  ULONG HeaderSize;
+  ULONG ColourCount;
+  PVOID Data;
+  HDC hScreenDc;
+  WORD wXHotspot;
+  WORD wYHotspot;
+
+  DPRINT("dwVersion, cxDesired, cyDesired are all ignored in this implementation!\n");
+
+  if (!fIcon)
+  {
+         wXHotspot = (WORD)*pbIconBits;
+         pbIconBits+=2;
+         wYHotspot = (WORD)*pbIconBits;
+         pbIconBits+=2;
+         cbIconBits-=4;
+  }
+  else
+  {
+         wXHotspot = cxDesired / 2;
+         wYHotspot = cyDesired / 2;
+  }
+
+  //get an safe copy of the icon data
+  SafeIconImage = RtlAllocateHeap(RtlGetProcessHeap(), 0, cbIconBits);
+  memcpy(SafeIconImage, pbIconBits, cbIconBits);
+
+  //take into acount the origonal hight was for both the AND and XOR images
+  SafeIconImage->icHeader.biHeight /= 2;
+
+  if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
+  {
+      BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
+      ColourCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
+      HeaderSize = sizeof(BITMAPCOREHEADER) + ColourCount * sizeof(RGBTRIPLE);
+  }
+  else
+  {
+      ColourCount = (SafeIconImage->icHeader.biBitCount <= 8) ? 
+                       (1 << SafeIconImage->icHeader.biBitCount) : 0;
+      HeaderSize = sizeof(BITMAPINFOHEADER) + ColourCount * sizeof(RGBQUAD);
+  }
+
+  //make data point to the start of the XOR image data
+  Data = (PBYTE)SafeIconImage + HeaderSize;
+
+  //get a handle to the screen dc, the icon we create is going to be compatable with this
+  hScreenDc = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
+  if (hScreenDc == NULL)
+  {
+     RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage);
+     return(NULL);
+  }
+
+  hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, cxDesired, cyDesired, wXHotspot, wYHotspot);
+  RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage);
+  return hIcon;
 }
 
+
+/*
+ * @implemented
+ */
 HICON
 STDCALL
 CreateIconIndirect(
   PICONINFO piconinfo)
 {
-  return (HICON)0;
+  BITMAP bmMask;
+  BITMAP bmColor;
+
+  NtGdiGetObject( piconinfo->hbmMask, sizeof(BITMAP), &bmMask );
+  NtGdiGetObject( piconinfo->hbmColor, sizeof(BITMAP), &bmColor );
+
+  return NtGdiCreateIcon(piconinfo->fIcon,
+                       bmColor.bmWidth,
+                       bmColor.bmHeight,
+                       bmColor.bmPlanes,
+                       bmColor.bmBitsPixel,
+                       piconinfo->xHotspot,
+                       piconinfo->yHotspot,
+                       bmMask.bmBits,
+                       bmColor.bmBits);
 }
+
+
+/*
+ * @implemented
+ */
 WINBOOL
 STDCALL
 DestroyIcon(
   HICON hIcon)
 {
-  return FALSE;
+  return NtGdiDeleteObject(hIcon);
 }
+
+
+/*
+ * @implemented
+ */
 WINBOOL
 STDCALL
 DrawIcon(
@@ -102,9 +288,13 @@ DrawIcon(
   int Y,
   HICON hIcon)
 {
-  return FALSE;
+  return DrawIconEx (hDC, X, Y, hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE);
 }
 
+/* Ported from WINE20030408 */
+/*
+ * @implemented
+ */
 WINBOOL
 STDCALL
 DrawIconEx(
@@ -118,42 +308,317 @@ DrawIconEx(
   HBRUSH hbrFlickerFreeDraw,
   UINT diFlags)
 {
-  return FALSE;
+    ICONINFO IconInfo;
+    BITMAP XORBitmap;
+    HDC hDC_off = 0, hMemDC;
+    BOOL result = FALSE, DoOffscreen;
+    HBITMAP hB_off = 0, hOld = 0;
+
+    if (!NtUserGetIconInfo(hIcon, &IconInfo.fIcon,
+                                  &IconInfo.xHotspot,
+                                  &IconInfo.yHotspot,
+                                  &IconInfo.hbmMask,
+                                  &IconInfo.hbmColor))
+      return FALSE;
+
+    NtGdiGetObject(IconInfo.hbmColor, sizeof(BITMAP), &XORBitmap);
+
+    DPRINT("(hdc=%p,pos=%d.%d,hicon=%p,extend=%d.%d,istep=%d,br=%p,flags=0x%08x)\n",
+                 hdc,xLeft,yTop,hIcon,cxWidth,cyWidth,istepIfAniCur,hbrFlickerFreeDraw,diFlags );
+
+    hMemDC = CreateCompatibleDC (hdc);
+    if (diFlags & DI_COMPAT)
+        DPRINT("Ignoring flag DI_COMPAT\n");
+
+    if (!diFlags)
+    {
+         diFlags = DI_NORMAL;
+    }
+
+    // Calculate the size of the destination image.
+    if (cxWidth == 0)
+    {
+      if (diFlags & DI_DEFAULTSIZE)
+            cxWidth = GetSystemMetrics (SM_CXICON);
+      else
+            cxWidth = XORBitmap.bmWidth;
+    }
+    if (cyWidth == 0)
+    {
+      if (diFlags & DI_DEFAULTSIZE)
+        cyWidth = GetSystemMetrics (SM_CYICON);
+      else
+           cyWidth = XORBitmap.bmHeight;
+    }
+
+    DoOffscreen = (GetObjectType( hbrFlickerFreeDraw ) == OBJ_BRUSH);
+
+    if (DoOffscreen)
+    {
+      RECT r;
+
+      r.left = 0;
+      r.top = 0;
+      r.right = cxWidth;
+      r.bottom = cxWidth;
+
+      DbgPrint("in DrawIconEx calling: CreateCompatibleDC\n");
+      hDC_off = CreateCompatibleDC(hdc);
+
+      DbgPrint("in DrawIconEx calling: CreateCompatibleBitmap\n");
+      hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
+      if (hDC_off && hB_off)
+      {
+        DbgPrint("in DrawIconEx calling: SelectObject\n");
+        hOld = SelectObject(hDC_off, hB_off);
+
+        DbgPrint("in DrawIconEx calling: FillRect\n");
+        FillRect(hDC_off, &r, hbrFlickerFreeDraw);
+      }
+    }
+
+    if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
+    {
+      COLORREF  oldFg, oldBg;
+      INT     nStretchMode;
+
+      nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
+
+      oldFg = SetTextColor( hdc, RGB(0,0,0) );
+
+      oldBg = SetBkColor( hdc, RGB(255,255,255) );
+
+      if (IconInfo.hbmColor && IconInfo.hbmMask)
+      {
+        HBITMAP hBitTemp = SelectObject( hMemDC, IconInfo.hbmMask );
+        if (diFlags & DI_MASK)
+        {
+          if (DoOffscreen)
+            StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
+               hMemDC, 0, 0, XORBitmap.bmWidth, XORBitmap.bmHeight, SRCAND);
+          else
+            StretchBlt (hdc, xLeft, yTop, cxWidth, cyWidth,
+                 hMemDC, 0, 0, XORBitmap.bmWidth, XORBitmap.bmHeight, SRCAND);
+        }
+        SelectObject( hMemDC, IconInfo.hbmColor );
+        if (diFlags & DI_IMAGE)
+        {
+          if (DoOffscreen)
+            StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
+               hMemDC, 0, 0, XORBitmap.bmWidth, XORBitmap.bmHeight, SRCPAINT);
+          else
+            StretchBlt (hdc, xLeft, yTop, cxWidth, cyWidth,
+              hMemDC, 0, 0, XORBitmap.bmWidth, XORBitmap.bmHeight, SRCPAINT);
+        }
+        SelectObject( hMemDC, hBitTemp );
+        result = TRUE;
+      }
+
+      SetTextColor( hdc, oldFg );
+      SetBkColor( hdc, oldBg );
+      if (IconInfo.hbmColor)
+        DeleteObject( IconInfo.hbmColor );
+
+      if (IconInfo.hbmMask) 
+        DeleteObject( IconInfo.hbmMask );
+
+      SetStretchBltMode (hdc, nStretchMode);
+
+      if (DoOffscreen)
+      {
+        BitBlt(hdc, xLeft, yTop, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
+        SelectObject(hDC_off, hOld);
+      }
+    }
+
+    if (hMemDC)
+      DeleteDC( hMemDC );
+    if (hDC_off)
+      DeleteDC(hDC_off);
+    if (hB_off)
+      DeleteObject(hB_off);
+    return result;
 }
+
+
+/*
+ * @implemented
+ */
 WINBOOL
 STDCALL
 GetIconInfo(
   HICON hIcon,
   PICONINFO piconinfo)
 {
-  return FALSE;
+  ICONINFO IconInfo;
+  WINBOOL res;
+  
+  if(!piconinfo)
+  {
+    SetLastError(ERROR_NOACCESS);
+    return FALSE;
+  }
+  
+  res = NtUserGetIconInfo(hIcon,
+                          &piconinfo->fIcon,
+                          &piconinfo->xHotspot,
+                          &piconinfo->yHotspot,
+                          &piconinfo->hbmMask,
+                          &piconinfo->hbmColor);
+  if(res)
+    RtlCopyMemory(piconinfo, &IconInfo, sizeof(ICONINFO));
+  return res;
 }
+
+
+/*
+ * @implemented
+ */
 HICON
 STDCALL
 LoadIconA(
   HINSTANCE hInstance,
   LPCSTR lpIconName)
 {
-  return (HICON)0;
+  return(LoadImageA(hInstance, lpIconName, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
 }
 
+
+/*
+ * @implemented
+ */
 HICON
 STDCALL
 LoadIconW(
   HINSTANCE hInstance,
   LPCWSTR lpIconName)
 {
-  return (HICON)0;
+  return(LoadImageW(hInstance, lpIconName, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
 }
+
+
+/*
+ * @implemented
+ */
 int
 STDCALL
 LookupIconIdFromDirectory(
   PBYTE presbits,
   WINBOOL fIcon)
 {
-  return 0;
+    return LookupIconIdFromDirectoryEx( presbits, fIcon,
+          fIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
+          fIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), LR_DEFAULTCOLOR );
+}
+
+/* Ported from WINE20030408 */
+CURSORICONDIRENTRY*
+CURSORICON_FindBestCursor( CURSORICONDIR *dir, int width, int height, int colors)
+{
+    int i;
+    CURSORICONDIRENTRY *entry, *bestEntry = NULL;
+    UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
+    UINT iTempXDiff, iTempYDiff, iTempColorDiff;
+
+    if (dir->idCount < 1)
+    {
+        DPRINT("Empty directory!\n");
+        return NULL;
+    }
+    if (dir->idCount == 1) 
+      return &dir->idEntries[0];  /* No choice... */
+
+    /* Find Best Fit */
+    iTotalDiff = 0xFFFFFFFF;
+    iColorDiff = 0xFFFFFFFF;
+    for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
+    {
+               iTempXDiff = abs(width - entry->bWidth);
+               iTempYDiff = abs(height - entry->bHeight);
+
+        if(iTotalDiff > (iTempXDiff + iTempYDiff))
+        {
+            iXDiff = iTempXDiff;
+            iYDiff = iTempYDiff;
+            iTotalDiff = iXDiff + iYDiff;
+        }
+    }
+
+    /* Find Best Colors for Best Fit */
+    for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
+    {
+        if(abs(width - entry->bWidth) == (int) iXDiff &&
+            abs(height - entry->bHeight) == (int) iYDiff)
+        {
+            iTempColorDiff = abs(colors - entry->bColorCount);
+
+            if(iColorDiff > iTempColorDiff)
+               {
+               bestEntry = entry;
+                iColorDiff = iTempColorDiff;
+               }
+        }
+    }
+
+    return bestEntry;
+}
+
+/* Ported from WINE20030408 */
+CURSORICONDIRENTRY*
+CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width, int height, int colors)
+{
+    int i;
+    CURSORICONDIRENTRY *entry, *bestEntry = NULL;
+    UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
+    UINT iTempXDiff, iTempYDiff, iTempColorDiff;
+
+    if (dir->idCount < 1)
+    {
+        DPRINT("Empty directory!\n");
+        return NULL;
+    }
+    if (dir->idCount == 1)
+      return &dir->idEntries[0];  /* No choice... */
+
+    /* Find Best Fit */
+    iTotalDiff = 0xFFFFFFFF;
+    iColorDiff = 0xFFFFFFFF;
+    for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
+      {
+       iTempXDiff = abs(width - entry->bWidth);
+
+       iTempYDiff = abs(height - entry->bHeight);
+
+        if(iTotalDiff > (iTempXDiff + iTempYDiff))
+        {
+            iXDiff = iTempXDiff;
+            iYDiff = iTempYDiff;
+            iTotalDiff = iXDiff + iYDiff;
+        }
+      }
+
+    /* Find Best Colors for Best Fit */
+    for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
+      {
+        if(abs(width - entry->bWidth) == (int) iXDiff &&
+           abs(height - entry->bHeight) == (int) iYDiff)
+        {
+            iTempColorDiff = abs(colors - entry->bColorCount);
+            if(iColorDiff > iTempColorDiff)
+            {
+                bestEntry = entry;
+                iColorDiff = iTempColorDiff;
+            }
+        }
+    }
+
+    return bestEntry;
 }
 
+/* Ported from WINE20030408 */
+/*
+ * @implemented
+ */
 int
 STDCALL
 LookupIconIdFromDirectoryEx(
@@ -163,5 +628,37 @@ LookupIconIdFromDirectoryEx(
   int cyDesired,
   UINT Flags)
 {
-  return 0;
+    GRPCURSORICONDIR *dir = (GRPCURSORICONDIR*)presbits;
+    UINT retVal = 0;
+
+    if( dir && !dir->idReserved && (dir->idType & 3) )
+    {
+       GRPCURSORICONDIRENTRY* entry;
+       HDC hdc;
+       UINT palEnts;
+       int colors;
+       hdc = GetDC(0);
+#if 0
+       palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
+       if (palEnts == 0)
+       palEnts = 256;
+#endif
+       palEnts = 16;  //use this until GetSystemPaletteEntries works
+       colors = (Flags & LR_MONOCHROME) ? 2 : palEnts;
+
+       ReleaseDC(0, hdc);
+
+       entry = (GRPCURSORICONDIRENTRY*)CURSORICON_FindBestIcon( (CURSORICONDIR*)dir,
+                                                          cxDesired,
+                                                          cyDesired,
+                                                          colors );
+
+       if( entry )
+           retVal = entry->nID;
+    }
+    else
+    {
+       DbgPrint("invalid resource directory\n");
+    }
+    return retVal;
 }