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

Last change on this file since 2160 was 2160, checked in by cbratschi, 26 years ago

some icon bug fixes

File size: 16.0 KB
Line 
1/* $Id: winicon.cpp,v 1.6 1999-12-20 16:45:18 cbratschi 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: 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 1
202 if(rc && pIconInfo->hbmColor)
203 {
204 HDC hdcSrc, hdcDst;
205 hdcSrc = CreateCompatibleDC(0);
206 hdcDst = CreateCompatibleDC(0);
207
208 GetObjectA(pIconInfo->hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
209
210 hbmMask = CreateCompatibleBitmap (hdcDst, bmp.bmWidth, bmp.bmHeight);
211 hbmOldDst = SelectObject (hdcDst, hbmMask);
212 hbmOldSrc = SelectObject (hdcSrc, pIconInfo->hbmMask);
213 BitBlt (hdcDst, 0, 0, bmp.bmWidth, bmp.bmHeight,
214 hdcSrc, 0, 0, SRCCOPY);
215
216 SelectObject(hdcDst, hbmOldDst);
217 SelectObject(hdcSrc, hbmOldSrc);
218 DeleteDC(hdcDst);
219 DeleteDC(hdcSrc);
220 DeleteObject(pIconInfo->hbmMask);
221 pIconInfo->hbmMask = hbmMask;
222 }
223#endif
224 return rc;
225}
226/**********************************************************************
227 * CURSORICON_FindBestIcon
228 *
229 * Find the icon closest to the requested size and number of colors.
230 */
231static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
232 int height, int colors )
233{
234 int i;
235 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
236 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
237 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
238
239 if (dir->idCount < 1)
240 {
241 dprintf(("Empty directory!\n" ));
242 return NULL;
243 }
244 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
245
246 /* Find Best Fit */
247 iTotalDiff = 0xFFFFFFFF;
248 iColorDiff = 0xFFFFFFFF;
249 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
250 {
251 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
252 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
253
254 if(iTotalDiff > (iTempXDiff + iTempYDiff))
255 {
256 iXDiff = iTempXDiff;
257 iYDiff = iTempYDiff;
258 iTotalDiff = iXDiff + iYDiff;
259 }
260 }
261
262 /* Find Best Colors for Best Fit */
263 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
264 {
265 if(abs(width - entry->ResInfo.icon.bWidth) == iXDiff &&
266 abs(height - entry->ResInfo.icon.bHeight) == iYDiff)
267 {
268 iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
269 if(iColorDiff > iTempColorDiff)
270 {
271 bestEntry = entry;
272 iColorDiff = iTempColorDiff;
273 }
274 }
275 }
276
277 return bestEntry;
278}
279
280
281/**********************************************************************
282 * CURSORICON_FindBestCursor
283 *
284 * Find the cursor closest to the requested size.
285 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
286 * ignored too
287 */
288static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
289 int width, int height, int color)
290{
291 int i, maxwidth, maxheight;
292 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
293
294 if (dir->idCount < 1)
295 {
296 dprintf(("Empty directory!\n" ));
297 return NULL;
298 }
299 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
300
301 /* Double height to account for AND and XOR masks */
302
303 height *= 2;
304
305 /* First find the largest one smaller than or equal to the requested size*/
306
307 maxwidth = maxheight = 0;
308 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
309 if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
310 (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
311 (entry->wBitCount == 1))
312 {
313 bestEntry = entry;
314 maxwidth = entry->ResInfo.cursor.wWidth;
315 maxheight = entry->ResInfo.cursor.wHeight;
316 }
317 if (bestEntry) return bestEntry;
318
319 /* Now find the smallest one larger than the requested size */
320
321 maxwidth = maxheight = 255;
322 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
323 if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
324 (entry->wBitCount == 1))
325 {
326 bestEntry = entry;
327 maxwidth = entry->ResInfo.cursor.wWidth;
328 maxheight = entry->ResInfo.cursor.wHeight;
329 }
330
331 return bestEntry;
332}
333/**********************************************************************
334 * LookupIconIdFromDirectoryEx16 (USER.364)
335 *
336 * FIXME: exact parameter sizes
337 */
338INT WIN32API LookupIconIdFromDirectoryEx(LPBYTE xdir, BOOL bIcon,
339 INT width, INT height, UINT cFlag )
340{
341 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
342 UINT retVal = 0;
343
344 dprintf(("LookupIconIdFromDirectoryEx %x %d (%d,%d)", xdir, bIcon, width, height));
345 if( dir && !dir->idReserved && (dir->idType & 3) )
346 {
347 CURSORICONDIRENTRY* entry;
348 HDC hdc;
349 UINT palEnts;
350 int colors;
351 hdc = GetDC(0);
352 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
353 if (palEnts == 0)
354 palEnts = 256;
355 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
356
357 ReleaseDC(0, hdc);
358
359 if( bIcon )
360 entry = CURSORICON_FindBestIcon( dir, width, height, colors );
361 else
362 entry = CURSORICON_FindBestCursor( dir, width, height, 1);
363
364 if( entry ) retVal = entry->wResId;
365 }
366 else dprintf(("invalid resource directory\n"));
367 return retVal;
368}
369/**********************************************************************
370 * LookupIconIdFromDirectory (USER32.379)
371 */
372INT WIN32API LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
373{
374 return LookupIconIdFromDirectoryEx( dir, bIcon,
375 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
376 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
377}
378/*************************************************************************
379 * CURSORICON_ExtCopy
380 *
381 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
382 *
383 * PARAMS
384 * Handle [I] handle to an Image
385 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
386 * iDesiredCX [I] The Desired width of the Image
387 * iDesiredCY [I] The desired height of the Image
388 * nFlags [I] The flags from CopyImage
389 *
390 * RETURNS
391 * Success: The new handle of the Image
392 *
393 * NOTES
394 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
395 * LR_MONOCHROME should be implemented by CURSORICON_CreateFromResource.
396 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
397 *
398 *
399 * TODO: LR_COPYFROMRESOURCE doesn't work. Uses supplied icon instead
400 *
401 */
402HGLOBAL CopyCursorIcon(HGLOBAL Handle, UINT nType,
403 INT iDesiredCX, INT iDesiredCY,
404 UINT nFlags)
405{
406 HGLOBAL hNew=0;
407 BOOL bIsIcon = (nType == IMAGE_ICON);
408
409 if(Handle == 0)
410 {
411 return 0;
412 }
413
414 /* Best Fit or Monochrome */
415 if(!bIsIcon || (nFlags & LR_COPYFROMRESOURCE
416 && (iDesiredCX > 0 || iDesiredCY > 0))
417 || nFlags & LR_MONOCHROME)
418 {
419 LPBYTE pBits;
420 HANDLE hMem;
421 HRSRC hRsrc;
422 DWORD dwBytesInRes;
423 WORD wResId;
424 CURSORICONDIR *pDir;
425 CURSORICONDIRENTRY *pDirEntry;
426
427 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
428 */
429 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
430 || (iDesiredCX == 0 && iDesiredCY == 0))
431 {
432 iDesiredCY = GetSystemMetrics(bIsIcon ?
433 SM_CYICON : SM_CYCURSOR);
434 iDesiredCX = GetSystemMetrics(bIsIcon ?
435 SM_CXICON : SM_CXCURSOR);
436 }
437
438 /* Create a New Icon with the proper dimension
439 */
440 ICONINFO iconinfo;
441
442 GetIconInfo(Handle, &iconinfo);
443 hNew = CreateIconIndirect(&iconinfo, bIsIcon, iDesiredCX, iDesiredCY, nFlags);
444 }
445 else
446 {
447 if(bIsIcon) {
448 return CopyIcon(Handle);
449 }
450 else return CopyCursor(Handle);
451 }
452 return hNew;
453}
454//******************************************************************************
455//******************************************************************************
Note: See TracBrowser for help on using the repository browser.