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

Last change on this file since 5487 was 5482, checked in by sandervl, 24 years ago

rewrote ShowCursor

File size: 54.3 KB
Line 
1/* $Id: winicon.cpp,v 1.21 2001-04-05 09:31:28 sandervl Exp $ */
2/*
3 * Win32 Icon Code for OS/2
4 *
5 *
6 * Copyright 1998 Sander van Leeuwen (sandervl@xs4all.nl) (OS/2 Port)
7 *
8 * 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 * Theory:
17 *
18 * http://www.microsoft.com/win32dev/ui/icons.htm
19 *
20 * Cursors and icons are stored in a global heap block, with the
21 * following layout:
22 *
23 * CURSORICONINFO info;
24 * BYTE[] ANDbits;
25 * BYTE[] XORbits;
26 *
27 * The bits structures are in the format of a device-dependent bitmap.
28 *
29 * This layout is very sub-optimal, as the bitmap bits are stored in
30 * the X client instead of in the server like other bitmaps; however,
31 * some programs (notably Paint Brush) expect to be able to manipulate
32 * the bits directly :-(
33 *
34 * FIXME: what are we going to do with animation and color (bpp > 1) cursors ?!
35 *
36 **************************************************************************************************
37 *
38 * TODO: Scaling of system cursors (store them as resources in user32 instead of using PM pointers)
39 * TODO: We use the hColorBmp member of the CURSORICONINFO structure to store the PM cursor handle
40 * Might mess up PaintBrush (see above)
41 *
42 * Project Odin Software License can be found in LICENSE.TXT
43 *
44 */
45#include <os2win.h>
46#include <stdio.h>
47#include <string.h>
48#include <winicon.h>
49#include <win\cursoricon.h>
50#include "dib.h"
51#include <heapstring.h>
52#include <win\virtual.h>
53#include "initterm.h"
54#include "oslibres.h"
55#include "oslibwin.h"
56#include "dc.h"
57
58#define DBG_LOCALLOG DBG_winicon
59#include "dbglocal.h"
60
61
62/**********************************************************************
63 * ICONCACHE for cursors/icons loaded with LR_SHARED.
64 *
65 * FIXME: This should not be allocated on the system heap, but on a
66 * subsystem-global heap (i.e. one for all Win16 processes,
67 * and one for each Win32 process).
68 */
69typedef struct tagICONCACHE
70{
71 struct tagICONCACHE *next;
72
73 HMODULE hModule;
74 HRSRC hRsrc;
75 HRSRC hGroupRsrc;
76 HANDLE handle;
77 INT count;
78} ICONCACHE;
79
80static ICONCACHE *IconAnchor = NULL;
81static CRITICAL_SECTION IconCrst = CRITICAL_SECTION_INIT;
82static WORD ICON_HOTSPOT = 0x4242;
83static HCURSOR hActiveCursor = 0;
84
85
86static HGLOBAL CURSORICON_CreateFromResource( HINSTANCE hInstance, DWORD dwResGroupId, HGLOBAL hObj, LPBYTE bits,
87 UINT cbSize, BOOL bIcon, DWORD dwVersion, INT width, INT height, UINT loadflags );
88static HGLOBAL CURSORICON_Copy( HGLOBAL handle );
89static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
90 int height, int colors );
91static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
92 int width, int height, int color);
93BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
94 CURSORICONDIR **res, LPBYTE **ptr);
95
96static INT CURSORICON_DelSharedIcon( HANDLE handle );
97static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HANDLE handle );
98static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc );
99static ICONCACHE* CURSORICON_FindCache(HANDLE handle);
100
101/***********************************************************************
102 * CreateIcon (USER32.75)
103 */
104HICON WIN32API CreateIcon(HINSTANCE hInstance, INT nWidth,
105 INT nHeight, BYTE bPlanes, BYTE bBitsPixel,
106 LPCVOID lpANDbits, LPCVOID lpXORbits )
107{
108 CURSORICONINFO info;
109
110 dprintf(("USER32: CreateIcon (%d,%d), %d, %x, %x", nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits));
111
112 info.ptHotSpot.x = ICON_HOTSPOT;
113 info.ptHotSpot.y = ICON_HOTSPOT;
114 info.nWidth = nWidth;
115 info.nHeight = nHeight;
116 info.nWidthBytes = 0;
117 info.bPlanes = bPlanes;
118 info.bBitsPerPixel = bBitsPixel;
119 info.hInstance = hInstance;
120 info.dwResGroupId = -1;
121 info.hColorBmp = 0;
122 return CreateCursorIconIndirect(0, &info, lpANDbits, lpXORbits);
123}
124/**********************************************************************
125 * CreateIconFromResource (USER32.76)
126 */
127HICON WIN32API CreateIconFromResource(LPBYTE bits, UINT cbSize,
128 BOOL bIcon, DWORD dwVersion)
129{
130 return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
131}
132//******************************************************************************
133//******************************************************************************
134HICON WIN32API CreateIconFromResourceEx(LPBYTE bits, UINT cbSize,
135 BOOL bIcon, DWORD dwVersion,
136 INT width, INT height,
137 UINT cFlag )
138{
139 dprintf(("USER32: CreateIconFromResourceEx %X %d %d %X %d %d %X,", bits, cbSize, bIcon, dwVersion, width, height, cFlag));
140 return CURSORICON_CreateFromResource(0, -1, 0, bits, cbSize, bIcon, dwVersion, width, height, cFlag );
141}
142/**********************************************************************
143 * CreateIconIndirect (USER32.78)
144 */
145HICON WINAPI CreateIconIndirect(ICONINFO *iconinfo)
146{
147 BITMAP bmpXor,bmpAnd;
148 HICON hObj;
149 int sizeXor,sizeAnd;
150
151 dprintf(("USER32: CreateIconIndirect %x", iconinfo));
152
153 GetObjectA( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
154 GetObjectA( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
155
156 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
157 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
158
159 hObj = GlobalAlloc( GMEM_MOVEABLE, sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
160 if (hObj)
161 {
162 CURSORICONINFO *info;
163
164 info = (CURSORICONINFO *)GlobalLock( hObj );
165
166 /* If we are creating an icon, the hotspot is unused */
167 if (iconinfo->fIcon)
168 {
169 info->ptHotSpot.x = ICON_HOTSPOT;
170 info->ptHotSpot.y = ICON_HOTSPOT;
171 }
172 else
173 {
174 info->ptHotSpot.x = iconinfo->xHotspot;
175 info->ptHotSpot.y = iconinfo->yHotspot;
176 }
177
178 info->nWidth = bmpXor.bmWidth;
179 info->nHeight = bmpXor.bmHeight;
180 info->nWidthBytes = bmpXor.bmWidthBytes;
181 info->bPlanes = bmpXor.bmPlanes;
182 info->bBitsPerPixel = bmpXor.bmBitsPixel;
183 info->hInstance = -1;
184 info->dwResGroupId = -1;
185 info->hColorBmp = 0;
186
187 /* Transfer the bitmap bits to the CURSORICONINFO structure */
188 GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
189 GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
190 GlobalUnlock(hObj);
191 }
192 else {
193 dprintf(("ERROR: CreateIconIndirect GlobalAlloc failed!!"));
194 }
195 return hObj;
196}
197//******************************************************************************
198//******************************************************************************
199BOOL WIN32API DestroyIcon( HICON hIcon)
200{
201 dprintf(("USER32: DestroyIcon %x", hIcon));
202 return CURSORICON_Destroy( hIcon, 0 );
203}
204//******************************************************************************
205//******************************************************************************
206HICON WIN32API CopyIcon( HICON hIcon)
207{
208 dprintf(("USER32: CopyIcon %x", hIcon));
209 return CURSORICON_Copy( hIcon );
210}
211/**********************************************************************
212 * GetIconInfo (USER32.242)
213 */
214BOOL WINAPI GetIconInfo(HICON hIcon, ICONINFO *iconinfo)
215{
216 CURSORICONINFO *ciconinfo;
217
218 dprintf(("GetIconInfo %x %x", hIcon, iconinfo));
219
220 ciconinfo = (CURSORICONINFO *)GlobalLock((HGLOBAL)hIcon);
221 if (!ciconinfo)
222 return FALSE;
223
224 if((ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
225 (ciconinfo->ptHotSpot.y == ICON_HOTSPOT))
226 {
227 iconinfo->fIcon = TRUE;
228 iconinfo->xHotspot = ciconinfo->nWidth / 2;
229 iconinfo->yHotspot = ciconinfo->nHeight / 2;
230 }
231 else
232 {
233 iconinfo->fIcon = FALSE;
234 iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
235 iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
236 }
237
238 //Create new bitmaps for the color and mask data; application is responsible
239 //for deleteing them (according to docs & verified in NT4)
240 if(ciconinfo->bBitsPerPixel > 1)
241 {
242 BITMAPINFO* pInfo;
243 int colorsize = 0;
244 int coloroff;
245
246 HDC hdc = CreateCompatibleDC(0);
247
248 if(ciconinfo->bBitsPerPixel <= 8) {
249 colorsize = (1<<ciconinfo->bBitsPerPixel)*sizeof(RGBQUAD);
250 }
251 else {
252 colorsize = 3*sizeof(DWORD); //color masks
253 }
254 pInfo = (BITMAPINFO *)malloc(ciconinfo->nHeight * ciconinfo->nWidthBytes + colorsize + sizeof(BITMAPINFO));
255 memset(pInfo, 0, sizeof(BITMAPINFO)+colorsize);
256
257 pInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
258 pInfo->bmiHeader.biWidth = ciconinfo->nWidth;
259 pInfo->bmiHeader.biHeight = ciconinfo->nHeight,
260 pInfo->bmiHeader.biPlanes = ciconinfo->bPlanes;
261 pInfo->bmiHeader.biBitCount = ciconinfo->bBitsPerPixel;
262 pInfo->bmiHeader.biSizeImage= ciconinfo->nHeight * ciconinfo->nWidthBytes;
263
264 //offset in cursorinfo memory
265 coloroff = ciconinfo->nHeight * BITMAP_GetWidthBytes (ciconinfo->nWidth, 1);
266
267 char *src = (char *)(ciconinfo + 1) + coloroff;
268 if(ciconinfo->bBitsPerPixel <= 8) {
269 src += colorsize; //no color masks in cursorinfo data for bpp > 8
270 }
271 if(ciconinfo->bBitsPerPixel <= 8) {
272 memcpy(&pInfo->bmiColors[0], (char *)(ciconinfo + 1) + coloroff, colorsize);
273 }
274 //else TODO: color masks (currently unused in CreateDIBitmap)
275
276 iconinfo->hbmColor = CreateDIBitmap(hdc, &pInfo->bmiHeader, CBM_INIT, src, pInfo, DIB_RGB_COLORS);
277
278 free(pInfo);
279 DeleteDC(hdc);
280 }
281 else {
282 iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
283 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
284 (char *)(ciconinfo + 1)
285 + ciconinfo->nHeight *
286 BITMAP_GetWidthBytes (ciconinfo->nWidth, 1) );
287 }
288
289 iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
290 1, 1, (char *)(ciconinfo + 1));
291
292 GlobalUnlock(hIcon);
293
294 return TRUE;
295}
296//******************************************************************************
297//******************************************************************************
298HCURSOR WIN32API CreateCursor(HINSTANCE hInst, int xHotSpot, int yHotSpot, int nWidth, int nHeight,
299 const VOID *lpANDbits, const VOID *lpXORbits)
300{
301 CURSORICONINFO info;
302
303 dprintf(("CreateCursor %dx%d spot=%d,%d xor=%p and=%p\n",
304 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits));
305
306 info.ptHotSpot.x = xHotSpot;
307 info.ptHotSpot.y = yHotSpot;
308 info.nWidth = nWidth;
309 info.nHeight = nHeight;
310 info.nWidthBytes = 0;
311 info.bPlanes = 1;
312 info.bBitsPerPixel = 1;
313 info.hInstance = hInst;
314 info.dwResGroupId = -1;
315 info.hColorBmp = 0;
316
317 return CreateCursorIconIndirect( 0, &info, lpANDbits, lpXORbits );
318}
319//******************************************************************************
320//******************************************************************************
321BOOL WIN32API DestroyCursor( HCURSOR hCursor)
322{
323 dprintf(("USER32: DestroyCursor %x", hCursor));
324 return CURSORICON_Destroy( hCursor, CID_WIN32 );
325}
326//******************************************************************************
327//******************************************************************************
328HCURSOR WIN32API GetCursor(void)
329{
330 dprintf2(("USER32: GetCursor"));
331 return hActiveCursor;
332}
333//******************************************************************************
334//******************************************************************************
335HCURSOR WIN32API SetCursor( HCURSOR hCursor)
336{
337 HCURSOR hOldCursor;
338
339 dprintf(("USER32: SetCursor %x (prev %x)", hCursor, hActiveCursor));
340 if (hCursor == hActiveCursor) return hActiveCursor; /* No change */
341
342 hOldCursor = hActiveCursor;
343 hActiveCursor = hCursor;
344
345 CURSORICONINFO *iconinfo = (CURSORICONINFO *)GlobalLock((HGLOBAL)hCursor);
346 if (!iconinfo) {
347 dprintf(("ERROR: Invalid cursor!"));
348 return 0;
349 }
350 if(!iconinfo->hColorBmp) {
351 dprintf(("SetCursor: invalid os/2 pointer handle!!"));
352 }
353
354 if(OSLibWinSetPointer(iconinfo->hColorBmp) == FALSE) {
355 dprintf(("OSLibWinSetPointer %x returned FALSE!!", iconinfo->hColorBmp));
356 }
357 GlobalUnlock(hCursor);
358
359 return hOldCursor;
360}
361//******************************************************************************
362//******************************************************************************
363BOOL WIN32API GetCursorPos( PPOINT lpPoint)
364{
365 dprintf2(("USER32: GetCursorPos %x", lpPoint));
366
367 if (!lpPoint) return FALSE;
368
369 if (OSLibWinQueryPointerPos(lpPoint)) //POINT == POINTL
370 {
371 mapScreenPoint((OSLIBPOINT*)lpPoint);
372 return TRUE;
373 }
374 else return FALSE;
375}
376//******************************************************************************
377//******************************************************************************
378BOOL WIN32API SetCursorPos( int X, int Y)
379{
380 dprintf(("USER32: SetCursorPos %d %d", X,Y));
381 return OSLibWinSetPointerPos(X, mapScreenY(Y));
382}
383//******************************************************************************
384//******************************************************************************
385/*****************************************************************************
386 * Name : BOOL WIN32API SetSystemCursor
387 * Purpose : The SetSystemCursor function replaces the contents of the system
388 * cursor specified by dwCursorId with the contents of the cursor
389 * specified by hCursor, and then destroys hCursor. This function
390 * lets an application customize the system cursors.
391 * Parameters: HCURSOR hCursor set specified system cursor to this cursor's
392 * contents, then destroy this
393 * DWORD dwCursorID system cursor specified by its identifier
394 * Variables :
395 * Result : If the function succeeds, the return value is TRUE.
396 * If the function fails, the return value is FALSE. To get extended
397 * error information, call GetLastError.
398 * Remark :
399 * Status : UNTESTED STUB
400 *
401 * Author : Patrick Haller [Thu, 1998/02/26 11:55]
402 *****************************************************************************/
403BOOL WIN32API SetSystemCursor(HCURSOR hCursor, DWORD dwCursorId)
404{
405 dprintf(("USER32:SetSystemCursor (%08xh,%08x) not supported.\n",
406 hCursor,
407 dwCursorId));
408
409 return DestroyCursor(hCursor);
410}
411//******************************************************************************
412//******************************************************************************
413INT OPEN32API __ShowCursor(BOOL bShow);
414
415inline INT _ShowCursor (BOOL bShow)
416{
417 INT yyrc;
418 USHORT sel = RestoreOS2FS();
419
420 yyrc = __ShowCursor(bShow);
421 SetFS(sel);
422
423 return yyrc;
424}
425//******************************************************************************
426static int cursorshowcnt = 0;
427//******************************************************************************
428void RestoreCursor()
429{
430 dprintf2(("USER32: RestoreCursor %d", cursorshowcnt));
431 while(cursorshowcnt != 0)
432 {
433 if(cursorshowcnt > 0 )
434 {
435 ShowCursor(FALSE);
436 }
437 else
438 {
439 ShowCursor(TRUE);
440 }
441 }
442}
443//******************************************************************************
444//******************************************************************************
445int WIN32API ShowCursor(BOOL bShow)
446{
447 dprintf2(("USER32: ShowCursor %d", bShow));
448 cursorshowcnt = cursorshowcnt + ((bShow) ? 1 : -1);
449 return _ShowCursor(bShow);
450}
451/***********************************************************************
452 * CreateCursorIconIndirect
453 */
454HGLOBAL WIN32API CreateCursorIconIndirect( HINSTANCE hInstance,
455 CURSORICONINFO *info,
456 LPCVOID lpANDbits,
457 LPCVOID lpXORbits )
458{
459 HGLOBAL handle;
460 char *ptr;
461 int sizeAnd, sizeXor;
462
463 if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
464 info->nWidthBytes = BITMAP_GetWidthBytes(info->nWidth,info->bBitsPerPixel);
465 sizeXor = info->nHeight * info->nWidthBytes;
466 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
467 if (!(handle = GlobalAlloc( GMEM_MOVEABLE,
468 sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
469 return 0;
470 ptr = (char *)GlobalLock( handle );
471 memcpy( ptr, info, sizeof(*info) );
472 memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
473 memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
474 GlobalUnlock( handle );
475 return handle;
476}
477/**********************************************************************
478 * CURSORICON_Load
479 *
480 * Load a cursor or icon from resource or file.
481 */
482HGLOBAL CURSORICON_Load( HINSTANCE hInstance, LPCWSTR name,
483 INT width, INT height, INT colors,
484 BOOL fCursor, UINT loadflags )
485{
486 HANDLE handle = 0, h = 0;
487 HANDLE hRsrc;
488 CURSORICONDIR *dir;
489 CURSORICONDIRENTRY *dirEntry;
490 LPBYTE bits;
491
492#ifdef __WIN32OS2__
493 //TODO: Can system cursors be loaded by name??? (#xxx)
494 if (fCursor && hInstance == NULL && !HIWORD(name))
495 {
496 HCURSOR hCursor = OSLibWinQuerySysPointer((ULONG)name, width, height);
497 if(hCursor)
498 {
499 /* If shared icon, check whether it was already loaded */
500 if ((loadflags & LR_SHARED)
501 && (h = CURSORICON_FindSharedIcon( -1, hCursor ) ) != 0 )
502 {
503 dprintf(("Found icon/cursor in cache; returned old handle %x", h));
504 return h;
505 }
506
507 HANDLE hObj = GlobalAlloc( GMEM_MOVEABLE, sizeof(CURSORICONINFO));
508 if (!hObj)
509 {
510 DebugInt3();
511 return 0;
512 }
513 CURSORICONINFO *info;
514
515 info = (CURSORICONINFO *)GlobalLock( hObj );
516 info->ptHotSpot.x = 0;
517 info->ptHotSpot.y = 0;
518 info->nWidth = width;
519 info->nHeight = height;
520 info->nWidthBytes = width*height/8;
521 info->bPlanes = 1;
522 info->bBitsPerPixel = 1;
523 info->hColorBmp = hCursor;
524 info->hInstance = -1;
525 info->dwResGroupId = -1;
526
527 if (loadflags & LR_SHARED )
528 CURSORICON_AddSharedIcon( -1, hCursor, -1, hObj );
529
530 GlobalUnlock( hObj );
531
532 return hObj;
533 }
534 }
535#endif
536 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
537 {
538 LPBYTE *ptr;
539
540 if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
541 return 0;
542 if (fCursor)
543 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
544 else
545 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(dir, width, height, colors);
546 bits = ptr[dirEntry->wResId-1];
547 h = CURSORICON_CreateFromResource( 0, -1, 0, bits, dirEntry->dwBytesInRes,
548 !fCursor, 0x00030000, width, height, loadflags);
549
550 HeapFree( GetProcessHeap(), 0, dir );
551 HeapFree( GetProcessHeap(), 0, ptr );
552 }
553 else /* Load from resource */
554 {
555 HANDLE hGroupRsrc;
556 WORD wResId;
557 DWORD dwBytesInRes;
558 BOOL bIsGroup = TRUE;
559
560 /* Get directory resource ID */
561 if (!hInstance)
562 {
563 hRsrc = FindResourceW(hInstanceUser32, name, fCursor ? RT_CURSORW : RT_ICONW);
564 if(!hRsrc) {
565 hRsrc = FindResourceW(hInstanceUser32, name, fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW);
566 }
567 else bIsGroup = FALSE;
568
569 if(!hRsrc) return 0;
570
571 hInstance = hInstanceUser32;
572 }
573 else {
574 hRsrc = FindResourceW(hInstance, name, fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW);
575 if(!hRsrc) return 0;
576 }
577 hGroupRsrc = hRsrc;
578
579 if(bIsGroup) {
580 /* Find the best entry in the directory */
581
582 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
583 if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
584
585 if (fCursor)
586 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
587 width, height, 1);
588 else
589 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
590 width, height, colors );
591 if (!dirEntry) return 0;
592 wResId = dirEntry->wResId;
593 dwBytesInRes = dirEntry->dwBytesInRes;
594 FreeResource( handle );
595
596 /* Load the resource */
597 if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
598 fCursor ? RT_CURSORW : RT_ICONW ))) return 0;
599 }
600
601 /* If shared icon, check whether it was already loaded */
602 if ((loadflags & LR_SHARED)
603 && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
604 {
605 dprintf(("Found icon/cursor in cache; returned old handle %x", h));
606 return h;
607 }
608
609 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
610 bits = (LPBYTE)LockResource( handle );
611 h = CURSORICON_CreateFromResource( hInstance, (DWORD)name, 0, bits, dwBytesInRes,
612 !fCursor, 0x00030000, width, height, loadflags);
613 FreeResource( handle );
614
615 /* If shared icon, add to icon cache */
616
617 if ( h && (loadflags & LR_SHARED) )
618 CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, h );
619
620 }
621
622 return h;
623}
624
625/*********************************************************************
626 * The main purpose of this function is to create fake resource directory
627 * and fake resource entries. There are several reasons for this:
628 * - CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
629 * fields
630 * There are some "bad" cursor files which do not have
631 * bColorCount initialized but instead one must read this info
632 * directly from corresponding DIB sections
633 * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
634 */
635BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
636 CURSORICONDIR **res, LPBYTE **ptr)
637{
638 LPBYTE _free;
639 CURSORICONFILEDIR *bits;
640 int entries, size, i;
641 HANDLE hMapping = 0;
642
643 *res = NULL;
644 *ptr = NULL;
645
646 hMapping = VIRTUAL_MapFileW( filename, (LPVOID *)&bits, TRUE);
647 if(hMapping == INVALID_HANDLE_VALUE)
648 return FALSE;
649
650 /* FIXME: test for inimated icons
651 * hack to load the first icon from the *.ani file
652 */
653 if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
654 {
655 LPBYTE pos = (LPBYTE) bits;
656 dprintf(("Animated icons not correctly implemented! %p \n", bits));
657
658 for (;;)
659 {
660 if (*(LPDWORD)pos==0x6e6f6369) /* "icon" */
661 {
662 dprintf(("icon entry found! %p\n", bits));
663 pos+=4;
664 if ( !*(LPWORD) pos==0x2fe) /* iconsize */
665 {
666 goto fail;
667 }
668 bits=(CURSORICONFILEDIR*)(pos+4);
669 dprintf(("icon size ok. offset=%p \n", bits));
670 break;
671 }
672 pos+=2;
673 if (pos>=(LPBYTE)bits+766) goto fail;
674 }
675 }
676 if (!(entries = bits->idCount)) goto fail;
677 size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * (entries - 1);
678 _free = (LPBYTE) size;
679
680 for (i=0; i < entries; i++)
681 size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
682
683 if (!(*ptr = (LPBYTE *)HeapAlloc( GetProcessHeap(), 0,
684 entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
685 if (!(*res = (CURSORICONDIR *)HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
686
687 _free = (LPBYTE)(*res) + (int)_free;
688 memcpy((*res), bits, 6);
689 for (i=0; i<entries; i++)
690 {
691 ((LPBYTE*)(*ptr))[i] = _free;
692 if (fCursor) {
693 (*res)->idEntries[i].ResInfo.cursor.wWidth=bits->idEntries[i].bWidth;
694 (*res)->idEntries[i].ResInfo.cursor.wHeight=bits->idEntries[i].bHeight;
695 ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
696 ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
697 _free+=sizeof(POINT16);
698 }
699 else {
700 (*res)->idEntries[i].ResInfo.icon.bWidth=bits->idEntries[i].bWidth;
701 (*res)->idEntries[i].ResInfo.icon.bHeight=bits->idEntries[i].bHeight;
702 (*res)->idEntries[i].ResInfo.icon.bColorCount = bits->idEntries[i].bColorCount;
703 }
704 (*res)->idEntries[i].wPlanes=1;
705 (*res)->idEntries[i].wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
706 bits->idEntries[i].dwDIBOffset))->biBitCount;
707 (*res)->idEntries[i].dwBytesInRes = bits->idEntries[i].dwDIBSize;
708 (*res)->idEntries[i].wResId=i+1;
709
710 memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
711 (*res)->idEntries[i].dwBytesInRes);
712 _free += (*res)->idEntries[i].dwBytesInRes;
713 }
714 UnmapViewOfFile( bits );
715 CloseHandle(hMapping);
716 return TRUE;
717
718fail:
719 if (*res) HeapFree( GetProcessHeap(), 0, *res );
720 if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
721
722 UnmapViewOfFile( bits );
723 CloseHandle(hMapping);
724 return FALSE;
725}
726
727/**********************************************************************
728 * CURSORICON_CreateFromResource
729 *
730 * Create a cursor or icon from in-memory resource template.
731 *
732 * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
733 * with cbSize parameter as well.
734 */
735static HGLOBAL CURSORICON_CreateFromResource( HINSTANCE hInstance, DWORD dwResGroupId, HGLOBAL hObj, LPBYTE bits,
736 UINT cbSize, BOOL bIcon, DWORD dwVersion,
737 INT width, INT height, UINT loadflags )
738{
739 int sizeAnd, sizeXor;
740 HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
741 BITMAP bmpXor, bmpAnd;
742 POINT16 hotspot;
743 BITMAPINFO *bmi;
744 HDC hdc = 0;
745 BOOL DoStretch;
746 INT size, colortablesize, bwsize, colorsize;
747
748 hotspot.x = ICON_HOTSPOT;
749 hotspot.y = ICON_HOTSPOT;
750
751//testestest
752 dprintf(("CURSORICON_CreateFromResource %x %x %x %x %d", hInstance, dwResGroupId, hObj, bits, cbSize));
753
754 if (dwVersion == 0x00020000)
755 {
756 dprintf(("CURSORICON_CreateFromResource 2.xx resources are not supported"));
757 return 0;
758 }
759
760 if (bIcon) {
761 bmi = (BITMAPINFO *)bits;
762 }
763 else /* get the hotspot */
764 {
765 POINT16 *pt = (POINT16 *)bits;
766 hotspot = *pt;
767 bmi = (BITMAPINFO *)(pt + 1);
768 }
769 size = DIB_BitmapInfoSize(bmi, DIB_RGB_COLORS);
770
771 if (!width) width = bmi->bmiHeader.biWidth;
772 if (!height) height = bmi->bmiHeader.biHeight/2;
773
774 DoStretch = (bmi->bmiHeader.biHeight/2 != height) || (bmi->bmiHeader.biWidth != width);
775
776 colorsize = DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2, bmi->bmiHeader.biBitCount);
777 bwsize = (bmi->bmiHeader.biWidth * bmi->bmiHeader.biHeight/2)/8;
778
779 /* Check bitmap header */
780 if((bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
781 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
782 bmi->bmiHeader.biCompression != BI_RGB) )
783 {
784 return 0;
785 }
786
787 if( (hdc = GetDC( 0 )) )
788 {
789 BITMAPINFO* pInfo;
790
791 /* Make sure we have room for the monochrome bitmap later on.
792 * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
793 * up to and including the biBitCount. In-memory icon resource
794 * format is as follows:
795 *
796 * BITMAPINFOHEADER icHeader // DIB header
797 * RGBQUAD icColors[] // Color table
798 * BYTE icXOR[] // DIB bits for XOR mask
799 * BYTE icAND[] // DIB bits for AND mask
800 */
801
802 if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0,
803 max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
804 {
805 memcpy( pInfo, bmi, size );
806 pInfo->bmiHeader.biHeight /= 2;
807
808 /* Create the XOR bitmap */
809 if (DoStretch)
810 {
811 if(bIcon)
812 {
813 hXorBits = CreateCompatibleBitmap(hdc, width, height);
814 }
815 else
816 {
817 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
818 }
819 if(hXorBits)
820 {
821 HBITMAP hOld;
822 HDC hMem = CreateCompatibleDC(hdc);
823 BOOL res;
824
825 if (hMem) {
826 hOld = SelectObject(hMem, hXorBits);
827 res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
828 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
829 (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
830 SelectObject(hMem, hOld);
831 DeleteDC(hMem);
832 }
833 else res = FALSE;
834 if (!res) {
835 DeleteObject(hXorBits);
836 hXorBits = 0;
837 }
838 }
839 }
840 else
841 {
842 hXorBits = CreateDIBitmap(hdc, &pInfo->bmiHeader,
843 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
844 }
845 if( hXorBits )
846 {
847 char* xbits = (char *)bmi + size + DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
848 bmi->bmiHeader.biHeight,
849 bmi->bmiHeader.biBitCount) / 2;
850
851 pInfo->bmiHeader.biBitCount = 1;
852 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
853 {
854 RGBQUAD *rgb = pInfo->bmiColors;
855
856 pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
857 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
858 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
859 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
860 }
861 else
862 {
863 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
864
865 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
866 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
867 }
868
869 /* Create the AND bitmap */
870 if (DoStretch)
871 {
872 if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL)))
873 {
874 HBITMAP hOld;
875 HDC hMem = CreateCompatibleDC(hdc);
876 BOOL res;
877
878 if (hMem) {
879 hOld = SelectObject(hMem, hAndBits);
880//SvL: This also doesn't work as StretchDIBits doesn't handle 1bpp bitmaps correctly
881//--------->>> hack alert!
882#if 1
883 HBITMAP hBmp, hOld1;
884 HDC hMem1;
885
886 hMem1 = CreateCompatibleDC(hdc);
887
888 int linewidth = BITMAP_GetWidthBytes(pInfo->bmiHeader.biWidth, 1);
889
890 char *newpix = (char *)malloc(linewidth*pInfo->bmiHeader.biHeight);
891
892 newpix += ((pInfo->bmiHeader.biHeight-1)*linewidth);
893
894 if(cbSize - size - colorsize - bwsize == bwsize)
895 {//this means an AND and XOR mask is present (interleaved; and/xor)
896 for(int i=0;i<pInfo->bmiHeader.biHeight;i++) {
897 memcpy(newpix, xbits, linewidth);
898 newpix -= linewidth;
899 xbits += linewidth*2;
900 }
901 }
902 else {
903 for(int i=0;i<pInfo->bmiHeader.biHeight;i++) {
904 memcpy(newpix, xbits, linewidth);
905 newpix -= linewidth;
906 xbits += linewidth;
907 }
908 }
909 newpix += linewidth;
910 hBmp = CreateBitmap(pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight, 1, 1, newpix);
911 free(newpix);
912
913 hOld1 = SelectObject(hMem1, hBmp);
914
915 res = StretchBlt(hMem, 0, 0, width, height, hMem1, 0, 0, pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight, SRCCOPY);
916
917 SelectObject(hMem1, hOld1);
918 DeleteObject(hBmp);
919 DeleteDC(hMem1);
920
921
922#else
923 res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
924 pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
925 xbits, pInfo, DIB_RGB_COLORS, SRCCOPY);
926#endif
927 SelectObject(hMem, hOld);
928 DeleteDC(hMem);
929 }
930 else res = FALSE;
931 if (!res) {
932 DeleteObject(hAndBits);
933 hAndBits = 0;
934 }
935 }
936 }
937 else {
938//SvL: Must use CreateBitmap here as CreateDIBitmap converts data to 8bpp (GetObjectA info -> 8 bpp)
939#if 1
940 int linewidth = BITMAP_GetWidthBytes(width, 1);
941
942 char *newpix = (char *)malloc(linewidth*height);
943
944 newpix += ((height-1)*linewidth);
945
946 if(cbSize - size - colorsize - bwsize == bwsize)
947 {//this means an AND and XOR mask is present (interleaved; and/xor)
948 for(int i=0;i<height;i++) {
949 memcpy(newpix, xbits, linewidth);
950 newpix -= linewidth;
951 xbits += linewidth*2;
952 }
953 }
954 else {
955 for(int i=0;i<height;i++) {
956 memcpy(newpix, xbits, linewidth);
957 newpix -= linewidth;
958 xbits += linewidth;
959 }
960 }
961 newpix += linewidth;
962 hAndBits = CreateBitmap(width, height, 1, 1, newpix);
963
964 free(newpix);
965
966#else
967 hAndBits = CreateDIBitmap(hdc, &pInfo->bmiHeader,
968 CBM_INIT, xbits, pInfo, DIB_RGB_COLORS );
969#endif
970 }
971 if( !hAndBits )
972 DeleteObject( hXorBits );
973 }
974 HeapFree( GetProcessHeap(), 0, pInfo );
975 }
976 ReleaseDC( 0, hdc );
977 }
978
979 if( !hXorBits || !hAndBits )
980 {
981 dprintf(("\tunable to create an icon bitmap."));
982 return 0;
983 }
984
985 /* Now create the CURSORICONINFO structure */
986 GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
987 GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
988 colortablesize = 0;
989
990 if(bmpXor.bmBitsPixel <= 8) {
991 colortablesize = sizeof(RGBQUAD)*(1<<bmpXor.bmBitsPixel);
992 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes + colortablesize;
993 }
994 else sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
995
996 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
997
998 if (hObj) hObj = GlobalReAlloc( hObj,
999 sizeof(CURSORICONINFO) + sizeXor + sizeAnd, GMEM_MOVEABLE );
1000 if (!hObj) hObj = GlobalAlloc( GMEM_MOVEABLE,
1001 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1002 if (hObj)
1003 {
1004 CURSORICONINFO *info;
1005
1006 info = (CURSORICONINFO *)GlobalLock( hObj );
1007 info->ptHotSpot.x = hotspot.x;
1008 info->ptHotSpot.y = hotspot.y;
1009 info->nWidth = bmpXor.bmWidth;
1010 info->nHeight = bmpXor.bmHeight;
1011 info->nWidthBytes = bmpXor.bmWidthBytes;
1012 info->bPlanes = bmpXor.bmPlanes;
1013 info->bBitsPerPixel = bmpXor.bmBitsPixel;
1014 info->hInstance = hInstance;
1015 info->dwResGroupId = dwResGroupId;
1016 info->hColorBmp = 0;
1017
1018 /* Transfer the bitmap bits to the CURSORICONINFO structure */
1019 GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1));
1020
1021 if(bmpXor.bmBitsPixel > 1)
1022 {
1023 BITMAPINFO* pInfo = (BITMAPINFO *)malloc(sizeof(BITMAPINFO)+colortablesize+3*sizeof(DWORD)); //+ extra space for > 8bpp images
1024 HBITMAP oldbmp;
1025
1026 hdc = CreateCompatibleDC(0);
1027
1028 memset(pInfo, 0, sizeof(BITMAPINFO)+colortablesize+3*sizeof(DWORD));
1029 pInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1030 pInfo->bmiHeader.biPlanes = info->bPlanes;
1031 pInfo->bmiHeader.biBitCount = info->bBitsPerPixel;
1032
1033 GetDIBits(hdc, hXorBits, 0, bmpXor.bmHeight, (char *)(info + 1) + sizeAnd + colortablesize, pInfo, DIB_RGB_COLORS);
1034 if(colortablesize) {
1035 memcpy((char *)(info + 1) + sizeAnd, (char *)&pInfo->bmiHeader + pInfo->bmiHeader.biSize, colortablesize);
1036 }
1037
1038 DeleteDC(hdc);
1039 free(pInfo);
1040 }
1041 else {
1042 GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd);
1043 }
1044 if(!bIcon) {
1045 info->hColorBmp = OSLibWinCreateCursor(info, (char *)(info + 1), (LPBITMAP_W)&bmpAnd, (char *)(info + 1) + sizeAnd, (LPBITMAP_W)&bmpXor);
1046 dprintf(("Create cursor %x with OS/2 pointer handle %x", hObj, info->hColorBmp));
1047 }
1048 GlobalUnlock( hObj );
1049 }
1050
1051 DeleteObject( hAndBits );
1052 DeleteObject( hXorBits );
1053 return hObj;
1054}
1055
1056/**********************************************************************
1057 * CURSORICON_Destroy (USER.610)
1058 *
1059 * This routine is actually exported from Win95 USER under the name
1060 * DestroyIcon32 ... The behaviour implemented here should mimic
1061 * the Win95 one exactly, especially the return values, which
1062 * depend on the setting of various flags.
1063 */
1064WORD WIN32API CURSORICON_Destroy( HGLOBAL handle, UINT flags )
1065{
1066 WORD retv;
1067
1068 /* Check whether destroying active cursor */
1069
1070 if ( hActiveCursor == handle )
1071 {
1072 dprintf(("WARNING: Destroying active cursor!" ));
1073 SetCursor( 0 );
1074 }
1075
1076 /* Try shared cursor/icon first */
1077 if ( !(flags & CID_NONSHARED) )
1078 {
1079 INT count = CURSORICON_DelSharedIcon( handle );
1080
1081 if ( count != -1 )
1082 return (flags & CID_WIN32)? TRUE : (count == 0);
1083
1084 /* FIXME: OEM cursors/icons should be recognized */
1085 }
1086 /* Now assume non-shared cursor/icon */
1087
1088#ifdef __WIN32OS2__
1089 CURSORICONINFO *iconinfo = (CURSORICONINFO *)GlobalLock((HGLOBAL)handle);
1090 if (!iconinfo) {
1091 dprintf(("ERROR: Invalid cursor!"));
1092 return 0;
1093 }
1094
1095 if(iconinfo->hColorBmp) {
1096 OSLibWinDestroyPointer(iconinfo->hColorBmp);
1097 }
1098 GlobalUnlock(handle);
1099#endif
1100
1101 retv = GlobalFree( handle );
1102 return (flags & CID_RESOURCE)? retv : TRUE;
1103}
1104
1105/***********************************************************************
1106 * CURSORICON_Copy
1107 *
1108 * Make a copy of a cursor or icon.
1109 */
1110static HGLOBAL CURSORICON_Copy(HGLOBAL handle)
1111{
1112 char *ptrOld, *ptrNew;
1113 int size;
1114 HGLOBAL hNew;
1115
1116 if (!(ptrOld = (char *)GlobalLock( handle ))) return 0;
1117
1118 size = GlobalSize( handle );
1119 hNew = GlobalAlloc( GMEM_MOVEABLE, size );
1120 ptrNew = (char *)GlobalLock( hNew );
1121 memcpy( ptrNew, ptrOld, size );
1122 GlobalUnlock( handle );
1123 GlobalUnlock( hNew );
1124 return hNew;
1125}
1126
1127/*************************************************************************
1128 * CURSORICON_ExtCopy
1129 *
1130 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
1131 *
1132 * PARAMS
1133 * Handle [I] handle to an Image
1134 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
1135 * iDesiredCX [I] The Desired width of the Image
1136 * iDesiredCY [I] The desired height of the Image
1137 * nFlags [I] The flags from CopyImage
1138 *
1139 * RETURNS
1140 * Success: The new handle of the Image
1141 *
1142 * NOTES
1143 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
1144 * LR_MONOCHROME should be implemented by CURSORICON_CreateFromResource.
1145 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
1146 *
1147 *
1148 */
1149HGLOBAL CURSORICON_ExtCopy(HGLOBAL Handle, UINT nType,
1150 INT iDesiredCX, INT iDesiredCY,
1151 UINT nFlags)
1152{
1153 HGLOBAL hNew=0;
1154
1155 if(Handle == 0)
1156 {
1157 return 0;
1158 }
1159 /* Best Fit or Monochrome */
1160 if( (nFlags & LR_COPYFROMRESOURCE
1161 && (iDesiredCX > 0 || iDesiredCY > 0))
1162 || nFlags & LR_MONOCHROME)
1163 {
1164 ICONCACHE* pIconCache = CURSORICON_FindCache(Handle);
1165
1166 /* Not Found in Cache, then do a straight copy
1167 */
1168 if(pIconCache == NULL)
1169 {
1170#ifdef __WIN32OS2__
1171 hNew = CURSORICON_Copy(Handle);
1172#else
1173 hNew = CURSORICON_Copy(0, Handle);
1174#endif
1175 if(nFlags & LR_COPYFROMRESOURCE)
1176 {
1177 dprintf(("WARNING: LR_COPYFROMRESOURCE: Failed to load from cache\n"));
1178 }
1179 }
1180 else
1181 {
1182 int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
1183 LPBYTE pBits;
1184 HANDLE hMem;
1185 HRSRC hRsrc;
1186 DWORD dwBytesInRes;
1187 WORD wResId;
1188 DWORD dwResGroupId;
1189 HINSTANCE hInstance;
1190 CURSORICONINFO *iconinfo;
1191 CURSORICONDIR *pDir;
1192 CURSORICONDIRENTRY *pDirEntry;
1193 BOOL bIsIcon = (nType == IMAGE_ICON);
1194
1195 iconinfo = (CURSORICONINFO *)GlobalLock( Handle );
1196 if(iconinfo == NULL) {
1197 dprintf(("ERROR: CURSORICON_ExtCopy invalid icon!"));
1198 }
1199 hInstance = iconinfo->hInstance;
1200 dwResGroupId = iconinfo->dwResGroupId;
1201 GlobalUnlock( Handle );
1202 if(dwResGroupId == -1) {
1203 //todo: if scaling is necessary..
1204 dprintf(("WARNING: no resource associated with icon/cursor -> copy without scaling!"));
1205 hNew = CURSORICON_Copy(Handle);
1206 return hNew;
1207 }
1208
1209 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
1210 */
1211 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
1212 || (iDesiredCX == 0 && iDesiredCY == 0))
1213 {
1214 iDesiredCY = GetSystemMetrics(bIsIcon ? SM_CYICON : SM_CYCURSOR);
1215 iDesiredCX = GetSystemMetrics(bIsIcon ? SM_CXICON : SM_CXCURSOR);
1216 }
1217
1218 /* Retreive the CURSORICONDIRENTRY
1219 */
1220 hRsrc = FindResourceW(hInstance, (LPWSTR)dwResGroupId, bIsIcon ? RT_GROUP_ICONW : RT_GROUP_CURSORW);
1221 if(!hRsrc) {
1222 goto notfound;
1223 }
1224
1225 if (!(hMem = LoadResource( hInstance, hRsrc)))
1226 {
1227 goto notfound;
1228 }
1229 if (!(pDir = (CURSORICONDIR*)LockResource( hMem )))
1230 {
1231 goto notfound;
1232 }
1233
1234 /* Find Best Fit
1235 */
1236 if(bIsIcon)
1237 {
1238 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(
1239 pDir, iDesiredCX, iDesiredCY, 256);
1240 }
1241 else
1242 {
1243 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(
1244 pDir, iDesiredCX, iDesiredCY, 1);
1245 }
1246
1247 wResId = pDirEntry->wResId;
1248 dwBytesInRes = pDirEntry->dwBytesInRes;
1249 FreeResource(hMem);
1250
1251 /* Get the Best Fit
1252 */
1253 if (!(hRsrc = FindResourceW(hInstance ,
1254 MAKEINTRESOURCEW(wResId), bIsIcon ? RT_ICONW : RT_CURSORW)))
1255 {
1256 goto notfound;
1257 }
1258 if (!(hMem = LoadResource( hInstance, hRsrc )))
1259 {
1260 goto notfound;
1261 }
1262
1263 pBits = (LPBYTE)LockResource( hMem );
1264
1265 if(nFlags & LR_DEFAULTSIZE)
1266 {
1267 iTargetCY = GetSystemMetrics(SM_CYICON);
1268 iTargetCX = GetSystemMetrics(SM_CXICON);
1269 }
1270
1271 /* Create a New Icon with the proper dimension
1272 */
1273 hNew = CURSORICON_CreateFromResource( hInstance, dwResGroupId, 0, pBits, dwBytesInRes,
1274 bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
1275 FreeResource(hMem);
1276 }
1277 }
1278 else
1279 {
1280 hNew = CURSORICON_Copy(Handle);
1281 }
1282 return hNew;
1283
1284notfound:
1285 dprintf(("WARNING: unable to find resource associated with icon/cursor -> copy without scaling!"));
1286 hNew = CURSORICON_Copy(Handle);
1287 return hNew;
1288}
1289
1290/**********************************************************************
1291 * CURSORICON_FindBestIcon
1292 *
1293 * Find the icon closest to the requested size and number of colors.
1294 */
1295static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
1296 int height, int colors )
1297{
1298 int i;
1299 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
1300 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
1301 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
1302
1303 if (dir->idCount < 1)
1304 {
1305 dprintf(("Empty directory!\n" ));
1306 return NULL;
1307 }
1308 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
1309
1310 /* Find Best Fit */
1311 iTotalDiff = 0xFFFFFFFF;
1312 iColorDiff = 0xFFFFFFFF;
1313 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
1314 {
1315 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
1316 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
1317
1318 if(iTotalDiff > (iTempXDiff + iTempYDiff))
1319 {
1320 iXDiff = iTempXDiff;
1321 iYDiff = iTempYDiff;
1322 iTotalDiff = iXDiff + iYDiff;
1323 }
1324 }
1325
1326 /* Find Best Colors for Best Fit */
1327 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
1328 {
1329 if(abs(width - entry->ResInfo.icon.bWidth) == iXDiff &&
1330 abs(height - entry->ResInfo.icon.bHeight) == iYDiff)
1331 {
1332#ifdef __WIN32OS2__
1333 iTempColorDiff = abs(colors - (1 << entry->wBitCount));
1334#else
1335 iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
1336#endif
1337 if(iColorDiff > iTempColorDiff)
1338 {
1339 bestEntry = entry;
1340 iColorDiff = iTempColorDiff;
1341 }
1342 }
1343 }
1344////testestest
1345 dprintf(("CURSORICON_FindBestIcon (%d,%d) %d -> %d", width, height, colors, (bestEntry) ? bestEntry->wResId : 0));
1346 return bestEntry;
1347}
1348
1349
1350/**********************************************************************
1351 * CURSORICON_FindBestCursor
1352 *
1353 * Find the cursor closest to the requested size.
1354 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
1355 * ignored too
1356 */
1357static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
1358 int width, int height, int color)
1359{
1360 int i, maxwidth, maxheight;
1361 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
1362
1363 if (dir->idCount < 1)
1364 {
1365 dprintf(("Empty directory!\n" ));
1366 return NULL;
1367 }
1368 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
1369
1370 /* Double height to account for AND and XOR masks */
1371
1372 height *= 2;
1373
1374 /* First find the largest one smaller than or equal to the requested size*/
1375
1376 maxwidth = maxheight = 0;
1377 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
1378 if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
1379 (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
1380 (entry->wBitCount == 1))
1381 {
1382 bestEntry = entry;
1383 maxwidth = entry->ResInfo.cursor.wWidth;
1384 maxheight = entry->ResInfo.cursor.wHeight;
1385 }
1386 if (bestEntry) return bestEntry;
1387
1388 /* Now find the smallest one larger than the requested size */
1389
1390 maxwidth = maxheight = 255;
1391 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
1392 if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
1393 (entry->wBitCount == 1))
1394 {
1395 bestEntry = entry;
1396 maxwidth = entry->ResInfo.cursor.wWidth;
1397 maxheight = entry->ResInfo.cursor.wHeight;
1398 }
1399
1400 return bestEntry;
1401}
1402/**********************************************************************
1403 * LookupIconIdFromDirectoryEx (USER.364)
1404 *
1405 * FIXME: exact parameter sizes
1406 */
1407INT WIN32API LookupIconIdFromDirectoryEx(LPBYTE xdir, BOOL bIcon,
1408 INT width, INT height, UINT cFlag )
1409{
1410 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1411 UINT retVal = 0;
1412
1413 dprintf(("LookupIconIdFromDirectoryEx %x %d (%d,%d)", xdir, bIcon, width, height));
1414 if( dir && !dir->idReserved && (dir->idType & 3) )
1415 {
1416 CURSORICONDIRENTRY* entry;
1417 HDC hdc;
1418 UINT palEnts;
1419 int colors;
1420 hdc = GetDC(0);
1421 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1422 if (palEnts == 0)
1423 palEnts = 256;
1424 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1425
1426 ReleaseDC(0, hdc);
1427
1428 if( bIcon )
1429 entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1430 else
1431 entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1432
1433 if( entry ) retVal = entry->wResId;
1434 }
1435 else dprintf(("invalid resource directory\n"));
1436 return retVal;
1437}
1438/**********************************************************************
1439 * LookupIconIdFromDirectory (USER32.379)
1440 */
1441INT WIN32API LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1442{
1443 return LookupIconIdFromDirectoryEx( dir, bIcon,
1444 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1445 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1446}
1447//******************************************************************************
1448//******************************************************************************
1449
1450//ICON cache implementation (Wine code)
1451
1452/**********************************************************************
1453 * CURSORICON_FindSharedIcon
1454 */
1455static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
1456{
1457 HANDLE handle = 0;
1458 ICONCACHE *ptr;
1459
1460 EnterCriticalSection( &IconCrst );
1461
1462 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
1463 if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
1464 {
1465 ptr->count++;
1466 handle = ptr->handle;
1467 break;
1468 }
1469
1470 LeaveCriticalSection( &IconCrst );
1471
1472 return handle;
1473}
1474
1475/*************************************************************************
1476 * CURSORICON_FindCache
1477 *
1478 * Given a handle, find the corresponding cache element
1479 *
1480 * PARAMS
1481 * Handle [I] handle to an Image
1482 *
1483 * RETURNS
1484 * Success: The cache entry
1485 * Failure: NULL
1486 *
1487 */
1488static ICONCACHE* CURSORICON_FindCache(HANDLE handle)
1489{
1490 ICONCACHE *ptr;
1491 ICONCACHE *pRet=NULL;
1492 BOOL IsFound = FALSE;
1493 int count;
1494
1495 EnterCriticalSection( &IconCrst );
1496
1497 for (count = 0, ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next, count++ )
1498 {
1499 if ( handle == ptr->handle )
1500 {
1501 IsFound = TRUE;
1502 pRet = ptr;
1503 }
1504 }
1505
1506 LeaveCriticalSection( &IconCrst );
1507
1508 return pRet;
1509}
1510
1511/**********************************************************************
1512 * CURSORICON_AddSharedIcon
1513 */
1514static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HANDLE handle )
1515{
1516 ICONCACHE *ptr = (ICONCACHE *)HeapAlloc( GetProcessHeap(), 0, sizeof(ICONCACHE) );
1517 if ( !ptr ) return;
1518
1519 ptr->hModule = hModule;
1520 ptr->hRsrc = hRsrc;
1521 ptr->handle = handle;
1522 ptr->hGroupRsrc = hGroupRsrc;
1523 ptr->count = 1;
1524
1525 EnterCriticalSection( &IconCrst );
1526 ptr->next = IconAnchor;
1527 IconAnchor = ptr;
1528 LeaveCriticalSection( &IconCrst );
1529}
1530
1531/**********************************************************************
1532 * CURSORICON_DelSharedIcon
1533 */
1534static INT CURSORICON_DelSharedIcon( HANDLE handle )
1535{
1536 INT count = -1;
1537 ICONCACHE *ptr;
1538
1539 EnterCriticalSection( &IconCrst );
1540
1541 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
1542 if ( ptr->handle == handle )
1543 {
1544 if ( ptr->count > 0 ) ptr->count--;
1545 count = ptr->count;
1546 break;
1547 }
1548
1549 LeaveCriticalSection( &IconCrst );
1550
1551 return count;
1552}
1553
1554/**********************************************************************
1555 * CURSORICON_FreeModuleIcons
1556 */
1557void CURSORICON_FreeModuleIcons( HMODULE hModule )
1558{
1559 ICONCACHE **ptr = &IconAnchor;
1560
1561 EnterCriticalSection( &IconCrst );
1562
1563 while ( *ptr )
1564 {
1565 if ( (*ptr)->hModule == hModule )
1566 {
1567 ICONCACHE *freePtr = *ptr;
1568 *ptr = freePtr->next;
1569
1570#ifdef __WIN32OS2__
1571 CURSORICON_Destroy(freePtr->handle, CID_NONSHARED);
1572#else
1573 GlobalFree( freePtr->handle );
1574#endif
1575 HeapFree( GetProcessHeap(), 0, freePtr );
1576 continue;
1577 }
1578 ptr = &(*ptr)->next;
1579 }
1580
1581 LeaveCriticalSection( &IconCrst );
1582}
1583
Note: See TracBrowser for help on using the repository browser.