Sweden-Number/win32/cursoricon32.c

462 lines
14 KiB
C
Raw Normal View History

Release 960324 Sun Mar 24 13:13:11 1996 Alexandre Julliard <julliard@lrc.epfl.ch> * [include/win.h] [windows/*.c] Replaced next, parent, child and owner handles by pointers in WND structure. This should improve performance, and should be reasonably safe since Microsoft did the same in Win95. * [include/wintypes.h] [*/*] Redefined HANDLE to be UINT instead of a pointer for Winelib. This allows removing a lot of unnecessary casts and NPFMTs. * [windows/caret.c] Create the caret brush upon CreateCaret(); use the bitmap dimensions for the caret. Fixed CARET_DisplayCaret() to use PatBlt(). Fri Mar 22 16:00:00 1996 Anand Kumria <akumria@ozemail.com.au> * [misc/winsocket.c] More sanity checks, fixup some erroneous return codes. * [documentation/winsock] Description of how compatible the winsock is currently. Fri Mar 22 13:05:34 1996 Ulrich Schmid <uschmid@mail.hh.provi.de> * [library/winmain.c] Set `lpszCmdParam' by concatenating arguments. * [loader/module.c] WinExec: accept Unix commands, use Wine emulator. Mon Mar 18 12:16:27 1996 Martin von Loewis <loewis@informatik.hu-berlin.de> * [if1632/kernel32.spec][win32/thread.c][include/kernel32.h] DeleteCriticalSection, EnterCriticalSection, InitializeCriticalSection, LeaveCriticalSection, TlsAlloc, TlsFree, TlsGetValue, TlsSetValue: new functions. CRITICAL_SECTION: new structure. * [if1632/kernel32.spec][win32/code_page.c] WideCharToMultiByte: new function. * [if1632/kernel32.spec][win32/file.c] GetFileAttributesA: new function. * [if1632/kernel32.spec][misc/main.c] GetEnvironmentStringsW, FreeEnvironmentStringsA, FreeEnvironmentStringsW: new functions. * [if1632/user.spec][win32/cursoricon32.c][win32/Makefile.in] cursoricon32.c: new file. LoadCursorA, LoadCursorW: modified implementation from LoadCursor to WIN32_*. LoadIconA, LoadIconW: modified implementation from LoadIconA32 to WIN32_*. * [include/struct32.h] pragma pack inserted. CURSORICON32 structures added. * [include/winnls.h] Constants CP_* and WC_* added. * [loader/pe_image.c] PE_LoadModule: call PE_InitDLL with hModule rather than wpnt. Sun Mar 17 16:59:12 1996 Albrecht Kleine <kleine@ak.sax.de> * [misc/commdlg.c] Introduced hook function handling in file dialog. Removed an unnecessary ShowWindow call in FILEDLG_WMCommand(). Thu Mar 14 10:50:00 1996 Thomas Sandford <t.d.g.sandford@prds-grn.demon.co.uk> * [if1632/gdi32.spec] Added GetNearestColor. * [if1632/kernel32.spec] Added GlobalAddAtomA. * [win32/param32.c] Added stackframe.h to includes. WIN32_GlobalAddAtomA() - new function.
1996-03-24 17:20:51 +01:00
/*
* Cursor and icon support
*
* Copyright 1995 Alexandre Julliard
* Copyright 1996 Martin von Loewis
*/
/*
* Theory:
*
* Cursors and icons are stored in a global heap block, with the
* following layout:
*
* CURSORICONINFO info;
* BYTE[] ANDbits;
* BYTE[] XORbits;
*
* The bits structures are in the format of a device-dependent bitmap.
*
* This layout is very sub-optimal, as the bitmap bits are stored in
* the X client instead of in the server like other bitmaps; however,
* some programs (notably Paint Brush) expect to be able to manipulate
* the bits directly :-(
*/
#include <string.h>
#include <stdlib.h>
#include "windows.h"
#include "bitmap.h"
#include "callback.h"
#include "cursoricon.h"
#include "sysmetrics.h"
#include "win.h"
#include "struct32.h"
#include "string32.h"
#include "resource32.h"
#include "stddebug.h"
#include "debug.h"
#include "xmalloc.h"
#include "task.h"
/**********************************************************************
* CURSORICON32_FindBestIcon
*
* Find the icon closest to the requested size and number of colors.
*/
static ICONDIRENTRY32 *CURSORICON32_FindBestIcon( CURSORICONDIR32 *dir,
int width, int height, int colors )
{
int i, maxcolors, maxwidth, maxheight;
ICONDIRENTRY32 *entry, *bestEntry = NULL;
if (dir->idCount < 1)
{
fprintf( stderr, "Icon: empty directory!\n" );
return NULL;
}
if (dir->idCount == 1) return &dir->idEntries[0].icon; /* No choice... */
/* First find the exact size with less colors */
maxcolors = 0;
for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
if ((entry->bWidth == width) && (entry->bHeight == height) &&
(entry->bColorCount <= colors) && (entry->bColorCount > maxcolors))
{
bestEntry = entry;
maxcolors = entry->bColorCount;
}
if (bestEntry) return bestEntry;
/* First find the exact size with more colors */
maxcolors = 255;
for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
if ((entry->bWidth == width) && (entry->bHeight == height) &&
(entry->bColorCount > colors) && (entry->bColorCount <= maxcolors))
{
bestEntry = entry;
maxcolors = entry->bColorCount;
}
if (bestEntry) return bestEntry;
/* Now find a smaller one with less colors */
maxcolors = maxwidth = maxheight = 0;
for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
if ((entry->bWidth <= width) && (entry->bHeight <= height) &&
(entry->bWidth >= maxwidth) && (entry->bHeight >= maxheight) &&
(entry->bColorCount <= colors) && (entry->bColorCount > maxcolors))
{
bestEntry = entry;
maxwidth = entry->bWidth;
maxheight = entry->bHeight;
maxcolors = entry->bColorCount;
}
if (bestEntry) return bestEntry;
/* Now find a smaller one with more colors */
maxcolors = 255;
maxwidth = maxheight = 0;
for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
if ((entry->bWidth <= width) && (entry->bHeight <= height) &&
(entry->bWidth >= maxwidth) && (entry->bHeight >= maxheight) &&
(entry->bColorCount > colors) && (entry->bColorCount <= maxcolors))
{
bestEntry = entry;
maxwidth = entry->bWidth;
maxheight = entry->bHeight;
maxcolors = entry->bColorCount;
}
if (bestEntry) return bestEntry;
/* Now find a larger one with less colors */
maxcolors = 0;
maxwidth = maxheight = 255;
for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
if ((entry->bWidth <= maxwidth) && (entry->bHeight <= maxheight) &&
(entry->bColorCount <= colors) && (entry->bColorCount > maxcolors))
{
bestEntry = entry;
maxwidth = entry->bWidth;
maxheight = entry->bHeight;
maxcolors = entry->bColorCount;
}
if (bestEntry) return bestEntry;
/* Now find a larger one with more colors */
maxcolors = maxwidth = maxheight = 255;
for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
if ((entry->bWidth <= maxwidth) && (entry->bHeight <= maxheight) &&
(entry->bColorCount > colors) && (entry->bColorCount <= maxcolors))
{
bestEntry = entry;
maxwidth = entry->bWidth;
maxheight = entry->bHeight;
maxcolors = entry->bColorCount;
}
return bestEntry;
}
/**********************************************************************
* CURSORICON32_FindBestCursor
*
* Find the cursor closest to the requested size.
*/
static CURSORDIRENTRY32 *CURSORICON32_FindBestCursor( CURSORICONDIR32 *dir,
int width, int height )
{
int i, maxwidth, maxheight;
CURSORDIRENTRY32 *entry, *bestEntry = NULL;
if (dir->idCount < 1)
{
fprintf( stderr, "Cursor: empty directory!\n" );
return NULL;
}
if (dir->idCount == 1) return &dir->idEntries[0].cursor; /* No choice... */
/* First find the largest one smaller than or equal to the requested size*/
maxwidth = maxheight = 0;
for(i = 0,entry = &dir->idEntries[0].cursor; i < dir->idCount; i++,entry++)
if ((entry->wWidth <= width) && (entry->wHeight <= height) &&
(entry->wWidth > maxwidth) && (entry->wHeight > maxheight))
{
bestEntry = entry;
maxwidth = entry->wWidth;
maxheight = entry->wHeight;
}
if (bestEntry) return bestEntry;
/* Now find the smallest one larger than the requested size */
maxwidth = maxheight = 255;
for(i = 0,entry = &dir->idEntries[0].cursor; i < dir->idCount; i++,entry++)
if ((entry->wWidth < maxwidth) && (entry->wHeight < maxheight))
{
bestEntry = entry;
maxwidth = entry->wWidth;
maxheight = entry->wHeight;
}
return bestEntry;
}
/**********************************************************************
* CURSORICON32_LoadDirEntry
*
* Load the icon/cursor directory for a given resource name and find the
* best matching entry.
*/
static BOOL CURSORICON32_LoadDirEntry(HANDLE hInstance, LPCWSTR name,
int width, int height, int colors,
BOOL fCursor, CURSORICONDIRENTRY32 *dirEntry)
{
HANDLE32 hRsrc;
HANDLE32 hMem;
CURSORICONDIR32 *dir;
CURSORICONDIRENTRY32 *entry = NULL;
if (!(hRsrc = FindResource32( hInstance, name,
(LPCWSTR)(fCursor ? RT_GROUP_CURSOR : RT_GROUP_ICON) )))
return FALSE;
if (!(hMem = LoadResource32( hInstance, hRsrc ))) return FALSE;
if ((dir = (CURSORICONDIR32 *)LockResource32( hMem )))
{
if (fCursor)
entry = (CURSORICONDIRENTRY32 *)CURSORICON32_FindBestCursor( dir,
width, height );
else
entry = (CURSORICONDIRENTRY32 *)CURSORICON32_FindBestIcon( dir,
width, height, colors );
if (entry) *dirEntry = *entry;
}
FreeResource32( hMem );
return (entry != NULL);
}
/**********************************************************************
* CURSORICON32_LoadHandler
*
* Create a cursor or icon from a resource.
*/
static HANDLE CURSORICON32_LoadHandler( HANDLE32 handle, HINSTANCE hInstance,
BOOL fCursor )
{
HANDLE hAndBits, hXorBits, hRes;
HDC hdc;
int size, sizeAnd, sizeXor;
POINT hotspot = { 0 ,0 };
BITMAPOBJ *bmpXor, *bmpAnd;
BITMAPINFO *bmi, *pInfo;
CURSORICONINFO *info;
char *bits;
hRes=0;
if (fCursor) /* If cursor, get the hotspot */
{
POINT *pt = (POINT *)LockResource32( handle );
hotspot = *pt;
bmi = (BITMAPINFO *)(pt + 1);
}
else bmi = (BITMAPINFO *)LockResource32( handle );
/* Create a copy of the bitmap header */
size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
/* Make sure we have room for the monochrome bitmap later on */
size = MAX( size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD) );
pInfo = (BITMAPINFO *)xmalloc( size );
memcpy( pInfo, bmi, size );
if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
{
if (pInfo->bmiHeader.biCompression != BI_RGB)
{
fprintf(stderr,"Unknown size for compressed icon bitmap.\n");
free( pInfo );
return 0;
}
pInfo->bmiHeader.biHeight /= 2;
}
else if (pInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
{
BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)pInfo;
core->bcHeight /= 2;
}
else
{
fprintf( stderr, "CURSORICON32_Load: Unknown bitmap length %ld!\n",
pInfo->bmiHeader.biSize );
free( pInfo );
return 0;
}
/* Create the XOR bitmap */
if (!(hdc = GetDC( 0 )))
{
free( pInfo );
return 0;
}
hXorBits = CreateDIBitmap( hdc, &pInfo->bmiHeader, CBM_INIT,
(char*)bmi + size, pInfo, DIB_RGB_COLORS );
/* Fix the bitmap header to load the monochrome mask */
if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
{
BITMAPINFOHEADER *bih = &pInfo->bmiHeader;
RGBQUAD *rgb = pInfo->bmiColors;
bits = (char *)bmi + size +
DIB_GetImageWidthBytes(bih->biWidth,bih->biBitCount)*bih->biHeight;
bih->biBitCount = 1;
bih->biClrUsed = bih->biClrImportant = 2;
rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
}
else
{
BITMAPCOREHEADER *bch = (BITMAPCOREHEADER *)pInfo;
RGBTRIPLE *rgb = (RGBTRIPLE *)(bch + 1);
bits = (char *)bmi + size +
DIB_GetImageWidthBytes(bch->bcWidth,bch->bcBitCount)*bch->bcHeight;
bch->bcBitCount = 1;
rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
}
/* Create the AND bitmap */
hAndBits = CreateDIBitmap( hdc, &pInfo->bmiHeader, CBM_INIT,
bits, pInfo, DIB_RGB_COLORS );
ReleaseDC( 0, hdc );
/* Now create the CURSORICONINFO structure */
bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( hXorBits, BITMAP_MAGIC );
bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( hAndBits, BITMAP_MAGIC );
sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
if (!(hRes = GlobalAlloc( GMEM_MOVEABLE,
sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
{
DeleteObject( hXorBits );
DeleteObject( hAndBits );
return 0;
}
/* Make it owned by the module */
if (hInstance) FarSetOwner( hRes, (WORD)(DWORD)GetExePtr(hInstance) );
info = (CURSORICONINFO *)GlobalLock( hRes );
info->ptHotSpot.x = hotspot.x;
info->ptHotSpot.y = hotspot.y;
info->nWidth = bmpXor->bitmap.bmWidth;
info->nHeight = bmpXor->bitmap.bmHeight;
info->nWidthBytes = bmpXor->bitmap.bmWidthBytes;
info->bPlanes = bmpXor->bitmap.bmPlanes;
info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
/* Transfer the bitmap bits to the CURSORICONINFO structure */
GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
DeleteObject( hXorBits );
DeleteObject( hAndBits );
GlobalUnlock( hRes );
return hRes;
}
/**********************************************************************
* CURSORICON32_Load
*
* Load a cursor or icon.
*/
static HANDLE CURSORICON32_Load( HANDLE hInstance, LPCWSTR name, int width,
int height, int colors, BOOL fCursor )
{
HANDLE32 handle;
HANDLE hRet;
HANDLE32 hRsrc;
CURSORICONDIRENTRY32 dirEntry;
if(!hInstance) /* OEM cursor/icon */
{
WORD resid;
if(HIWORD(name))
{
LPSTR ansi;
ansi=STRING32_DupUniToAnsi(name);
if(ansi[0]=='#') /*Check for '#xxx' name */
{
resid=atoi(ansi+1);
free(ansi);
}else{
free(ansi);
return 0;
}
}
else
resid=(WORD)(int)name;
return OBM_LoadCursorIcon(resid, fCursor);
}
/* Find the best entry in the directory */
if (!CURSORICON32_LoadDirEntry( hInstance, name, width, height,
colors, fCursor, &dirEntry )) return 0;
/* Load the resource */
if (!(hRsrc = FindResource32( hInstance,
(LPWSTR) (DWORD) dirEntry.icon.wResId,
(LPWSTR) (fCursor ? RT_CURSOR : RT_ICON )))) return 0;
if (!(handle = LoadResource32( hInstance, hRsrc ))) return 0;
hRet = CURSORICON32_LoadHandler( handle, hInstance, fCursor );
FreeResource32(handle);
return hRet;
}
/***********************************************************************
* LoadCursor
*/
HCURSOR WIN32_LoadCursorW( HANDLE hInstance, LPCWSTR name )
{
return CURSORICON32_Load( hInstance, name,
SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, 1, TRUE);
}
HCURSOR WIN32_LoadCursorA(HANDLE hInstance, LPCSTR name)
{
HCURSOR res=0;
if(!HIWORD(name))
return WIN32_LoadCursorW(hInstance, name);
else {
LPWSTR uni = STRING32_DupAnsiToUni(name);
res = WIN32_LoadCursorW(hInstance, uni);
free(uni);
}
return res;
}
/***********************************************************************
* LoadIcon
*/
HICON WIN32_LoadIconW( HANDLE hInstance, LPCWSTR name )
{
return CURSORICON32_Load( hInstance, name,
SYSMETRICS_CXICON, SYSMETRICS_CYICON,
MIN( 16, 1 << screenDepth ), FALSE );
}
HICON WIN32_LoadIconA( HANDLE hInstance, LPCSTR name)
{
HICON res=0;
if(!HIWORD(name))
return WIN32_LoadIconW(hInstance, name);
else {
LPWSTR uni = STRING32_DupAnsiToUni(name);
res = WIN32_LoadIconW(hInstance, uni);
free(uni);
}
return res;
}