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
];
193 CURSORICONFILEDIR
*IconDIR
;
200 CURSORICONFILEDIRENTRY
* dirEntry
;
201 ICONIMAGE
* SafeIconImage
= NULL
;
202 GRPCURSORICONDIR
* IconResDir
;
205 BOOL Icon
= (uType
== IMAGE_ICON
);
208 if (!(fuLoad
& LR_LOADFROMFILE
))
211 hinst
= User32Instance
;
213 hResInfo
= FindResourceW(hinst
, lpszName
,
214 Icon
? RT_GROUP_ICON
: RT_GROUP_CURSOR
);
215 if (hResInfo
== NULL
)
218 hResource
= LoadResource(hinst
, hResInfo
);
219 if (hResource
== NULL
)
222 IconResDir
= LockResource(hResource
);
223 if (IconResDir
== NULL
)
228 /* Find the best fitting in the IconResDir for this resolution */
229 id
= LookupIconIdFromDirectoryEx((PBYTE
)IconResDir
, Icon
, width
, height
,
230 fuLoad
& (LR_DEFAULTCOLOR
| LR_MONOCHROME
));
232 hResInfo
= FindResourceW(hinst
, MAKEINTRESOURCEW(id
),
233 Icon
? (LPCWSTR
) RT_ICON
:
234 (LPCWSTR
) RT_CURSOR
);
235 if (hResInfo
== NULL
)
240 /* Now we have found the icon we want to load.
241 * Let's see if we already loaded it */
242 if (fuLoad
& LR_SHARED
)
244 hIcon
= NtUserFindExistingCursorIcon(hinst
, hResInfo
, 0, 0);
251 hResource
= LoadResource(hinst
, hResInfo
);
252 if (hResource
== NULL
)
257 ResIcon
= LockResource(hResource
);
263 hIcon
= CreateIconFromResourceEx((PBYTE
)ResIcon
,
264 SizeofResource(hinst
, hResInfo
),
265 Icon
, 0x00030000, width
, height
,
266 fuLoad
& (LR_DEFAULTCOLOR
| LR_MONOCHROME
));
268 if (hIcon
&& 0 != (fuLoad
& LR_SHARED
))
270 NtUserSetCursorIconData((HICON
)hIcon
, NULL
, NULL
, hinst
, hResInfo
,
277 if (fuLoad
& LR_SHARED
)
279 DbgPrint("FIXME: need LR_SHARED support for loading icon images from files\n");
282 hFile
= CreateFileW(lpszName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
283 OPEN_EXISTING
, 0, NULL
);
284 if (hFile
== INVALID_HANDLE_VALUE
)
287 hSection
= CreateFileMappingW(hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
288 filesize
= GetFileSize( hFile
, NULL
);
290 if (hSection
== NULL
)
293 IconDIR
= MapViewOfFile(hSection
, FILE_MAP_READ
, 0, 0, 0);
294 CloseHandle(hSection
);
298 if (0 != IconDIR
->idReserved
||
299 (IMAGE_ICON
!= IconDIR
->idType
&& IMAGE_CURSOR
!= IconDIR
->idType
))
301 UnmapViewOfFile(IconDIR
);
305 /* Get a handle to the screen dc, the icon we create is going to be
306 * compatable with this. */
307 hScreenDc
= CreateDCW(NULL
, NULL
, NULL
, NULL
);
308 if (hScreenDc
== NULL
)
310 UnmapViewOfFile(IconDIR
);
311 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage
);
315 if (fuLoad
& LR_MONOCHROME
)
321 ColorBits
= GetDeviceCaps(hScreenDc
, BITSPIXEL
);
324 * Remove this after proper support for alpha icons will be finished.
330 /* Pick the best size. */
331 dirEntry
= CURSORICON_FindBestCursorFile( IconDIR
, width
, height
, ColorBits
);
335 UnmapViewOfFile(IconDIR
);
339 if ( dirEntry
->dwDIBOffset
> filesize
)
342 UnmapViewOfFile(IconDIR
);
346 if ( dirEntry
->dwDIBOffset
+ dirEntry
->dwDIBSize
> filesize
){
348 UnmapViewOfFile(IconDIR
);
352 SafeIconImage
= RtlAllocateHeap(GetProcessHeap(), 0, dirEntry
->dwDIBSize
);
353 if (SafeIconImage
== NULL
)
356 UnmapViewOfFile(IconDIR
);
360 memcpy(SafeIconImage
, ((PBYTE
)IconDIR
) + dirEntry
->dwDIBOffset
, dirEntry
->dwDIBSize
);
361 UnmapViewOfFile(IconDIR
);
363 /* At this point we have a copy of the icon image to play with. */
365 SafeIconImage
->icHeader
.biHeight
= SafeIconImage
->icHeader
.biHeight
/2;
367 if (SafeIconImage
->icHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
369 BITMAPCOREHEADER
* Core
= (BITMAPCOREHEADER
*)SafeIconImage
;
370 ColorCount
= (Core
->bcBitCount
<= 8) ? (1 << Core
->bcBitCount
) : 0;
371 HeaderSize
= sizeof(BITMAPCOREHEADER
) + ColorCount
* sizeof(RGBTRIPLE
);
375 ColorCount
= SafeIconImage
->icHeader
.biClrUsed
;
376 if (ColorCount
== 0 && SafeIconImage
->icHeader
.biBitCount
<= 8)
377 ColorCount
= 1 << SafeIconImage
->icHeader
.biBitCount
;
378 HeaderSize
= sizeof(BITMAPINFOHEADER
) + ColorCount
* sizeof(RGBQUAD
);
381 /* Make data point to the start of the XOR image data. */
382 Data
= (PBYTE
)SafeIconImage
+ HeaderSize
;
384 hIcon
= ICON_CreateIconFromData(hScreenDc
, Data
, SafeIconImage
, width
, height
, width
/2, height
/2);
385 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage
);
393 LoadBitmapImage(HINSTANCE hInstance
, LPCWSTR lpszName
, UINT fuLoad
)
398 LPBITMAPINFO BitmapInfo
;
399 LPBITMAPINFO PrivateInfo
;
406 if (!(fuLoad
& LR_LOADFROMFILE
))
408 if (hInstance
== NULL
)
409 hInstance
= User32Instance
;
411 hResource
= FindResourceW(hInstance
, lpszName
, RT_BITMAP
);
412 if (hResource
== NULL
)
414 hResource
= LoadResource(hInstance
, hResource
);
415 if (hResource
== NULL
)
417 BitmapInfo
= LockResource(hResource
);
418 if (BitmapInfo
== NULL
)
423 hFile
= CreateFileW(lpszName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
424 OPEN_EXISTING
, 0, NULL
);
425 if (hFile
== INVALID_HANDLE_VALUE
)
428 hSection
= CreateFileMappingW(hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
430 if (hSection
== NULL
)
433 BitmapInfo
= MapViewOfFile(hSection
, FILE_MAP_READ
, 0, 0, 0);
434 CloseHandle(hSection
);
435 if (BitmapInfo
== NULL
)
438 BitmapInfo
= (LPBITMAPINFO
)((ULONG_PTR
)BitmapInfo
+ sizeof(BITMAPFILEHEADER
));
441 if (BitmapInfo
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
443 BITMAPCOREHEADER
* Core
= (BITMAPCOREHEADER
*)BitmapInfo
;
444 ColorCount
= (Core
->bcBitCount
<= 8) ? (1 << Core
->bcBitCount
) : 0;
445 HeaderSize
= sizeof(BITMAPCOREHEADER
) + ColorCount
* sizeof(RGBTRIPLE
);
449 ColorCount
= BitmapInfo
->bmiHeader
.biClrUsed
;
450 if (ColorCount
== 0 && BitmapInfo
->bmiHeader
.biBitCount
<= 8)
451 ColorCount
= 1 << BitmapInfo
->bmiHeader
.biBitCount
;
452 HeaderSize
= sizeof(BITMAPINFOHEADER
) + ColorCount
* sizeof(RGBQUAD
);
454 Data
= (PVOID
)((ULONG_PTR
)BitmapInfo
+ HeaderSize
);
456 PrivateInfo
= RtlAllocateHeap(GetProcessHeap(), 0, HeaderSize
);
457 if (PrivateInfo
== NULL
)
459 if (fuLoad
& LR_LOADFROMFILE
)
460 UnmapViewOfFile(BitmapInfo
);
463 memcpy(PrivateInfo
, BitmapInfo
, HeaderSize
);
465 /* FIXME: Handle color conversion and transparency. */
467 hScreenDc
= CreateCompatibleDC(NULL
);
468 if (hScreenDc
== NULL
)
470 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo
);
471 if (fuLoad
& LR_LOADFROMFILE
)
472 UnmapViewOfFile(BitmapInfo
);
476 if (fuLoad
& LR_CREATEDIBSECTION
)
480 hBitmap
= CreateDIBSection(hScreenDc
, PrivateInfo
, DIB_RGB_COLORS
, NULL
,
482 GetObjectA(hBitmap
, sizeof(DIBSECTION
), &Dib
);
483 SetDIBits(hScreenDc
, hBitmap
, 0, Dib
.dsBm
.bmHeight
, Data
, BitmapInfo
,
488 hBitmap
= CreateDIBitmap(hScreenDc
, &PrivateInfo
->bmiHeader
, CBM_INIT
,
489 Data
, PrivateInfo
, DIB_RGB_COLORS
);
492 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo
);
494 if (fuLoad
& LR_LOADFROMFILE
)
495 UnmapViewOfFile(BitmapInfo
);
509 if (fuLoad
& LR_DEFAULTSIZE
)
511 if (uType
== IMAGE_ICON
)
514 cxDesired
= GetSystemMetrics(SM_CXICON
);
516 cyDesired
= GetSystemMetrics(SM_CYICON
);
518 else if (uType
== IMAGE_CURSOR
)
521 cxDesired
= GetSystemMetrics(SM_CXCURSOR
);
523 cyDesired
= GetSystemMetrics(SM_CYCURSOR
);
530 return LoadBitmapImage(hinst
, lpszName
, fuLoad
);
533 return LoadCursorIconImage(hinst
, lpszName
, cxDesired
, cyDesired
,
547 LoadBitmapA(HINSTANCE hInstance
, LPCSTR lpBitmapName
)
549 return LoadImageA(hInstance
, lpBitmapName
, IMAGE_BITMAP
, 0, 0, 0);
557 LoadBitmapW(HINSTANCE hInstance
, LPCWSTR lpBitmapName
)
559 return LoadImageW(hInstance
, lpBitmapName
, IMAGE_BITMAP
, 0, 0, 0);
576 * Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
577 * all other versions (95/2000/XP have been tested) ignore it.
580 * If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
581 * a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
582 * the copy will have the same depth as the screen.
583 * The content of the image will only be copied if the bit depth of the
584 * original image is compatible with the bit depth of the screen, or
585 * if the source is a DIB section.
586 * The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
597 objSize
= GetObjectW( hnd
, sizeof(ds
), &ds
);
598 if (!objSize
) return 0;
599 if ((desiredx
< 0) || (desiredy
< 0)) return 0;
601 if (flags
& LR_COPYFROMRESOURCE
)
603 DPRINT1("FIXME: The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
606 if (desiredx
== 0) desiredx
= ds
.dsBm
.bmWidth
;
607 if (desiredy
== 0) desiredy
= ds
.dsBm
.bmHeight
;
609 /* Allocate memory for a BITMAPINFOHEADER structure and a
610 color table. The maximum number of colors in a color table
611 is 256 which corresponds to a bitmap with depth 8.
612 Bitmaps with higher depths don't have color tables. */
613 bi
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
616 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
617 bi
->bmiHeader
.biPlanes
= ds
.dsBm
.bmPlanes
;
618 bi
->bmiHeader
.biBitCount
= ds
.dsBm
.bmBitsPixel
;
619 bi
->bmiHeader
.biCompression
= BI_RGB
;
621 if (flags
& LR_CREATEDIBSECTION
)
623 /* Create a DIB section. LR_MONOCHROME is ignored */
625 HDC dc
= CreateCompatibleDC(NULL
);
627 if (objSize
== sizeof(DIBSECTION
))
629 /* The source bitmap is a DIB.
630 Get its attributes to create an exact copy */
631 memcpy(bi
, &ds
.dsBmih
, sizeof(BITMAPINFOHEADER
));
634 /* Get the color table or the color masks */
635 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
637 bi
->bmiHeader
.biWidth
= desiredx
;
638 bi
->bmiHeader
.biHeight
= desiredy
;
639 bi
->bmiHeader
.biSizeImage
= 0;
641 res
= CreateDIBSection(dc
, bi
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
646 /* Create a device-dependent bitmap */
648 BOOL monochrome
= (flags
& LR_MONOCHROME
);
650 if (objSize
== sizeof(DIBSECTION
))
652 /* The source bitmap is a DIB section.
653 Get its attributes */
654 HDC dc
= CreateCompatibleDC(NULL
);
655 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
656 bi
->bmiHeader
.biBitCount
= ds
.dsBm
.bmBitsPixel
;
657 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
660 if (!monochrome
&& ds
.dsBm
.bmBitsPixel
== 1)
662 /* Look if the colors of the DIB are black and white */
665 (bi
->bmiColors
[0].rgbRed
== 0xff
666 && bi
->bmiColors
[0].rgbGreen
== 0xff
667 && bi
->bmiColors
[0].rgbBlue
== 0xff
668 && bi
->bmiColors
[0].rgbReserved
== 0
669 && bi
->bmiColors
[1].rgbRed
== 0
670 && bi
->bmiColors
[1].rgbGreen
== 0
671 && bi
->bmiColors
[1].rgbBlue
== 0
672 && bi
->bmiColors
[1].rgbReserved
== 0)
674 (bi
->bmiColors
[0].rgbRed
== 0
675 && bi
->bmiColors
[0].rgbGreen
== 0
676 && bi
->bmiColors
[0].rgbBlue
== 0
677 && bi
->bmiColors
[0].rgbReserved
== 0
678 && bi
->bmiColors
[1].rgbRed
== 0xff
679 && bi
->bmiColors
[1].rgbGreen
== 0xff
680 && bi
->bmiColors
[1].rgbBlue
== 0xff
681 && bi
->bmiColors
[1].rgbReserved
== 0);
684 else if (!monochrome
)
686 monochrome
= ds
.dsBm
.bmBitsPixel
== 1;
691 res
= CreateBitmap(desiredx
, desiredy
, 1, 1, NULL
);
695 HDC screenDC
= GetDC(NULL
);
696 res
= CreateCompatibleBitmap(screenDC
, desiredx
, desiredy
);
697 ReleaseDC(NULL
, screenDC
);
703 /* Only copy the bitmap if it's a DIB section or if it's
704 compatible to the screen */
707 if (objSize
== sizeof(DIBSECTION
))
713 HDC screenDC
= GetDC(NULL
);
714 int screen_depth
= GetDeviceCaps(screenDC
, BITSPIXEL
);
715 ReleaseDC(NULL
, screenDC
);
717 copyContents
= (ds
.dsBm
.bmBitsPixel
== 1 || ds
.dsBm
.bmBitsPixel
== screen_depth
);
722 /* The source bitmap may already be selected in a device context,
723 use GetDIBits/StretchDIBits and not StretchBlt */
728 dc
= CreateCompatibleDC(NULL
);
730 bi
->bmiHeader
.biWidth
= ds
.dsBm
.bmWidth
;
731 bi
->bmiHeader
.biHeight
= ds
.dsBm
.bmHeight
;
732 bi
->bmiHeader
.biSizeImage
= 0;
733 bi
->bmiHeader
.biClrUsed
= 0;
734 bi
->bmiHeader
.biClrImportant
= 0;
736 /* Fill in biSizeImage */
737 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
738 bits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, bi
->bmiHeader
.biSizeImage
);
744 /* Get the image bits of the source bitmap */
745 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, bits
, bi
, DIB_RGB_COLORS
);
747 /* Copy it to the destination bitmap */
748 oldBmp
= SelectObject(dc
, res
);
749 StretchDIBits(dc
, 0, 0, desiredx
, desiredy
,
750 0, 0, ds
.dsBm
.bmWidth
, ds
.dsBm
.bmHeight
,
751 bits
, bi
, DIB_RGB_COLORS
, SRCCOPY
);
752 SelectObject(dc
, oldBmp
);
754 HeapFree(GetProcessHeap(), 0, bits
);
760 if (flags
& LR_COPYDELETEORG
)
765 HeapFree(GetProcessHeap(), 0, bi
);
770 static BOOL IconMsgDisplayed
= FALSE
;
771 /* FIXME: support loading the image as shared from an instance */
772 if (!IconMsgDisplayed
)
774 DPRINT("FIXME: CopyImage doesn't support IMAGE_ICON correctly!\n");
775 IconMsgDisplayed
= TRUE
;
777 return CopyIcon(hnd
);
778 // return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
783 static BOOL IconMsgDisplayed
= FALSE
;
784 /* FIXME: support loading the image as shared from an instance */
785 if (!IconMsgDisplayed
)
787 DPRINT("FIXME: CopyImage doesn't support IMAGE_CURSOR correctly!\n");
788 IconMsgDisplayed
= TRUE
;
790 /* Should call CURSORICON_ExtCopy but more testing
791 * needs to be done before we change this
793 if (flags
) DPRINT1("FIXME: Flags are ignored\n");
794 return CopyCursor(hnd
);