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

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

Rewrote (Get)ClipCursor

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