3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * PROJECT: ReactOS user32.dll
22 * FILE: lib/user32/windows/input.c
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * 09-05-2001 CSH Created
29 /* INCLUDES ******************************************************************/
33 #include <wine/debug.h>
46 } CURSORICONFILEDIRENTRY
;
53 CURSORICONFILEDIRENTRY idEntries
[1];
58 /*forward declerations... actualy in user32\windows\icon.c but usful here****/
59 HICON
ICON_CreateCursorFromData(HDC hDC
, PVOID ImageData
, ICONIMAGE
* IconImage
, int cxDesired
, int cyDesired
, int xHotspot
, int yHotspot
);
60 HICON
ICON_CreateIconFromData(HDC hDC
, PVOID ImageData
, ICONIMAGE
* IconImage
, int cxDesired
, int cyDesired
, int xHotspot
, int yHotspot
);
61 CURSORICONDIRENTRY
*CURSORICON_FindBestIcon( CURSORICONDIR
*dir
, int width
, int height
, int colors
);
62 CURSORICONDIRENTRY
*CURSORICON_FindBestCursor( CURSORICONDIR
*dir
, int width
, int height
, int colors
);
64 /* FUNCTIONS *****************************************************************/
70 LoadImageA(HINSTANCE hinst
,
79 UNICODE_STRING NameString
;
83 RtlCreateUnicodeStringFromAsciiz(&NameString
, (LPSTR
)lpszName
);
84 lpszWName
= NameString
.Buffer
;
85 Handle
= LoadImageW(hinst
, lpszWName
, uType
, cxDesired
,
87 RtlFreeUnicodeString(&NameString
);
91 Handle
= LoadImageW(hinst
, (LPCWSTR
)lpszName
, uType
, cxDesired
,
100 * The following macro functions account for the irregularities of
101 * accessing cursor and icon resources in files and resource entries.
103 typedef BOOL (*fnGetCIEntry
)( LPVOID dir
, int n
,
104 int *width
, int *height
, int *bits
);
106 /**********************************************************************
107 * CURSORICON_FindBestCursor2
109 * Find the cursor closest to the requested size.
110 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
113 static int CURSORICON_FindBestCursor2( LPVOID dir
, fnGetCIEntry get_entry
,
114 int width
, int height
, int color
)
116 int i
, maxwidth
, maxheight
, cx
, cy
, bits
, bestEntry
= -1;
118 /* Double height to account for AND and XOR masks */
122 /* First find the largest one smaller than or equal to the requested size*/
124 maxwidth
= maxheight
= 0;
125 for ( i
= 0; get_entry( dir
, i
, &cx
, &cy
, &bits
); i
++ )
127 if ((cx
<= width
) && (cy
<= height
) &&
128 (cx
> maxwidth
) && (cy
> maxheight
) &&
136 if (bestEntry
!= -1) return bestEntry
;
138 /* Now find the smallest one larger than the requested size */
140 maxwidth
= maxheight
= 255;
141 for ( i
= 0; get_entry( dir
, i
, &cx
, &cy
, &bits
); i
++ )
143 if (((cx
< maxwidth
) && (cy
< maxheight
) && (bits
== 1)) ||
155 static BOOL
CURSORICON_GetFileEntry( LPVOID dir
, int n
,
156 int *width
, int *height
, int *bits
)
158 CURSORICONFILEDIR
*filedir
= dir
;
159 CURSORICONFILEDIRENTRY
*entry
;
161 if ( filedir
->idCount
<= n
)
163 entry
= &filedir
->idEntries
[n
];
164 *width
= entry
->bWidth
;
165 *height
= entry
->bHeight
;
166 *bits
= entry
->bColorCount
;
170 static CURSORICONFILEDIRENTRY
*CURSORICON_FindBestCursorFile( CURSORICONFILEDIR
*dir
,
171 int width
, int height
, int color
)
173 int n
= CURSORICON_FindBestCursor2( dir
, CURSORICON_GetFileEntry
,
174 width
, height
, color
);
177 return &dir
->idEntries
[n
];
194 CURSORICONFILEDIR
*IconDIR
;
201 CURSORICONFILEDIRENTRY
* dirEntry
;
202 ICONIMAGE
* SafeIconImage
= NULL
;
203 GRPCURSORICONDIR
* IconResDir
;
206 BOOL Icon
= (uType
== IMAGE_ICON
);
209 if (!(fuLoad
& LR_LOADFROMFILE
))
212 hinst
= User32Instance
;
214 hResource
= hfRes
= FindResourceW(hinst
, lpszName
,
215 Icon
? RT_GROUP_ICON
: RT_GROUP_CURSOR
);
216 if (hResource
== NULL
)
219 if (fuLoad
& LR_SHARED
)
221 hIcon
= NtUserFindExistingCursorIcon(hinst
, (HRSRC
)hfRes
, width
, height
);
226 hResource
= LoadResource(hinst
, hResource
);
227 if (hResource
== NULL
)
230 IconResDir
= LockResource(hResource
);
231 if (IconResDir
== NULL
)
235 * Find the best fitting in the IconResDir for this resolution
238 id
= LookupIconIdFromDirectoryEx((PBYTE
)IconResDir
, Icon
, width
, height
,
239 fuLoad
& (LR_DEFAULTCOLOR
| LR_MONOCHROME
));
241 h2Resource
= FindResourceW(hinst
, MAKEINTRESOURCEW(id
),
242 Icon
? MAKEINTRESOURCEW(RT_ICON
) :
243 MAKEINTRESOURCEW(RT_CURSOR
));
244 if (h2Resource
== NULL
)
247 hResource
= LoadResource(hinst
, h2Resource
);
248 if (hResource
== NULL
)
251 ResIcon
= LockResource(hResource
);
255 hIcon
= CreateIconFromResourceEx((PBYTE
)ResIcon
,
256 SizeofResource(hinst
, h2Resource
),
257 Icon
, 0x00030000, width
, height
,
258 fuLoad
& (LR_DEFAULTCOLOR
| LR_MONOCHROME
));
259 if (hIcon
&& 0 != (fuLoad
& LR_SHARED
))
261 NtUserSetCursorIconData((HICON
)hIcon
, NULL
, NULL
, hinst
, (HRSRC
)hfRes
,
268 if (fuLoad
& LR_SHARED
)
270 DbgPrint("FIXME: need LR_SHARED support for loading icon images from files\n");
273 hFile
= CreateFileW(lpszName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
274 OPEN_EXISTING
, 0, NULL
);
275 if (hFile
== INVALID_HANDLE_VALUE
)
278 hSection
= CreateFileMappingW(hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
279 filesize
= GetFileSize( hFile
, NULL
);
281 if (hSection
== NULL
)
284 IconDIR
= MapViewOfFile(hSection
, FILE_MAP_READ
, 0, 0, 0);
285 CloseHandle(hSection
);
289 if (0 != IconDIR
->idReserved
||
290 (IMAGE_ICON
!= IconDIR
->idType
&& IMAGE_CURSOR
!= IconDIR
->idType
))
292 UnmapViewOfFile(IconDIR
);
296 /* Get a handle to the screen dc, the icon we create is going to be
297 * compatable with this. */
298 hScreenDc
= CreateDCW(NULL
, NULL
, NULL
, NULL
);
299 if (hScreenDc
== NULL
)
301 UnmapViewOfFile(IconDIR
);
302 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage
);
306 if (fuLoad
& LR_MONOCHROME
)
312 ColorBits
= GetDeviceCaps(hScreenDc
, BITSPIXEL
);
315 * Remove this after proper support for alpha icons will be finished.
321 /* Pick the best size. */
322 dirEntry
= CURSORICON_FindBestCursorFile( IconDIR
, width
, height
, ColorBits
);
326 UnmapViewOfFile(IconDIR
);
330 if ( dirEntry
->dwDIBOffset
> filesize
)
333 UnmapViewOfFile(IconDIR
);
337 if ( dirEntry
->dwDIBOffset
+ dirEntry
->dwDIBSize
> filesize
){
339 UnmapViewOfFile(IconDIR
);
343 SafeIconImage
= RtlAllocateHeap(GetProcessHeap(), 0, dirEntry
->dwDIBSize
);
344 if (SafeIconImage
== NULL
)
347 UnmapViewOfFile(IconDIR
);
351 memcpy(SafeIconImage
, ((PBYTE
)IconDIR
) + dirEntry
->dwDIBOffset
, dirEntry
->dwDIBSize
);
352 UnmapViewOfFile(IconDIR
);
354 /* At this point we have a copy of the icon image to play with. */
356 SafeIconImage
->icHeader
.biHeight
= SafeIconImage
->icHeader
.biHeight
/2;
358 if (SafeIconImage
->icHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
360 BITMAPCOREHEADER
* Core
= (BITMAPCOREHEADER
*)SafeIconImage
;
361 ColorCount
= (Core
->bcBitCount
<= 8) ? (1 << Core
->bcBitCount
) : 0;
362 HeaderSize
= sizeof(BITMAPCOREHEADER
) + ColorCount
* sizeof(RGBTRIPLE
);
366 ColorCount
= SafeIconImage
->icHeader
.biClrUsed
;
367 if (ColorCount
== 0 && SafeIconImage
->icHeader
.biBitCount
<= 8)
368 ColorCount
= 1 << SafeIconImage
->icHeader
.biBitCount
;
369 HeaderSize
= sizeof(BITMAPINFOHEADER
) + ColorCount
* sizeof(RGBQUAD
);
372 /* Make data point to the start of the XOR image data. */
373 Data
= (PBYTE
)SafeIconImage
+ HeaderSize
;
375 hIcon
= ICON_CreateIconFromData(hScreenDc
, Data
, SafeIconImage
, width
, height
, width
/2, height
/2);
376 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage
);
384 LoadBitmapImage(HINSTANCE hInstance
, LPCWSTR lpszName
, UINT fuLoad
)
389 LPBITMAPINFO BitmapInfo
;
390 LPBITMAPINFO PrivateInfo
;
397 if (!(fuLoad
& LR_LOADFROMFILE
))
399 if (hInstance
== NULL
)
400 hInstance
= User32Instance
;
402 hResource
= FindResourceW(hInstance
, lpszName
, RT_BITMAP
);
403 if (hResource
== NULL
)
405 hResource
= LoadResource(hInstance
, hResource
);
406 if (hResource
== NULL
)
408 BitmapInfo
= LockResource(hResource
);
409 if (BitmapInfo
== NULL
)
414 hFile
= CreateFileW(lpszName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
415 OPEN_EXISTING
, 0, NULL
);
416 if (hFile
== INVALID_HANDLE_VALUE
)
419 hSection
= CreateFileMappingW(hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
421 if (hSection
== NULL
)
424 BitmapInfo
= MapViewOfFile(hSection
, FILE_MAP_READ
, 0, 0, 0);
425 CloseHandle(hSection
);
426 if (BitmapInfo
== NULL
)
429 BitmapInfo
= (LPBITMAPINFO
)((ULONG_PTR
)BitmapInfo
+ sizeof(BITMAPFILEHEADER
));
432 if (BitmapInfo
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
434 BITMAPCOREHEADER
* Core
= (BITMAPCOREHEADER
*)BitmapInfo
;
435 ColorCount
= (Core
->bcBitCount
<= 8) ? (1 << Core
->bcBitCount
) : 0;
436 HeaderSize
= sizeof(BITMAPCOREHEADER
) + ColorCount
* sizeof(RGBTRIPLE
);
440 ColorCount
= BitmapInfo
->bmiHeader
.biClrUsed
;
441 if (ColorCount
== 0 && BitmapInfo
->bmiHeader
.biBitCount
<= 8)
442 ColorCount
= 1 << BitmapInfo
->bmiHeader
.biBitCount
;
443 HeaderSize
= sizeof(BITMAPINFOHEADER
) + ColorCount
* sizeof(RGBQUAD
);
445 Data
= (PVOID
)((ULONG_PTR
)BitmapInfo
+ HeaderSize
);
447 PrivateInfo
= RtlAllocateHeap(GetProcessHeap(), 0, HeaderSize
);
448 if (PrivateInfo
== NULL
)
450 if (fuLoad
& LR_LOADFROMFILE
)
451 UnmapViewOfFile(BitmapInfo
);
454 memcpy(PrivateInfo
, BitmapInfo
, HeaderSize
);
456 /* FIXME: Handle color conversion and transparency. */
458 hScreenDc
= CreateCompatibleDC(NULL
);
459 if (hScreenDc
== NULL
)
461 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo
);
462 if (fuLoad
& LR_LOADFROMFILE
)
463 UnmapViewOfFile(BitmapInfo
);
467 if (fuLoad
& LR_CREATEDIBSECTION
)
471 hBitmap
= CreateDIBSection(hScreenDc
, PrivateInfo
, DIB_RGB_COLORS
, NULL
,
473 GetObjectA(hBitmap
, sizeof(DIBSECTION
), &Dib
);
474 SetDIBits(hScreenDc
, hBitmap
, 0, Dib
.dsBm
.bmHeight
, Data
, BitmapInfo
,
479 hBitmap
= CreateDIBitmap(hScreenDc
, &PrivateInfo
->bmiHeader
, CBM_INIT
,
480 Data
, PrivateInfo
, DIB_RGB_COLORS
);
483 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo
);
485 if (fuLoad
& LR_LOADFROMFILE
)
486 UnmapViewOfFile(BitmapInfo
);
500 if (fuLoad
& LR_DEFAULTSIZE
)
502 if (uType
== IMAGE_ICON
)
505 cxDesired
= GetSystemMetrics(SM_CXICON
);
507 cyDesired
= GetSystemMetrics(SM_CYICON
);
509 else if (uType
== IMAGE_CURSOR
)
512 cxDesired
= GetSystemMetrics(SM_CXCURSOR
);
514 cyDesired
= GetSystemMetrics(SM_CYCURSOR
);
521 return LoadBitmapImage(hinst
, lpszName
, fuLoad
);
524 return LoadCursorIconImage(hinst
, lpszName
, cxDesired
, cyDesired
,
538 LoadBitmapA(HINSTANCE hInstance
, LPCSTR lpBitmapName
)
540 return LoadImageA(hInstance
, lpBitmapName
, IMAGE_BITMAP
, 0, 0, 0);
548 LoadBitmapW(HINSTANCE hInstance
, LPCWSTR lpBitmapName
)
550 return LoadImageW(hInstance
, lpBitmapName
, IMAGE_BITMAP
, 0, 0, 0);
567 * Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
568 * all other versions (95/2000/XP have been tested) ignore it.
571 * If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
572 * a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
573 * the copy will have the same depth as the screen.
574 * The content of the image will only be copied if the bit depth of the
575 * original image is compatible with the bit depth of the screen, or
576 * if the source is a DIB section.
577 * The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
588 objSize
= GetObjectW( hnd
, sizeof(ds
), &ds
);
589 if (!objSize
) return 0;
590 if ((desiredx
< 0) || (desiredy
< 0)) return 0;
592 if (flags
& LR_COPYFROMRESOURCE
)
594 DPRINT1("FIXME: The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
597 if (desiredx
== 0) desiredx
= ds
.dsBm
.bmWidth
;
598 if (desiredy
== 0) desiredy
= ds
.dsBm
.bmHeight
;
600 /* Allocate memory for a BITMAPINFOHEADER structure and a
601 color table. The maximum number of colors in a color table
602 is 256 which corresponds to a bitmap with depth 8.
603 Bitmaps with higher depths don't have color tables. */
604 bi
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
607 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
608 bi
->bmiHeader
.biPlanes
= ds
.dsBm
.bmPlanes
;
609 bi
->bmiHeader
.biBitCount
= ds
.dsBm
.bmBitsPixel
;
610 bi
->bmiHeader
.biCompression
= BI_RGB
;
612 if (flags
& LR_CREATEDIBSECTION
)
614 /* Create a DIB section. LR_MONOCHROME is ignored */
616 HDC dc
= CreateCompatibleDC(NULL
);
618 if (objSize
== sizeof(DIBSECTION
))
620 /* The source bitmap is a DIB.
621 Get its attributes to create an exact copy */
622 memcpy(bi
, &ds
.dsBmih
, sizeof(BITMAPINFOHEADER
));
625 /* Get the color table or the color masks */
626 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
628 bi
->bmiHeader
.biWidth
= desiredx
;
629 bi
->bmiHeader
.biHeight
= desiredy
;
630 bi
->bmiHeader
.biSizeImage
= 0;
632 res
= CreateDIBSection(dc
, bi
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
637 /* Create a device-dependent bitmap */
639 BOOL monochrome
= (flags
& LR_MONOCHROME
);
641 if (objSize
== sizeof(DIBSECTION
))
643 /* The source bitmap is a DIB section.
644 Get its attributes */
645 HDC dc
= CreateCompatibleDC(NULL
);
646 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
647 bi
->bmiHeader
.biBitCount
= ds
.dsBm
.bmBitsPixel
;
648 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
651 if (!monochrome
&& ds
.dsBm
.bmBitsPixel
== 1)
653 /* Look if the colors of the DIB are black and white */
656 (bi
->bmiColors
[0].rgbRed
== 0xff
657 && bi
->bmiColors
[0].rgbGreen
== 0xff
658 && bi
->bmiColors
[0].rgbBlue
== 0xff
659 && bi
->bmiColors
[0].rgbReserved
== 0
660 && bi
->bmiColors
[1].rgbRed
== 0
661 && bi
->bmiColors
[1].rgbGreen
== 0
662 && bi
->bmiColors
[1].rgbBlue
== 0
663 && bi
->bmiColors
[1].rgbReserved
== 0)
665 (bi
->bmiColors
[0].rgbRed
== 0
666 && bi
->bmiColors
[0].rgbGreen
== 0
667 && bi
->bmiColors
[0].rgbBlue
== 0
668 && bi
->bmiColors
[0].rgbReserved
== 0
669 && bi
->bmiColors
[1].rgbRed
== 0xff
670 && bi
->bmiColors
[1].rgbGreen
== 0xff
671 && bi
->bmiColors
[1].rgbBlue
== 0xff
672 && bi
->bmiColors
[1].rgbReserved
== 0);
675 else if (!monochrome
)
677 monochrome
= ds
.dsBm
.bmBitsPixel
== 1;
682 res
= CreateBitmap(desiredx
, desiredy
, 1, 1, NULL
);
686 HDC screenDC
= GetDC(NULL
);
687 res
= CreateCompatibleBitmap(screenDC
, desiredx
, desiredy
);
688 ReleaseDC(NULL
, screenDC
);
694 /* Only copy the bitmap if it's a DIB section or if it's
695 compatible to the screen */
698 if (objSize
== sizeof(DIBSECTION
))
704 HDC screenDC
= GetDC(NULL
);
705 int screen_depth
= GetDeviceCaps(screenDC
, BITSPIXEL
);
706 ReleaseDC(NULL
, screenDC
);
708 copyContents
= (ds
.dsBm
.bmBitsPixel
== 1 || ds
.dsBm
.bmBitsPixel
== screen_depth
);
713 /* The source bitmap may already be selected in a device context,
714 use GetDIBits/StretchDIBits and not StretchBlt */
719 dc
= CreateCompatibleDC(NULL
);
721 bi
->bmiHeader
.biWidth
= ds
.dsBm
.bmWidth
;
722 bi
->bmiHeader
.biHeight
= ds
.dsBm
.bmHeight
;
723 bi
->bmiHeader
.biSizeImage
= 0;
724 bi
->bmiHeader
.biClrUsed
= 0;
725 bi
->bmiHeader
.biClrImportant
= 0;
727 /* Fill in biSizeImage */
728 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
729 bits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, bi
->bmiHeader
.biSizeImage
);
735 /* Get the image bits of the source bitmap */
736 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, bits
, bi
, DIB_RGB_COLORS
);
738 /* Copy it to the destination bitmap */
739 oldBmp
= SelectObject(dc
, res
);
740 StretchDIBits(dc
, 0, 0, desiredx
, desiredy
,
741 0, 0, ds
.dsBm
.bmWidth
, ds
.dsBm
.bmHeight
,
742 bits
, bi
, DIB_RGB_COLORS
, SRCCOPY
);
743 SelectObject(dc
, oldBmp
);
745 HeapFree(GetProcessHeap(), 0, bits
);
751 if (flags
& LR_COPYDELETEORG
)
756 HeapFree(GetProcessHeap(), 0, bi
);
761 static BOOL IconMsgDisplayed
= FALSE
;
762 /* FIXME: support loading the image as shared from an instance */
763 if (!IconMsgDisplayed
)
765 DPRINT("FIXME: CopyImage doesn't support IMAGE_ICON correctly!\n");
766 IconMsgDisplayed
= TRUE
;
768 return CopyIcon(hnd
);
769 // return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
774 static BOOL IconMsgDisplayed
= FALSE
;
775 /* FIXME: support loading the image as shared from an instance */
776 if (!IconMsgDisplayed
)
778 DPRINT("FIXME: CopyImage doesn't support IMAGE_CURSOR correctly!\n");
779 IconMsgDisplayed
= TRUE
;
781 /* Should call CURSORICON_ExtCopy but more testing
782 * needs to be done before we change this
784 if (flags
) DPRINT1("FIXME: Flags are ignored\n");
785 return CopyCursor(hnd
);