source: trunk/src/user32/winicon.cpp@ 1810

Last change on this file since 1810 was 1810, checked in by sandervl, 26 years ago

EB's fixes + removal of GetIconInfo hack

File size: 15.4 KB
Line 
1/* $Id: winicon.cpp,v 1.5 1999-11-22 20:33:25 sandervl Exp $ */
2/*
3 * Win32 Icon Code for OS/2
4 *
5 *
6 * Copyright 1998 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 * Parts based on Wine code (objects\bitmap.c, loader\resource.c, objects\cursoricon.c):
9 *
10 * Copyright 1993 Alexandre Julliard
11 * 1993 Robert J. Amstadt
12 * 1996 Martin Von Loewis
13 * 1997 Alex Korobka
14 * 1998 Turchanov Sergey
15 * 1998 Huw D M Davies
16 *
17 * Project Odin Software License can be found in LICENSE.TXT
18 *
19 */
20#include <os2win.h>
21#include <winicon.h>
22#include <win\cursoricon.h>
23
24//******************************************************************************
25//******************************************************************************
26HICON WIN32API CreateIcon( HINSTANCE arg1, INT arg2, INT arg3, BYTE arg4, BYTE arg5, LPCVOID arg6, LPCVOID arg7)
27{
28#ifdef DEBUG
29 WriteLog("USER32: CreateIcon\n");
30#endif
31 return O32_CreateIcon(arg1, arg2, arg3, arg4, arg5, (const BYTE *)arg6, (const BYTE *)arg7);
32}
33//******************************************************************************
34//ASSERT dwVer == win31 (ok according to SDK docs)
35//******************************************************************************
36HICON WIN32API CreateIconFromResource(PBYTE presbits, UINT dwResSize,
37 BOOL fIcon, DWORD dwVer)
38{
39 HICON hicon;
40 DWORD OS2ResSize = 0;
41 PBYTE OS2Icon = ConvertWin32Icon(presbits, dwResSize, &OS2ResSize);
42
43 hicon = O32_CreateIconFromResource(OS2Icon, OS2ResSize, fIcon, dwVer);
44#ifdef DEBUG
45 WriteLog("USER32: CreateIconFromResource returned %X (%X)\n", hicon, GetLastError());
46#endif
47 if(OS2Icon)
48 FreeIcon(OS2Icon);
49
50 return(hicon);
51}
52//******************************************************************************
53//******************************************************************************
54HICON WIN32API CreateIconFromResourceEx(PBYTE presbits, UINT dwResSize,
55 BOOL fIcon, DWORD dwVer,
56 int cxDesired, int cyDesired,
57 UINT Flags)
58{
59#ifdef DEBUG
60 WriteLog("USER32: CreateIconFromResourceEx %X %d %d %X %d %d %X, not completely supported!\n", presbits, dwResSize, fIcon, dwVer, cxDesired, cyDesired, Flags);
61#endif
62 return CreateIconFromResource(presbits, dwResSize, fIcon, dwVer);
63}
64//******************************************************************************
65//******************************************************************************
66HICON WIN32API CreateIconIndirect(LPICONINFO pIcon)
67{
68 HICON hIcon;
69 HDC hdcSrc, hdcDst;
70
71 dprintf(("USER32: CreateIconIndirect\n"));
72 if(pIcon->hbmMask && pIcon->hbmColor)
73 {
74 ICONINFO iconinfo;
75 SIZE bmpsize;
76
77 iconinfo = *pIcon;
78 if(GetBitmapDimensionEx(pIcon->hbmColor, &bmpsize) == FALSE) {
79 return 0;
80 }
81 //if there's a color bitmap, the mask bitmap contains only the AND bits
82 //Open32 calls WinCreatePointerIndirect which expects AND & XOR bits
83 //To solve this we create a bitmap that's 2x height of the mask, copy
84 //the AND bits and set the XOR bits to 0
85 hdcSrc = CreateCompatibleDC(0);
86 hdcDst = CreateCompatibleDC(0);
87
88 iconinfo.hbmMask = CreateCompatibleBitmap (hdcDst, bmpsize.cx, bmpsize.cy*2);
89 SelectObject (hdcDst, iconinfo.hbmMask);
90 SelectObject (hdcSrc, pIcon->hbmMask);
91 BitBlt (hdcDst, 0, 0, bmpsize.cx, bmpsize.cy,
92 hdcSrc, 0, 0, SRCCOPY);
93 PatBlt (hdcDst, bmpsize.cx, bmpsize.cy, bmpsize.cx, bmpsize.cy, BLACKNESS);
94
95 hIcon = O32_CreateIconIndirect(&iconinfo);
96
97 DeleteObject(iconinfo.hbmMask);
98 DeleteDC(hdcSrc);
99 DeleteDC(hdcDst);
100
101 return hIcon;
102 }
103 hIcon = O32_CreateIconIndirect(pIcon);
104 if(hIcon == 0) {
105 dprintf(("CreateIconIndirect %d (%d,%d) %x %x failed with %x", pIcon->fIcon, pIcon->xHotspot, pIcon->yHotspot, pIcon->hbmMask, pIcon->hbmColor, GetLastError()));
106 }
107 return hIcon;
108}
109//******************************************************************************
110//******************************************************************************
111HICON CreateIconIndirect(LPICONINFO pIcon, BOOL bIsIcon, int desiredX, int desiredY, DWORD flags)
112{
113 HICON hIcon;
114 HDC hdcSrc, hdcDst;
115 BITMAP bmp;
116
117 if(pIcon->hbmMask && pIcon->hbmColor)
118 {
119 ICONINFO iconinfo;
120 HBITMAP hbmOldSrc, hbmOldDst;
121
122 iconinfo = *pIcon;
123 GetObjectA(pIcon->hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
124
125 //if there's a color bitmap, the mask bitmap contains only the AND bits
126 //Open32 calls WinCreatePointerIndirect which expects AND & XOR bits
127 //To solve this we create a bitmap that's 2x height of the mask, copy
128 //the AND bits and set the XOR bits to 0
129 hdcSrc = CreateCompatibleDC(0);
130 hdcDst = CreateCompatibleDC(0);
131
132 iconinfo.hbmMask = CreateCompatibleBitmap (hdcDst, desiredX, desiredY*2);
133 hbmOldDst = SelectObject (hdcDst, iconinfo.hbmMask);
134 hbmOldSrc = SelectObject (hdcSrc, pIcon->hbmMask);
135 if(desiredX != bmp.bmWidth || desiredY != bmp.bmHeight) {
136 StretchBlt(hdcDst, 0, 0, desiredX, desiredY, hdcSrc, 0, 0,
137 bmp.bmWidth, bmp.bmHeight, SRCCOPY);
138 }
139 else {
140 BitBlt (hdcDst, 0, 0, bmp.bmWidth, bmp.bmHeight,
141 hdcSrc, 0, 0, SRCCOPY);
142 }
143 PatBlt (hdcDst, desiredX, desiredY, desiredX, desiredY, BLACKNESS);
144
145 if(desiredX != bmp.bmWidth || desiredY != bmp.bmHeight) {
146 iconinfo.hbmColor = CreateCompatibleBitmap (hdcDst, desiredX, desiredY);
147 SelectObject (hdcDst, iconinfo.hbmColor);
148 SelectObject (hdcSrc, pIcon->hbmColor);
149 StretchBlt(hdcDst, 0, 0, desiredX, desiredY, hdcSrc, 0, 0,
150 bmp.bmWidth, bmp.bmHeight, SRCCOPY);
151 }
152
153 hIcon = O32_CreateIconIndirect(&iconinfo);
154
155 DeleteObject(iconinfo.hbmMask);
156 if(desiredX != bmp.bmWidth || desiredY != bmp.bmHeight) {
157 DeleteObject(iconinfo.hbmColor);
158 }
159 SelectObject (hdcDst, hbmOldDst);
160 SelectObject (hdcSrc, hbmOldSrc);
161 DeleteDC(hdcSrc);
162 DeleteDC(hdcDst);
163
164 return hIcon;
165 }
166 hIcon = O32_CreateIconIndirect(pIcon);
167 if(hIcon == 0) {
168 dprintf(("CreateIconIndirect %d (%d,%d) %x %x failed with %x", pIcon->fIcon, pIcon->xHotspot, pIcon->yHotspot, pIcon->hbmMask, pIcon->hbmColor, GetLastError()));
169 }
170 return hIcon;
171}
172//******************************************************************************
173//******************************************************************************
174BOOL WIN32API DestroyIcon( HICON hIcon)
175{
176 dprintf(("USER32: DestroyIcon %x", hIcon));
177 return O32_DestroyIcon(hIcon);
178}
179//******************************************************************************
180//******************************************************************************
181HICON WIN32API CopyIcon( HICON hIcon)
182{
183 dprintf(("USER32: CopyIcon %x", hIcon));
184 return O32_CopyIcon(hIcon);
185}
186//******************************************************************************
187//WARNING: MEMORY LEAK & DIRTY HACK TO WORK AROUND OPEN32 BUG
188//OS/2 icon masks must be twice the height of the color bitmap
189//In Windows, the mask only contains the AND data if there's a color bitmap
190//--->> We're allocating a bitmap to replace the mask bitmap, but DON'T DELETE it!
191//WARNING: MEMORY LEAK & DIRTY HACK TO WORK AROUND OPEN32 BUG
192//******************************************************************************
193BOOL WIN32API GetIconInfo( HICON hIcon, LPICONINFO pIconInfo)
194{
195 BOOL rc;
196 HBITMAP hbmMask, hbmOldSrc, hbmOldDst;
197 BITMAP bmp;
198
199 dprintf(("USER32: GetIconInfo %x", hIcon));
200 rc = O32_GetIconInfo(hIcon, pIconInfo);
201#if 0
202 if(rc && pIconInfo->hbmColor)
203 {
204 HDC hdcSrc, hdcDst;
205 hdcSrc = CreateCompatibleDC(0);
206 hdcDst = CreateCompatibleDC(0);
207
208 GetObjectA(pIconInfo->hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
209
210 hbmMask = CreateCompatibleBitmap (hdcDst, bmp.bmWidth, bmp.bmHeight/2);
211 hbmOldDst = SelectObject (hdcDst, hbmMask);
212 hbmOldSrc = SelectObject (hdcSrc, pIconInfo->hbmMask);
213 BitBlt (hdcDst, 0, 0, bmp.bmWidth, bmp.bmHeight/2,
214 hdcSrc, 0, bmp.bmHeight/2, SRCCOPY);
215
216 SelectObject(hdcDst, hbmOldDst);
217 SelectObject(hdcSrc, hbmOldSrc);
218 DeleteDC(hdcDst);
219 DeleteDC(hdcSrc);
220 pIconInfo->hbmMask = hbmMask;
221 }
222#endif
223 return rc;
224}
225/**********************************************************************
226 * CURSORICON_FindBestIcon
227 *
228 * Find the icon closest to the requested size and number of colors.
229 */
230static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
231 int height, int colors )
232{
233 int i;
234 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
235 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
236 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
237
238 if (dir->idCount < 1)
239 {
240 dprintf(("Empty directory!\n" ));
241 return NULL;
242 }
243 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
244
245 /* Find Best Fit */
246 iTotalDiff = 0xFFFFFFFF;
247 iColorDiff = 0xFFFFFFFF;
248 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
249 {
250 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
251 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
252
253 if(iTotalDiff > (iTempXDiff + iTempYDiff))
254 {
255 iXDiff = iTempXDiff;
256 iYDiff = iTempYDiff;
257 iTotalDiff = iXDiff + iYDiff;
258 }
259 }
260
261 /* Find Best Colors for Best Fit */
262 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
263 {
264 if(abs(width - entry->ResInfo.icon.bWidth) == iXDiff &&
265 abs(height - entry->ResInfo.icon.bHeight) == iYDiff)
266 {
267 iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
268 if(iColorDiff > iTempColorDiff)
269 {
270 bestEntry = entry;
271 iColorDiff = iTempColorDiff;
272 }
273 }
274 }
275
276 return bestEntry;
277}
278
279
280/**********************************************************************
281 * CURSORICON_FindBestCursor
282 *
283 * Find the cursor closest to the requested size.
284 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
285 * ignored too
286 */
287static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
288 int width, int height, int color)
289{
290 int i, maxwidth, maxheight;
291 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
292
293 if (dir->idCount < 1)
294 {
295 dprintf(("Empty directory!\n" ));
296 return NULL;
297 }
298 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
299
300 /* Double height to account for AND and XOR masks */
301
302 height *= 2;
303
304 /* First find the largest one smaller than or equal to the requested size*/
305
306 maxwidth = maxheight = 0;
307 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
308 if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
309 (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
310 (entry->wBitCount == 1))
311 {
312 bestEntry = entry;
313 maxwidth = entry->ResInfo.cursor.wWidth;
314 maxheight = entry->ResInfo.cursor.wHeight;
315 }
316 if (bestEntry) return bestEntry;
317
318 /* Now find the smallest one larger than the requested size */
319
320 maxwidth = maxheight = 255;
321 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
322 if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
323 (entry->wBitCount == 1))
324 {
325 bestEntry = entry;
326 maxwidth = entry->ResInfo.cursor.wWidth;
327 maxheight = entry->ResInfo.cursor.wHeight;
328 }
329
330 return bestEntry;
331}
332/**********************************************************************
333 * LookupIconIdFromDirectoryEx16 (USER.364)
334 *
335 * FIXME: exact parameter sizes
336 */
337INT WIN32API LookupIconIdFromDirectoryEx(LPBYTE xdir, BOOL bIcon,
338 INT width, INT height, UINT cFlag )
339{
340 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
341 UINT retVal = 0;
342
343 dprintf(("LookupIconIdFromDirectoryEx %x %d (%d,%d)", xdir, bIcon, width, height));
344 if( dir && !dir->idReserved && (dir->idType & 3) )
345 {
346 CURSORICONDIRENTRY* entry;
347 HDC hdc;
348 UINT palEnts;
349 int colors;
350 hdc = GetDC(0);
351 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
352 if (palEnts == 0)
353 palEnts = 256;
354 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
355
356 ReleaseDC(0, hdc);
357
358 if( bIcon )
359 entry = CURSORICON_FindBestIcon( dir, width, height, colors );
360 else
361 entry = CURSORICON_FindBestCursor( dir, width, height, 1);
362
363 if( entry ) retVal = entry->wResId;
364 }
365 else dprintf(("invalid resource directory\n"));
366 return retVal;
367}
368/**********************************************************************
369 * LookupIconIdFromDirectory (USER32.379)
370 */
371INT WIN32API LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
372{
373 return LookupIconIdFromDirectoryEx( dir, bIcon,
374 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
375 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
376}
377/*************************************************************************
378 * CURSORICON_ExtCopy
379 *
380 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
381 *
382 * PARAMS
383 * Handle [I] handle to an Image
384 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
385 * iDesiredCX [I] The Desired width of the Image
386 * iDesiredCY [I] The desired height of the Image
387 * nFlags [I] The flags from CopyImage
388 *
389 * RETURNS
390 * Success: The new handle of the Image
391 *
392 * NOTES
393 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
394 * LR_MONOCHROME should be implemented by CURSORICON_CreateFromResource.
395 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
396 *
397 *
398 * TODO: LR_COPYFROMRESOURCE doesn't work. Uses supplied icon instead
399 *
400 */
401HGLOBAL CopyCursorIcon(HGLOBAL Handle, UINT nType,
402 INT iDesiredCX, INT iDesiredCY,
403 UINT nFlags)
404{
405 HGLOBAL hNew=0;
406 BOOL bIsIcon = (nType == IMAGE_ICON);
407
408 if(Handle == 0)
409 {
410 return 0;
411 }
412
413 /* Best Fit or Monochrome */
414 if(!bIsIcon || (nFlags & LR_COPYFROMRESOURCE
415 && (iDesiredCX > 0 || iDesiredCY > 0))
416 || nFlags & LR_MONOCHROME)
417 {
418 LPBYTE pBits;
419 HANDLE hMem;
420 HRSRC hRsrc;
421 DWORD dwBytesInRes;
422 WORD wResId;
423 CURSORICONDIR *pDir;
424 CURSORICONDIRENTRY *pDirEntry;
425
426 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
427 */
428 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
429 || (iDesiredCX == 0 && iDesiredCY == 0))
430 {
431 iDesiredCY = GetSystemMetrics(bIsIcon ?
432 SM_CYICON : SM_CYCURSOR);
433 iDesiredCX = GetSystemMetrics(bIsIcon ?
434 SM_CXICON : SM_CXCURSOR);
435 }
436
437 /* Create a New Icon with the proper dimension
438 */
439 ICONINFO iconinfo;
440
441 GetIconInfo(Handle, &iconinfo);
442 hNew = CreateIconIndirect(&iconinfo, bIsIcon, iDesiredCX, iDesiredCY, nFlags);
443 }
444 else
445 {
446 if(bIsIcon) {
447 return CopyIcon(Handle);
448 }
449 else return CopyCursor(Handle);
450 }
451 return hNew;
452}
453//******************************************************************************
454//******************************************************************************
Note: See TracBrowser for help on using the repository browser.