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

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

SetCursor fix

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