|
|
/****************************** Module Header ******************************\
* Module Name: acons.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * This module contains code for dealing with animated icons/cursors. * * History: * 10-02-91 DarrinM Created. * 07-30-92 DarrinM Unicodized. \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/***************************************************************************\
* zzzSetSystemCursor (API) * * Replace a system (aka 'public') cursor with a user provided one. The new * cursor is pulled from a file (.CUR, .ICO, or .ANI) specified in WIN.INI. * * History: * 12/26/1991 DarrinM Created. * 08/04/1992 DarrinM Recreated. * 10/14/1995 SanfordS Win95 support. \***************************************************************************/ BOOL zzzSetSystemCursor( PCURSOR pcur, DWORD id) { int i;
if (!CheckWinstaWriteAttributesAccess()) { return FALSE; }
UserAssert(pcur);
/*
* Check if this cursor is one of the replaceable ones. */ for (i = 0; i < COCR_CONFIGURABLE; i++) { if (gasyscur[i].Id == (WORD)id) { break; } }
/*
* Not replaceable, bail out. */ if (i == COCR_CONFIGURABLE) { RIPMSG1(RIP_WARNING, "_SetSystemCursor: called with bad id 0x%x", id); return FALSE; }
return zzzSetSystemImage(pcur, gasyscur[i].spcur); }
/***********************************************************************\
* zzzSetSystemImage * * Places the contents of pcur into pcurSys and destroys pcur. * * 10/14/1995 Created SanfordS \***********************************************************************/ BOOL zzzSetSystemImage( PCURSOR pcur, PCURSOR pcurSys) { #define CBCOPY (max(sizeof(CURSOR), sizeof(ACON)) - FIELD_OFFSET(CURSOR, CI_COPYSTART))
#define pacon ((PACON)pcur)
char cbT[CBCOPY]; UINT CURSORF_flags;
UserAssert(pcurSys);
if (pcurSys == pcur) { return TRUE; }
/*
* All ssytem images being replaced should have ordinal names * and reference the USER module and be unowned. */ UserAssert(!IS_PTR(pcurSys->strName.Buffer)); UserAssert(pcurSys->atomModName == atomUSER32);
/*
* if pcur was an acon, transfer frame ownerships to pcurSys. */ UserAssert(pcurSys->head.ppi == NULL); if (pcur->CURSORF_flags & CURSORF_ACON && pcur->head.ppi != NULL) {
int i; PHE phe = HMPheFromObject(pcurSys); PTHREADINFO ptiOwner = ((PPROCESSINFO)phe->pOwner)->ptiList;
for (i = 0; i < pacon->cpcur; i++) { HMChangeOwnerProcess(pacon->aspcur[i], ptiOwner); pacon->aspcur[i]->head.ppi = NULL; } }
/*
* If this assert fails, the CURSOR and ACON structures were changed * incorrectly - read the comments in user.h and wingdi.w around * tagCURSOR, tagACON, and CURSINFO. */ UserAssert(FIELD_OFFSET(CURSOR, CI_FIRST) == FIELD_OFFSET(ACON, CI_FIRST));
/*
* swap everything starting from CI_COPYSTART. */ RtlCopyMemory(cbT, &pcur->CI_COPYSTART, CBCOPY); RtlCopyMemory(&pcur->CI_COPYSTART, &pcurSys->CI_COPYSTART, CBCOPY); RtlCopyMemory(&pcurSys->CI_COPYSTART, cbT, CBCOPY); /*
* Swap the CURSORF_ACON flags since they go with the swapped data. */ CURSORF_flags = pcur->CURSORF_flags & CURSORF_ACON; pcur->CURSORF_flags = (pcur->CURSORF_flags & ~CURSORF_ACON) | (pcurSys->CURSORF_flags & CURSORF_ACON); pcurSys->CURSORF_flags = (pcurSys->CURSORF_flags & ~CURSORF_ACON) | CURSORF_flags;
/*
* If we swapped acons into pcur, then we need to change the ownerhsip to * make sure they can get destroyed. */ if (pcur->CURSORF_flags & CURSORF_ACON) { int i; PTHREADINFO ptiCurrent = PtiCurrent();
for (i = 0; i < pacon->cpcur; i++) { HMChangeOwnerProcess(pacon->aspcur[i], ptiCurrent); } }
/*
* Use THREADCLEANUP so system cursors are not destroyed. */ _DestroyCursor(pcur, CURSOR_THREADCLEANUP);
/*
* If the current logical cursor is changing then force the current physical * cursor to change. */ if (gpcurLogCurrent == pcurSys) { gpcurLogCurrent = NULL; gpcurPhysCurrent = NULL; zzzUpdateCursorImage(); }
/*
* Mark the cursor as a system cursor that can be shadowed by GDI. */ pcurSys->CURSORF_flags |= CURSORF_SYSTEM;
return TRUE; #undef pacon
#undef CBCOPY
}
/***************************************************************************\
* _GetCursorFrameInfo (API) * * Example usage: * * hcur = _GetCursorFrameInfo(hacon, NULL, 4, &ccur); * hcur = _GetCursorFrameInfo(NULL, IDC_NORMAL, 0, &ccur); // get device's arrow
* * History: * 08-05-92 DarrinM Created. \***************************************************************************/ PCURSOR _GetCursorFrameInfo( PCURSOR pcur, int iFrame, PJIF pjifRate, LPINT pccur) { /*
* If this is only a single cursor (not an ACON) just return it and * a frame count of 1. */ if (!(pcur->CURSORF_flags & CURSORF_ACON)) { *pccur = 1; *pjifRate = 0; return pcur; }
/*
* Return the useful cursor information for the specified frame * of the ACON. */ #define pacon ((PACON)pcur)
if (iFrame < 0 || iFrame >= pacon->cicur) { return NULL; }
*pccur = pacon->cicur; *pjifRate = pacon->ajifRate[iFrame];
return pacon->aspcur[pacon->aicur[iFrame]]; #undef pacon
}
/***************************************************************************\
* DestroyAniIcon * * Free all the individual cursors that make up the frames of an animated * icon. * * WARNING: DestroyAniIcon assumes that all fields that an ACON shares with * a cursor will be freed by some cursor code (probably the cursor function * that calls this one). * * History: * 08-04-92 DarrinM Created. \***************************************************************************/ BOOL DestroyAniIcon( PACON pacon) { int i; PCURSOR pcur;
for (i = 0; i < pacon->cpcur; i++) { UserAssert(pacon->aspcur[i]->CURSORF_flags & CURSORF_ACONFRAME);
/*
* This should not be a public acon; if it is, unlock won't be able * to destroy it. If destroy a public icon, ownership must be called * before calling this function (see zzzSetSystemImage). */ UserAssert(GETPPI(pacon->aspcur[i]) != NULL); pcur = Unlock(&pacon->aspcur[i]); if (pcur != NULL) { _DestroyCursor(pcur, CURSOR_ALWAYSDESTROY); } }
UserFreePool(pacon->aspcur);
return TRUE; }
/***********************************************************************\
* LinkCursor * * Links unlinked cursor into the apropriate icon cache IFF its the * type of cursor that needs to be in the cache. * * Note that changing ownership if cursor objects needs to keep this * cache linking in mind. The unlink routine in * DestroyEmptyCursorObject() will handle public cursor objects made * local but that is all. * * 10/18/1995 Created SanfordS \***********************************************************************/ VOID LinkCursor( PCURSOR pcur) { /*
* Should never try to link twice! */ UserAssert(!(pcur->CURSORF_flags & CURSORF_LINKED));
/*
* We don't cache acon frames because they all belong to the * root acon object. * * We don't cache process owned objects that are not LRSHARED * either. */ if (!(pcur->CURSORF_flags & CURSORF_ACONFRAME)) { PPROCESSINFO ppi = pcur->head.ppi;
if (ppi == NULL) { /*
* Public cache object. */ pcur->pcurNext = gpcurFirst; gpcurFirst = pcur; pcur->CURSORF_flags |= CURSORF_LINKED; } else if (pcur->CURSORF_flags & CURSORF_LRSHARED) { /*
* Private cache LR_SHARED object. */ pcur->pcurNext = ppi->pCursorCache; ppi->pCursorCache = pcur; pcur->CURSORF_flags |= CURSORF_LINKED; } } }
/***************************************************************************\
* ProcessAlphaBitmap * * Examines the source bitmap to see if it supports and uses an alpha * channel. If it does, a new DIB section is created that contains a * premultiplied copy of the data from the source bitmap. * * If the source bitmap is not capable of supporting, or simply doesn't use, * an alpha channel, the return value is NULL. * * If an error occurs, the return value is NULL. * * 8/10/2000 Created DwayneN \***************************************************************************/ HBITMAP ProcessAlphaBitmap( HBITMAP hbmSource) { BITMAP bmp; BITMAPINFO bi; HBITMAP hbmAlpha; RGBQUAD * pAlphaBitmapBits; DWORD cPixels; DWORD i; RGBQUAD pixel; BOOL fAlphaChannel;
/*
* There are several code paths that end up calling us with a NULL * hbmSource. This is fine, in that it simply indicates that there * is no alpha channel. */ if (hbmSource == NULL) { return NULL; }
if (GreExtGetObjectW(hbmSource, sizeof(BITMAP), &bmp) == 0) { return NULL; }
/*
* Only single plane, 32bpp bitmaps can even contain an alpha channel. */ if (bmp.bmPlanes != 1 || bmp.bmBitsPixel != 32) { return NULL; }
/*
* Allocate room to hold the source bitmap's bits for examination. * We actually allocate a DIB - that will be passed out if the * source bitmap does indeed contain an alpha channel. */ RtlZeroMemory(&bi, sizeof(bi)); bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth = bmp.bmWidth; bi.bmiHeader.biHeight = bmp.bmHeight; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biCompression = BI_RGB;
hbmAlpha = GreCreateDIBitmapReal(gpDispInfo->hdcScreen, 0, NULL, (LPBITMAPINFO)&bi, DIB_RGB_COLORS, sizeof(bi), 0, NULL, 0, NULL, 0, 0, &pAlphaBitmapBits); if (NULL != hbmAlpha) { /*
* Set up the header again in case it was tweaked by GreCreateDIBitmapReal. */ RtlZeroMemory(&bi, sizeof(bi)); bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth = bmp.bmWidth; bi.bmiHeader.biHeight = bmp.bmHeight; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biCompression = BI_RGB;
/*
* Copy the bitmap data from the source bitmap into our alpha DIB. */ if (0 == GreGetDIBitsInternal(gpDispInfo->hdcScreen, hbmSource, 0, bi.bmiHeader.biHeight, (LPBYTE) pAlphaBitmapBits, (LPBITMAPINFO)&bi, DIB_RGB_COLORS, BITMAPWIDTHSIZE(bi.bmiHeader.biWidth, bi.bmiHeader.biHeight,1,32), bi.bmiHeader.biSize)) { GreDeleteObject(hbmAlpha); return NULL; }
/*
* We need to examine the source bitmap to see if it contains an alpha * channel. This is simply a heuristic since there is no format difference * between 32bpp 888 RGB image and 32bpp 8888 ARGB image. What we do is look * for any non-0 alpha/reserved values. If all alpha/reserved values are 0, * then the image would be 100% invisible if blitted with alpha - which is * almost cerainly not the desired result. So we assume such bitmaps are * 32bpp non-alpha. */ cPixels = bi.bmiHeader.biWidth * bi.bmiHeader.biHeight; fAlphaChannel = FALSE; for (i = 0; i < cPixels; i++) { if (pAlphaBitmapBits[i].rgbReserved != 0) { fAlphaChannel = TRUE; break; } }
if (fAlphaChannel == FALSE) { GreDeleteObject(hbmAlpha); return NULL; }
/*
* The source bitmap appears to use an alpha channel. Spin through our * copy of the bits and premultiply them. This is a necessary step to * prepare an alpha bitmap for use by GDI. */ for (i=0; i < cPixels; i++) { pixel = pAlphaBitmapBits[i];
pAlphaBitmapBits[i].rgbRed = (pixel.rgbRed * pixel.rgbReserved) / 0xFF; pAlphaBitmapBits[i].rgbGreen = (pixel.rgbGreen * pixel.rgbReserved) / 0xFF; pAlphaBitmapBits[i].rgbBlue = (pixel.rgbBlue * pixel.rgbReserved) / 0xFF; } }
return hbmAlpha; }
/***************************************************************************\
* _SetCursorIconData * * Initializes empty cursor/icons. Note that the string buffers and * pcurData are not captured. If a fault occurs in this routine, * all allocated memory will be freed when the cursors are destroyed. * * Critical side effect: If this function fails, the bitmaps must NOT * have been made public. (See CreateIconIndirect()). * * History: * 12-01-94 JimA Created. \***************************************************************************/ BOOL _SetCursorIconData( PCURSOR pcur, PUNICODE_STRING cczpstrModName, PUNICODE_STRING cczpstrName, PCURSORDATA pcurData, DWORD cbData) { #define pacon ((PACON)pcur)
int i; #if DBG
BOOL fSuccess; #endif
pcur->CURSORF_flags |= pcurData->CURSORF_flags; pcur->rt = pcurData->rt;
if (pcurData->CURSORF_flags & CURSORF_ACON) { UserAssert(pacon->aspcur == NULL); RtlCopyMemory(&pacon->cpcur, &pcurData->cpcur, sizeof(ACON) - FIELD_OFFSET(ACON, cpcur)); } else { RtlCopyMemory(&pcur->CI_COPYSTART, &pcurData->CI_COPYSTART, sizeof(CURSOR) - FIELD_OFFSET(CURSOR, CI_COPYSTART)); }
/*
* Save name of the cursor resource */ if (cczpstrName->Length != 0){ /*
* AllocateUnicodeString guards access to src Buffer with * a try block. */
if (!AllocateUnicodeString(&pcur->strName, cczpstrName)) return FALSE; } else { pcur->strName = *cczpstrName; }
/*
* Save the module name */ if (cczpstrModName->Buffer) { /*
* UserAddAtom guards access to the string with a try block. */ pcur->atomModName = UserAddAtom(cczpstrModName->Buffer, FALSE); if (pcur->atomModName == 0) { return FALSE; } }
if (pcur->CURSORF_flags & CURSORF_ACON) {
/*
* Stash away animated icon info. */ pacon = (PACON)pcur; pacon->aspcur = UserAllocPool(cbData, TAG_CURSOR); if (pacon->aspcur == NULL) return FALSE;
/*
* Copy the handle array. Do this in a try/except so the * buffer will be freed if pcurData goes away. Even though * cursor destruction would free the array, a fault will * leave the contents in an undetermined state and cause * problems during cursor destruction. */ try { RtlCopyMemory(pacon->aspcur, pcurData->aspcur, cbData); pacon->aicur = (DWORD *)((PBYTE)pacon->aspcur + (ULONG_PTR)pcurData->aicur); pacon->ajifRate = (PJIF)((PBYTE)pacon->aspcur + (ULONG_PTR)pcurData->ajifRate); } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { UserFreePool(pacon->aspcur); pacon->aspcur = NULL; return FALSE; }
/*
* Convert handles into pointers and lock them in. */ for (i = 0; i < pacon->cpcur; i++) { PCURSOR pcurT;
pcurT = (PCURSOR) HMValidateHandle(pacon->aspcur[i], TYPE_CURSOR); if (pcurT) { pacon->aspcur[i] = NULL; Lock(&pacon->aspcur[i], pcurT); } else { while (--i >= 0) { Unlock(&pacon->aspcur[i]); }
UserFreePool(pacon->aspcur); pacon->aspcur = NULL; RIPMSG0(RIP_WARNING, "SetCursorIconData: invalid cursor handle for animated cursor"); return FALSE; } } } else { PW32PROCESS W32Process = W32GetCurrentProcess();
/*
* If the icon's color bitmap has an alpha channel, pre-process it * and cache it in our hbmUserAlpha field. */ pcur->hbmUserAlpha = ProcessAlphaBitmap(pcur->hbmColor);
/*
* Make the cursor and its bitmaps public - LAST THING! */ UserAssert(pcur->hbmMask); UserAssert(pcur->cx); UserAssert(pcur->cy);
/*
* Make the cursor public so that it can be shared across processes. * Charge the curson to this very process GDI quota even if it's public. */ #if DBG
fSuccess = #endif
GreSetBitmapOwner(pcur->hbmMask, OBJECT_OWNER_PUBLIC); UserAssert(fSuccess); GreIncQuotaCount(W32Process); if (pcur->hbmColor) { #if DBG
fSuccess = #endif
GreSetBitmapOwner(pcur->hbmColor, OBJECT_OWNER_PUBLIC); UserAssert(fSuccess); GreIncQuotaCount(W32Process); } if (pcur->hbmUserAlpha != NULL) { #if DBG
fSuccess = #endif
GreSetBitmapOwner(pcur->hbmUserAlpha, OBJECT_OWNER_PUBLIC); UserAssert(fSuccess); GreIncQuotaCount(W32Process); } }
LinkCursor(pcur);
return TRUE; #undef pacon
}
|