[user32]
[reactos.git] / reactos / dll / win32 / user32 / windows / icon.c
index 218b3ef..5840b89 100644 (file)
 #include <user32.h>
 
 #include <wine/debug.h>
-
+WINE_DEFAULT_DEBUG_CHANNEL(user32);
 
 /* FUNCTIONS *****************************************************************/
 
-HICON
-ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot)
-{
-   BYTE BitmapInfoBuffer[sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD)];
-   BITMAPINFO *bwBIH = (BITMAPINFO *)BitmapInfoBuffer;
-   ICONINFO IconInfo;
-
-   IconInfo.fIcon = TRUE;
-   IconInfo.xHotspot = xHotspot;
-   IconInfo.yHotspot = yHotspot;
-
-   /* Load the XOR bitmap */
-   IconInfo.hbmColor = 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->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 = 0;
-   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. */
-   IconInfo.hbmMask = CreateDIBitmap(hDC, &bwBIH->bmiHeader, 0,
-                                     ImageData, bwBIH, DIB_RGB_COLORS);
-
-   SetDIBits(hDC, IconInfo.hbmMask, 0, IconImage->icHeader.biHeight,
-             ImageData, bwBIH, DIB_RGB_COLORS);
-
-   /* Create the icon based on everything we have so far */
-   return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
-}
 
 HICON
-ICON_CreateCursorFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot)
+CreateCursorIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot, BOOL fIcon)
 {
-   /* FIXME - color cursors */
    BYTE BitmapInfoBuffer[sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD)];
    BITMAPINFO *bwBIH = (BITMAPINFO *)BitmapInfoBuffer;
    ICONINFO IconInfo;
-   PVOID XORImageData = ImageData;
 
-   IconInfo.fIcon = FALSE;
+   IconInfo.fIcon = fIcon;
    IconInfo.xHotspot = xHotspot;
    IconInfo.yHotspot = yHotspot;
 
-   /* Create a BITMAPINFO header for the monocrome part of the icon */
-   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 = 0;
-   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 */
-   IconInfo.hbmMask = CreateDIBitmap(hDC, &bwBIH->bmiHeader, 0,
-                                     XORImageData, bwBIH, DIB_RGB_COLORS);
-   if (IconInfo.hbmMask)
+   if (IconImage->icHeader.biBitCount == 1)
+   {
+       IconInfo.hbmColor = (HBITMAP)0;
+       IconImage->icHeader.biHeight *= 2;
+       IconInfo.hbmMask = CreateDIBitmap(hDC, &IconImage->icHeader, CBM_INIT,
+                                  ImageData, (BITMAPINFO*)IconImage,
+                                  DIB_RGB_COLORS);
+   }
+   else
    {
-      SetDIBits(hDC, IconInfo.hbmMask, 0, IconImage->icHeader.biHeight,
-                XORImageData, bwBIH, DIB_RGB_COLORS);
+       /* Create the XOR bitmap */
+       IconInfo.hbmColor = 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 monochrome part of the icon. */
+       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 = 0;
+       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;
+
+       /* Create the AND bitmap. */
+       IconInfo.hbmMask = CreateDIBitmap(hDC, &bwBIH->bmiHeader, 0,
+                                         ImageData, bwBIH, DIB_RGB_COLORS);
+
+       SetDIBits(hDC, IconInfo.hbmMask, 0, IconImage->icHeader.biHeight,
+                 ImageData, bwBIH, DIB_RGB_COLORS);
    }
 
-   IconInfo.hbmColor = (HBITMAP)0;
 
    /* Create the icon based on everything we have so far */
    return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
 }
 
-
 /*
  * @implemented
  */
 HICON
-STDCALL
-CopyIcon(
-  HICON hIcon)
+WINAPI
+CopyIcon(HICON hIcon)
 {
-  ICONINFO IconInfo;
+    HICON hRetIcon = NULL;
+    ICONINFO IconInfo;
 
-  if(NtUserGetCursorIconInfo((HANDLE)hIcon, &IconInfo))
-  {
-    return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
-  }
-  return (HICON)0;
+    if(GetIconInfo(hIcon, &IconInfo))
+    {
+        hRetIcon = CreateIconIndirect(&IconInfo);
+        DeleteObject(IconInfo.hbmColor);
+        DeleteObject(IconInfo.hbmMask);
+    }
+
+    return hRetIcon;
 }
 
 
@@ -164,7 +128,7 @@ CopyIcon(
  * @implemented
  */
 HICON
-STDCALL
+WINAPI
 CreateIcon(
   HINSTANCE hInstance,
   int nWidth,
@@ -177,18 +141,29 @@ CreateIcon(
   ICONINFO IconInfo;
 
   IconInfo.fIcon = TRUE;
-  IconInfo.xHotspot = nWidth / 2;
-  IconInfo.yHotspot = nHeight / 2;
+  
+  if (cBitsPixel == 1)
+  {
+    nHeight <<= 1;
+  }
   IconInfo.hbmMask = CreateBitmap(nWidth, nHeight, 1, 1, ANDbits);
   if(!IconInfo.hbmMask)
   {
     return (HICON)0;
   }
-  IconInfo.hbmColor = CreateBitmap(nWidth, nHeight, cPlanes, cBitsPixel, XORbits);
-  if(!IconInfo.hbmColor)
+
+  if (cBitsPixel == 1)
   {
-    DeleteObject(IconInfo.hbmMask);
-    return (HICON)0;
+    IconInfo.hbmColor = (HBITMAP)0;
+  }
+  else
+  {
+    IconInfo.hbmColor = CreateBitmap(nWidth, nHeight, cPlanes, cBitsPixel, XORbits);
+    if(!IconInfo.hbmColor)
+    { 
+       DeleteObject(IconInfo.hbmMask);
+       return (HICON)0;
+    }
   }
 
   return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
@@ -199,14 +174,14 @@ CreateIcon(
  * @implemented
  */
 HICON
-STDCALL
+WINAPI
 CreateIconFromResource(
   PBYTE presbits,
   DWORD dwResSize,
   BOOL fIcon,
   DWORD dwVer)
 {
-  return CreateIconFromResourceEx(presbits, dwResSize, fIcon, dwVer, 0, 0, 0);
+  return CreateIconFromResourceEx(presbits, dwResSize, fIcon, dwVer, 0, 0, LR_DEFAULTSIZE|LR_SHARED );
 }
 
 
@@ -214,7 +189,7 @@ CreateIconFromResource(
  * @implemented
  */
 HICON
-STDCALL
+WINAPI
 CreateIconFromResourceEx(
   PBYTE pbIconBits,
   DWORD cbIconBits,
@@ -242,15 +217,15 @@ CreateIconFromResourceEx(
   }
   */
 
-  DPRINT("dwVersion, cxDesired, cyDesired are all ignored in this implementation!\n");
+  TRACE("dwVersion, cxDesired, cyDesired are all ignored in this implementation!\n");
 
   if (! fIcon)
     {
       wXHotspot = *(WORD*)pbIconBits;
-      pbIconBits+=sizeof(WORD);
+      pbIconBits += sizeof(WORD);
       wYHotspot = *(WORD*)pbIconBits;
-      pbIconBits+=sizeof(WORD);
-      cbIconBits-=2*sizeof(WORD);
+      pbIconBits += sizeof(WORD);
+      cbIconBits -= 2 * sizeof(WORD);
     }
   else
     {
@@ -266,8 +241,7 @@ CreateIconFromResourceEx(
     }
   memcpy(SafeIconImage, pbIconBits, cbIconBits);
 
-  /* take into acount the origonal height was for both the AND and XOR images */
-  if(fIcon)
+  /* Take into acount the original height was for both the AND and XOR images */
     SafeIconImage->icHeader.biHeight /= 2;
 
   if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
@@ -287,6 +261,8 @@ CreateIconFromResourceEx(
   Data = (PBYTE)SafeIconImage + HeaderSize;
 
   /* get a handle to the screen dc, the icon we create is going to be compatable with this */
+  // FIXME!!! This is a victim of the Win32k Initialization BUG!!!!!
+  //hScreenDc = CreateDCW(NULL, NULL, NULL, NULL);
   hScreenDc = CreateCompatibleDC(NULL);
   if (hScreenDc == NULL)
     {
@@ -294,10 +270,7 @@ CreateIconFromResourceEx(
       return(NULL);
     }
 
-  if(fIcon)
-    hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, cxDesired, cyDesired, wXHotspot, wYHotspot);
-  else
-    hIcon = ICON_CreateCursorFromData(hScreenDc, Data, SafeIconImage, cxDesired, cyDesired, wXHotspot, wYHotspot);
+  hIcon = CreateCursorIconFromData(hScreenDc, Data, SafeIconImage, cxDesired, cyDesired, wXHotspot, wYHotspot, fIcon);
   RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
   DeleteDC(hScreenDc);
 
@@ -309,11 +282,12 @@ CreateIconFromResourceEx(
  * @implemented
  */
 HICON
-STDCALL
+WINAPI
 CreateIconIndirect(PICONINFO IconInfo)
 {
   BITMAP ColorBitmap;
   BITMAP MaskBitmap;
+  HBITMAP hbmTemp;
 
   if(!IconInfo)
   {
@@ -325,20 +299,26 @@ CreateIconIndirect(PICONINFO IconInfo)
   {
     return (HICON)0;
   }
-  /* FIXME - does there really *have* to be a color bitmap? monochrome cursors don't have one */
-  if(IconInfo->hbmColor && !GetObjectW(IconInfo->hbmColor, sizeof(BITMAP), &ColorBitmap))
-  {
-    return (HICON)0;
-  }
 
-  /* FIXME - i doubt this is right (monochrome cursors */
-  /*if(ColorBitmap.bmWidth != MaskBitmap.bmWidth ||
-     ColorBitmap.bmHeight != MaskBitmap.bmWidth)
+  /* Try to get color bitmap */
+  if (GetObjectW(IconInfo->hbmColor, sizeof(BITMAP), &ColorBitmap))
   {
-    SetLastError(ERROR_INVALID_PARAMETER);
-    return (HICON)0;
-  }*/
-
+     /* Compare size of color and mask bitmap*/
+     if (ColorBitmap.bmWidth != MaskBitmap.bmWidth ||
+        ColorBitmap.bmHeight != MaskBitmap.bmHeight)
+     {
+        ERR("Color and mask size are different!");
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return (HICON)0;
+     }
+     /* Check if color and mask are switched and switch them back */
+     if (MaskBitmap.bmBitsPixel != 1 && ColorBitmap.bmBitsPixel == 1)
+     {
+        hbmTemp = IconInfo->hbmMask;
+        IconInfo->hbmMask = IconInfo->hbmColor;
+        IconInfo->hbmColor = hbmTemp;
+     }
+  }
   return (HICON)NtUserCreateCursorIconHandle(IconInfo, TRUE);
 }
 
@@ -347,11 +327,11 @@ CreateIconIndirect(PICONINFO IconInfo)
  * @implemented
  */
 BOOL
-STDCALL
+WINAPI
 DestroyIcon(
   HICON hIcon)
 {
-  return (BOOL)NtUserDestroyCursorIcon((HANDLE)hIcon, 0);
+  return (BOOL)NtUserDestroyCursor((HANDLE)hIcon, 0);
 }
 
 
@@ -359,7 +339,7 @@ DestroyIcon(
  * @implemented
  */
 BOOL
-STDCALL
+WINAPI
 DrawIcon(
   HDC hDC,
   int X,
@@ -373,7 +353,7 @@ DrawIcon(
  * @implemented
  */
 BOOL
-STDCALL
+WINAPI
 DrawIconEx(
   HDC hdc,
   int xLeft,
@@ -395,13 +375,12 @@ DrawIconEx(
  * @implemented
  */
 BOOL
-STDCALL
+WINAPI
 GetIconInfo(
   HICON hIcon,
   PICONINFO IconInfo)
 {
-  /* FIXME - copy bitmaps */
-  return (BOOL)NtUserGetCursorIconInfo((HANDLE)hIcon, IconInfo);
+  return NtUserGetIconInfo((HANDLE)hIcon, IconInfo, 0, 0, 0, 0);
 }
 
 
@@ -409,7 +388,7 @@ GetIconInfo(
  * @implemented
  */
 HICON
-STDCALL
+WINAPI
 LoadIconA(
   HINSTANCE hInstance,
   LPCSTR lpIconName)
@@ -422,7 +401,7 @@ LoadIconA(
  * @implemented
  */
 HICON
-STDCALL
+WINAPI
 LoadIconW(
   HINSTANCE hInstance,
   LPCWSTR lpIconName)
@@ -435,7 +414,7 @@ LoadIconW(
  * @implemented
  */
 int
-STDCALL
+WINAPI
 LookupIconIdFromDirectory(
   PBYTE presbits,
   BOOL fIcon)
@@ -505,7 +484,7 @@ CURSORICON_FindBestIcon(LPVOID dir,
         }
     }
 
-    DPRINT("Best Icon: ResId: %d, bits : %d\n", BestEntry, BestBits);
+    TRACE("Best Icon: ResId: %d, bits : %d\n", BestEntry, BestBits);
 
     return BestEntry;
 }
@@ -526,40 +505,43 @@ CURSORICON_FindBestCursor(LPVOID dir,
                           int Height,
                           int ColorBits)
 {
-    int i, MaxWidth, MaxHeight, cx, cy, Bits, BestEntry = -1;
-
-    /* Double height to account for AND and XOR masks */
-    Height *= 2;
+    int i, cx, cy, Bits, BestBits = 0, BestEntry = -1;
+    UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
+    UINT iTempXDiff, iTempYDiff, iTempColorDiff;
 
-    /* First find the largest one smaller than or equal to the requested size*/
-    MaxWidth = MaxHeight = 0;
+    /* Find Best Fit */
+    iTotalDiff = 0xFFFFFFFF;
+    iColorDiff = 0xFFFFFFFF;
     for (i = 0; get_entry(dir, i, &cx, &cy, &Bits); i++ )
     {
-        if ((cx <= Width) && (cy <= Height) &&
-            (cx > MaxWidth) && (cy > MaxHeight) &&
-            (Bits == 1))
+        iTempXDiff = abs(Width - cx);
+        iTempYDiff = abs(Height - cy);
+
+        if(iTotalDiff > (iTempXDiff + iTempYDiff))
         {
-            BestEntry = i;
-            MaxWidth  = cx;
-            MaxHeight = cy;
+            iXDiff = iTempXDiff;
+            iYDiff = iTempYDiff;
+            iTotalDiff = iXDiff + iYDiff;
         }
     }
-    if (BestEntry != -1)
-        return BestEntry;
 
-    /* Now find the smallest one larger than the requested size */
-    MaxWidth = MaxHeight = 255;
+    /* Find Best Colors for Best Fit */
     for (i = 0; get_entry(dir, i, &cx, &cy, &Bits); i++ )
     {
-        if (((cx < MaxWidth) && (cy < MaxHeight) && (Bits == 1)) ||
-            (BestEntry == -1))
+        if(abs(Width - cx) == iXDiff && abs(Height - cy) == iYDiff)
         {
-            BestEntry = i;
-            MaxWidth  = cx;
-            MaxHeight = cy;
+            iTempColorDiff = abs(ColorBits - Bits);
+            if(iColorDiff > iTempColorDiff)
+            {
+                BestEntry = i;
+                BestBits = Bits;
+                iColorDiff = iTempColorDiff;
+            }
         }
     }
 
+    TRACE("Best Cursor: ResId: %d, bits : %d\n", BestEntry, BestBits);
+
     return BestEntry;
 }
 
@@ -650,6 +632,9 @@ LookupIconIdFromDirectoryEx(PBYTE xdir,
 {
     GRPCURSORICONDIR *dir = (GRPCURSORICONDIR*)xdir;
     UINT retVal = 0;
+
+    GetConnected();
+
     if(dir && !dir->idReserved && (IMAGE_ICON == dir->idType || IMAGE_CURSOR == dir->idType))
     {
         GRPCURSORICONDIRENTRY *entry = NULL;
@@ -659,11 +644,13 @@ LookupIconIdFromDirectoryEx(PBYTE xdir,
         {
             ColorBits = 1;
         }
+        else if (cFlag & LR_VGACOLOR)
+        {
+            ColorBits = 4;
+        }
         else
         {
-            HDC hdc = GetDC(0);
-            ColorBits = GetDeviceCaps(hdc, BITSPIXEL);
-            ReleaseDC(0, hdc);
+            ColorBits = gpsi->BitsPixel;
         }
 
         if(bIcon)
@@ -675,7 +662,7 @@ LookupIconIdFromDirectoryEx(PBYTE xdir,
             retVal = entry->nID;
     }
     else
-        DPRINT1("%s() : Invalid resource directory\n", __FUNCTION__);
+        WARN("%s() : Invalid resource directory\n", __FUNCTION__);
 
     return retVal;
 }