2 * Cursor and icon support
4 * Copyright 1995 Alexandre Julliard
5 * Copyright 1996 Martin von Loewis
11 * Cursors and icons are stored in a global heap block, with the
14 * CURSORICONINFO info;
18 * The bits structures are in the format of a device-dependent bitmap.
20 * This layout is very sub-optimal, as the bitmap bits are stored in
21 * the X client instead of in the server like other bitmaps; however,
22 * some programs (notably Paint Brush) expect to be able to manipulate
23 * the bits directly :-(
31 #include "cursoricon.h"
32 #include "sysmetrics.h"
36 #include "resource32.h"
43 /**********************************************************************
44 * CURSORICON32_FindBestIcon
46 * Find the icon closest to the requested size and number of colors.
48 static ICONDIRENTRY32
*CURSORICON32_FindBestIcon( CURSORICONDIR32
*dir
,
49 int width
, int height
, int colors
)
51 int i
, maxcolors
, maxwidth
, maxheight
;
52 ICONDIRENTRY32
*entry
, *bestEntry
= NULL
;
56 fprintf( stderr
, "Icon: empty directory!\n" );
59 if (dir
->idCount
== 1) return &dir
->idEntries
[0].icon
; /* No choice... */
61 /* First find the exact size with less colors */
64 for (i
= 0, entry
= &dir
->idEntries
[0].icon
; i
< dir
->idCount
; i
++,entry
++)
65 if ((entry
->bWidth
== width
) && (entry
->bHeight
== height
) &&
66 (entry
->bColorCount
<= colors
) && (entry
->bColorCount
> maxcolors
))
69 maxcolors
= entry
->bColorCount
;
71 if (bestEntry
) return bestEntry
;
73 /* First find the exact size with more colors */
76 for (i
= 0, entry
= &dir
->idEntries
[0].icon
; i
< dir
->idCount
; i
++,entry
++)
77 if ((entry
->bWidth
== width
) && (entry
->bHeight
== height
) &&
78 (entry
->bColorCount
> colors
) && (entry
->bColorCount
<= maxcolors
))
81 maxcolors
= entry
->bColorCount
;
83 if (bestEntry
) return bestEntry
;
85 /* Now find a smaller one with less colors */
87 maxcolors
= maxwidth
= maxheight
= 0;
88 for (i
= 0, entry
= &dir
->idEntries
[0].icon
; i
< dir
->idCount
; i
++,entry
++)
89 if ((entry
->bWidth
<= width
) && (entry
->bHeight
<= height
) &&
90 (entry
->bWidth
>= maxwidth
) && (entry
->bHeight
>= maxheight
) &&
91 (entry
->bColorCount
<= colors
) && (entry
->bColorCount
> maxcolors
))
94 maxwidth
= entry
->bWidth
;
95 maxheight
= entry
->bHeight
;
96 maxcolors
= entry
->bColorCount
;
98 if (bestEntry
) return bestEntry
;
100 /* Now find a smaller one with more colors */
103 maxwidth
= maxheight
= 0;
104 for (i
= 0, entry
= &dir
->idEntries
[0].icon
; i
< dir
->idCount
; i
++,entry
++)
105 if ((entry
->bWidth
<= width
) && (entry
->bHeight
<= height
) &&
106 (entry
->bWidth
>= maxwidth
) && (entry
->bHeight
>= maxheight
) &&
107 (entry
->bColorCount
> colors
) && (entry
->bColorCount
<= maxcolors
))
110 maxwidth
= entry
->bWidth
;
111 maxheight
= entry
->bHeight
;
112 maxcolors
= entry
->bColorCount
;
114 if (bestEntry
) return bestEntry
;
116 /* Now find a larger one with less colors */
119 maxwidth
= maxheight
= 255;
120 for (i
= 0, entry
= &dir
->idEntries
[0].icon
; i
< dir
->idCount
; i
++,entry
++)
121 if ((entry
->bWidth
<= maxwidth
) && (entry
->bHeight
<= maxheight
) &&
122 (entry
->bColorCount
<= colors
) && (entry
->bColorCount
> maxcolors
))
125 maxwidth
= entry
->bWidth
;
126 maxheight
= entry
->bHeight
;
127 maxcolors
= entry
->bColorCount
;
129 if (bestEntry
) return bestEntry
;
131 /* Now find a larger one with more colors */
133 maxcolors
= maxwidth
= maxheight
= 255;
134 for (i
= 0, entry
= &dir
->idEntries
[0].icon
; i
< dir
->idCount
; i
++,entry
++)
135 if ((entry
->bWidth
<= maxwidth
) && (entry
->bHeight
<= maxheight
) &&
136 (entry
->bColorCount
> colors
) && (entry
->bColorCount
<= maxcolors
))
139 maxwidth
= entry
->bWidth
;
140 maxheight
= entry
->bHeight
;
141 maxcolors
= entry
->bColorCount
;
148 /**********************************************************************
149 * CURSORICON32_FindBestCursor
151 * Find the cursor closest to the requested size.
153 static CURSORDIRENTRY32
*CURSORICON32_FindBestCursor( CURSORICONDIR32
*dir
,
154 int width
, int height
)
156 int i
, maxwidth
, maxheight
;
157 CURSORDIRENTRY32
*entry
, *bestEntry
= NULL
;
159 if (dir
->idCount
< 1)
161 fprintf( stderr
, "Cursor: empty directory!\n" );
164 if (dir
->idCount
== 1) return &dir
->idEntries
[0].cursor
; /* No choice... */
166 /* First find the largest one smaller than or equal to the requested size*/
168 maxwidth
= maxheight
= 0;
169 for(i
= 0,entry
= &dir
->idEntries
[0].cursor
; i
< dir
->idCount
; i
++,entry
++)
170 if ((entry
->wWidth
<= width
) && (entry
->wHeight
<= height
) &&
171 (entry
->wWidth
> maxwidth
) && (entry
->wHeight
> maxheight
))
174 maxwidth
= entry
->wWidth
;
175 maxheight
= entry
->wHeight
;
177 if (bestEntry
) return bestEntry
;
179 /* Now find the smallest one larger than the requested size */
181 maxwidth
= maxheight
= 255;
182 for(i
= 0,entry
= &dir
->idEntries
[0].cursor
; i
< dir
->idCount
; i
++,entry
++)
183 if ((entry
->wWidth
< maxwidth
) && (entry
->wHeight
< maxheight
))
186 maxwidth
= entry
->wWidth
;
187 maxheight
= entry
->wHeight
;
194 /**********************************************************************
195 * CURSORICON32_LoadDirEntry
197 * Load the icon/cursor directory for a given resource name and find the
198 * best matching entry.
200 static BOOL
CURSORICON32_LoadDirEntry(HANDLE hInstance
, LPCWSTR name
,
201 int width
, int height
, int colors
,
202 BOOL fCursor
, CURSORICONDIRENTRY32
*dirEntry
)
206 CURSORICONDIR32
*dir
;
207 CURSORICONDIRENTRY32
*entry
= NULL
;
209 if (!(hRsrc
= FindResource32( hInstance
, name
,
210 (LPCWSTR
)(fCursor
? RT_GROUP_CURSOR
: RT_GROUP_ICON
) )))
212 if (!(hMem
= LoadResource32( hInstance
, hRsrc
))) return FALSE
;
213 if ((dir
= (CURSORICONDIR32
*)LockResource32( hMem
)))
216 entry
= (CURSORICONDIRENTRY32
*)CURSORICON32_FindBestCursor( dir
,
219 entry
= (CURSORICONDIRENTRY32
*)CURSORICON32_FindBestIcon( dir
,
220 width
, height
, colors
);
221 if (entry
) *dirEntry
= *entry
;
223 FreeResource32( hMem
);
224 return (entry
!= NULL
);
228 /**********************************************************************
229 * CURSORICON32_LoadHandler
231 * Create a cursor or icon from a resource.
233 static HANDLE
CURSORICON32_LoadHandler( HANDLE32 handle
, HINSTANCE hInstance
,
236 HANDLE hAndBits
, hXorBits
, hRes
;
238 int size
, sizeAnd
, sizeXor
;
239 POINT hotspot
= { 0 ,0 };
240 BITMAPOBJ
*bmpXor
, *bmpAnd
;
241 BITMAPINFO
*bmi
, *pInfo
;
242 CURSORICONINFO
*info
;
246 if (fCursor
) /* If cursor, get the hotspot */
248 POINT
*pt
= (POINT
*)LockResource32( handle
);
250 bmi
= (BITMAPINFO
*)(pt
+ 1);
252 else bmi
= (BITMAPINFO
*)LockResource32( handle
);
254 /* Create a copy of the bitmap header */
256 size
= DIB_BitmapInfoSize( bmi
, DIB_RGB_COLORS
);
257 /* Make sure we have room for the monochrome bitmap later on */
258 size
= MAX( size
, sizeof(BITMAPINFOHEADER
) + 2*sizeof(RGBQUAD
) );
259 pInfo
= (BITMAPINFO
*)xmalloc( size
);
260 memcpy( pInfo
, bmi
, size
);
262 if (pInfo
->bmiHeader
.biSize
== sizeof(BITMAPINFOHEADER
))
264 if (pInfo
->bmiHeader
.biCompression
!= BI_RGB
)
266 fprintf(stderr
,"Unknown size for compressed icon bitmap.\n");
270 pInfo
->bmiHeader
.biHeight
/= 2;
272 else if (pInfo
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
274 BITMAPCOREHEADER
*core
= (BITMAPCOREHEADER
*)pInfo
;
279 fprintf( stderr
, "CURSORICON32_Load: Unknown bitmap length %ld!\n",
280 pInfo
->bmiHeader
.biSize
);
285 /* Create the XOR bitmap */
287 if (!(hdc
= GetDC( 0 )))
293 hXorBits
= CreateDIBitmap( hdc
, &pInfo
->bmiHeader
, CBM_INIT
,
294 (char*)bmi
+ size
, pInfo
, DIB_RGB_COLORS
);
296 /* Fix the bitmap header to load the monochrome mask */
298 if (pInfo
->bmiHeader
.biSize
== sizeof(BITMAPINFOHEADER
))
300 BITMAPINFOHEADER
*bih
= &pInfo
->bmiHeader
;
301 RGBQUAD
*rgb
= pInfo
->bmiColors
;
302 bits
= (char *)bmi
+ size
+
303 DIB_GetImageWidthBytes(bih
->biWidth
,bih
->biBitCount
)*bih
->biHeight
;
305 bih
->biClrUsed
= bih
->biClrImportant
= 2;
306 rgb
[0].rgbBlue
= rgb
[0].rgbGreen
= rgb
[0].rgbRed
= 0x00;
307 rgb
[1].rgbBlue
= rgb
[1].rgbGreen
= rgb
[1].rgbRed
= 0xff;
308 rgb
[0].rgbReserved
= rgb
[1].rgbReserved
= 0;
312 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)pInfo
;
313 RGBTRIPLE
*rgb
= (RGBTRIPLE
*)(bch
+ 1);
314 bits
= (char *)bmi
+ size
+
315 DIB_GetImageWidthBytes(bch
->bcWidth
,bch
->bcBitCount
)*bch
->bcHeight
;
317 rgb
[0].rgbtBlue
= rgb
[0].rgbtGreen
= rgb
[0].rgbtRed
= 0x00;
318 rgb
[1].rgbtBlue
= rgb
[1].rgbtGreen
= rgb
[1].rgbtRed
= 0xff;
321 /* Create the AND bitmap */
323 hAndBits
= CreateDIBitmap( hdc
, &pInfo
->bmiHeader
, CBM_INIT
,
324 bits
, pInfo
, DIB_RGB_COLORS
);
327 /* Now create the CURSORICONINFO structure */
329 bmpXor
= (BITMAPOBJ
*) GDI_GetObjPtr( hXorBits
, BITMAP_MAGIC
);
330 bmpAnd
= (BITMAPOBJ
*) GDI_GetObjPtr( hAndBits
, BITMAP_MAGIC
);
331 sizeXor
= bmpXor
->bitmap
.bmHeight
* bmpXor
->bitmap
.bmWidthBytes
;
332 sizeAnd
= bmpAnd
->bitmap
.bmHeight
* bmpAnd
->bitmap
.bmWidthBytes
;
334 if (!(hRes
= GlobalAlloc( GMEM_MOVEABLE
,
335 sizeof(CURSORICONINFO
) + sizeXor
+ sizeAnd
)))
337 DeleteObject( hXorBits
);
338 DeleteObject( hAndBits
);
342 /* Make it owned by the module */
343 if (hInstance
) FarSetOwner( hRes
, (WORD
)(DWORD
)GetExePtr(hInstance
) );
345 info
= (CURSORICONINFO
*)GlobalLock( hRes
);
346 info
->ptHotSpot
.x
= hotspot
.x
;
347 info
->ptHotSpot
.y
= hotspot
.y
;
348 info
->nWidth
= bmpXor
->bitmap
.bmWidth
;
349 info
->nHeight
= bmpXor
->bitmap
.bmHeight
;
350 info
->nWidthBytes
= bmpXor
->bitmap
.bmWidthBytes
;
351 info
->bPlanes
= bmpXor
->bitmap
.bmPlanes
;
352 info
->bBitsPerPixel
= bmpXor
->bitmap
.bmBitsPixel
;
354 /* Transfer the bitmap bits to the CURSORICONINFO structure */
356 GetBitmapBits( hAndBits
, sizeAnd
, (char *)(info
+ 1) );
357 GetBitmapBits( hXorBits
, sizeXor
, (char *)(info
+ 1) + sizeAnd
);
358 DeleteObject( hXorBits
);
359 DeleteObject( hAndBits
);
360 GlobalUnlock( hRes
);
364 /**********************************************************************
367 * Load a cursor or icon.
369 static HANDLE
CURSORICON32_Load( HANDLE hInstance
, LPCWSTR name
, int width
,
370 int height
, int colors
, BOOL fCursor
)
375 CURSORICONDIRENTRY32 dirEntry
;
377 if(!hInstance
) /* OEM cursor/icon */
383 ansi
=STRING32_DupUniToAnsi(name
);
384 if(ansi
[0]=='#') /*Check for '#xxx' name */
394 resid
=(WORD
)(int)name
;
395 return OBM_LoadCursorIcon(resid
, fCursor
);
398 /* Find the best entry in the directory */
400 if (!CURSORICON32_LoadDirEntry( hInstance
, name
, width
, height
,
401 colors
, fCursor
, &dirEntry
)) return 0;
403 /* Load the resource */
405 if (!(hRsrc
= FindResource32( hInstance
,
406 (LPWSTR
) (DWORD
) dirEntry
.icon
.wResId
,
407 (LPWSTR
) (fCursor
? RT_CURSOR
: RT_ICON
)))) return 0;
408 if (!(handle
= LoadResource32( hInstance
, hRsrc
))) return 0;
410 hRet
= CURSORICON32_LoadHandler( handle
, hInstance
, fCursor
);
411 FreeResource32(handle
);
416 /***********************************************************************
419 HCURSOR
WIN32_LoadCursorW( HANDLE hInstance
, LPCWSTR name
)
421 return CURSORICON32_Load( hInstance
, name
,
422 SYSMETRICS_CXCURSOR
, SYSMETRICS_CYCURSOR
, 1, TRUE
);
425 HCURSOR
WIN32_LoadCursorA(HANDLE hInstance
, LPCSTR name
)
429 return WIN32_LoadCursorW(hInstance
, name
);
431 LPWSTR uni
= STRING32_DupAnsiToUni(name
);
432 res
= WIN32_LoadCursorW(hInstance
, uni
);
439 /***********************************************************************
442 HICON
WIN32_LoadIconW( HANDLE hInstance
, LPCWSTR name
)
444 return CURSORICON32_Load( hInstance
, name
,
445 SYSMETRICS_CXICON
, SYSMETRICS_CYICON
,
446 MIN( 16, 1 << screenDepth
), FALSE
);
449 HICON
WIN32_LoadIconA( HANDLE hInstance
, LPCSTR name
)
453 return WIN32_LoadIconW(hInstance
, name
);
455 LPWSTR uni
= STRING32_DupAnsiToUni(name
);
456 res
= WIN32_LoadIconW(hInstance
, uni
);