[PATCH] Support for animated cursors
Trent Waddington
trent.waddington at gmail.com
Mon Aug 27 01:57:29 CDT 2007
Test program at:
http://rtfm.insomnia.org/~qg/animatedcursor.exe
Probably doesn't support all the possible animated cursors supported
under windows, and correct timing of animation hasn't been attempted.
Trent
-------------- next part --------------
From 760d2556e1f3ce4123b500ffc4f6d141cfcbca03 Mon Sep 17 00:00:00 2001
From: Trent Waddington <trentw at linux.localdomain>
Date: Mon, 27 Aug 2007 16:49:48 +1000
Subject: Support for animated cursors.
---
dlls/user32/cursoricon.c | 160 +++++++++++++++++++++++++++++++++++++++++++++-
include/wine/winuser16.h | 1 +
2 files changed, 159 insertions(+), 2 deletions(-)
diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c
index d528bee..6c54a50 100644
--- a/dlls/user32/cursoricon.c
+++ b/dlls/user32/cursoricon.c
@@ -664,6 +664,106 @@ static CURSORICONFILEDIRENTRY *CURSORICON_FindBestIconFile( CURSORICONFILEDIR *d
return &dir->idEntries[n];
}
+// functions for decoding animated cursors
+// see: http://www.oreilly.com/www/centers/gff/formats/micriff/
+
+typedef DWORD FOURCC; // Four-character code
+typedef FOURCC CKID; // Four-character-code chunk identifier
+typedef DWORD CKSIZE; // 32-bit unsigned size value
+
+typedef struct { // Chunk structure
+ CKID ckID; // Chunk type identifier
+ CKSIZE ckSize; // Chunk size
+ BYTE ckData[1]; // Chunk data
+} CK;
+
+typedef struct
+{
+ DWORD HeaderSize; /* Size of the subchunk data in bytes */
+ DWORD NumFrames; /* Number of icon or cursor frames */
+ DWORD NumSteps; /* Number of steps in the animation */
+ DWORD Width; /* Width of frame in pixels */
+ DWORD Height; /* Height of frame in pixels */
+ DWORD BitCount; /* Number of bits in the frame pixels */
+ DWORD NumPlanes; /* Number of color planes in the frame data */
+ DWORD DisplayRate; /* Default frame display rate */
+ DWORD Flags; /* File attributes flags */
+} ANIHEADER;
+
+ANIHEADER *anih = NULL;
+LPBYTE *ani_frames = NULL;
+DWORD ani_frame_idx = 0;
+
+static void decodeRIFF(LPBYTE bytes, DWORD size)
+{
+ CK *chunk = (CK*)bytes;
+ CKSIZE sizeWithPad = chunk->ckSize % 2 ? chunk->ckSize + 1 : chunk->ckSize;
+ switch(chunk->ckID) {
+ case 0x46464952: // RIFF
+ {
+ //DWORD form = *(DWORD*)chunk->ckData;
+ decodeRIFF(chunk->ckData + 4, chunk->ckSize - 4);
+ }
+ break;
+ case 0x5453494c: // LIST
+ {
+ //DWORD type = *(DWORD*)chunk->ckData;
+ decodeRIFF(chunk->ckData + 4, chunk->ckSize - 4);
+ }
+ break;
+ case 0x68696e61: // anih
+ {
+ anih = (ANIHEADER*)chunk->ckData;
+ ani_frames = (LPBYTE *)HeapAlloc( GetProcessHeap(), 0, sizeof(LPBYTE) * anih->NumFrames );
+ }
+ break;
+ case 0x6e6f6369: // icon
+ {
+ if (anih && ani_frame_idx < anih->NumFrames)
+ ani_frames[ani_frame_idx++] = chunk->ckData;
+ }
+ break;
+ }
+ if (sizeWithPad + 8 < size)
+ decodeRIFF(bytes + 8 + sizeWithPad, size - 8 - sizeWithPad);
+}
+
+// frames and nFrames are out parameters, it is the caller's responsibility to
+// free *frames when done. Do not use *frames after freeing data.
+void decodeAnimatedCursor(LPBYTE data, DWORD size, LPBYTE **frames, DWORD *nFrames)
+{
+ anih = NULL;
+ ani_frames = NULL;
+ ani_frame_idx = 0;
+
+ decodeRIFF(data, size);
+
+ *nFrames = 0;
+ if (anih) {
+ *frames = ani_frames;
+ *nFrames = anih->NumFrames;
+ }
+}
+
+BOOL isAnimatedCursor(LPBYTE bits)
+{
+ return bits[0] == 'R' && bits[1] == 'I' && bits[2] == 'F' && bits[3] == 'F';
+}
+
+BOOL animate_timer_started = FALSE;
+
+static void CALLBACK animate_cursor(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ HCURSOR hCursor = GetCursor();
+
+ if (hCursor) {
+ CURSORICONINFO *info = (CURSORICONINFO*)GlobalLock16( HCURSOR_16(hCursor) );
+ if (info && info->hNext) {
+ SetCursor(HCURSOR_32(info->hNext));
+ }
+ }
+}
+
/**********************************************************************
* CreateIconFromResourceEx (USER32.@)
*
@@ -699,7 +799,57 @@ HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
if (bIcon)
bmi = (BITMAPINFO *)bits;
- else /* get the hotspot */
+ else if (isAnimatedCursor(bits))
+ {
+ HICON hFirstIcon = 0;
+ LPBYTE *frames = NULL;
+ DWORD nFrames;
+ decodeAnimatedCursor(bits, cbSize, &frames, &nFrames);
+
+ if (frames) {
+ DWORD i;
+ HICON hCurIcon = 0;
+
+ for (i = 0; i < nFrames; i++) {
+ CURSORICONFILEDIR *dir;
+ CURSORICONFILEDIRENTRY *entry;
+ LPBYTE bits = frames[i];
+
+ dir = (CURSORICONFILEDIR*) bits;
+ entry = CURSORICON_FindBestCursorFile( dir, width, height, 1 );
+ if (entry) {
+ HICON hNextIcon = CreateIconFromResourceEx( &bits[entry->dwDIBOffset], entry->dwDIBSize, TRUE, 0x00030000, 0, 0, 0 );
+
+ if (hNextIcon == NULL) {
+ // umm, eep
+ continue;
+ } else {
+ if (hCurIcon) {
+ CURSORICONINFO *info = (CURSORICONINFO *)GlobalLock16( HICON_16(hCurIcon) );
+ info->hNext = HICON_16(hNextIcon);
+ GlobalUnlock16( HICON_16(hCurIcon) );
+ }
+ hCurIcon = hNextIcon;
+ }
+
+ if (i == 0)
+ hFirstIcon = hNextIcon;
+ }
+ }
+
+ if (hCurIcon) {
+ CURSORICONINFO *info = (CURSORICONINFO *)GlobalLock16( HICON_16(hCurIcon) );
+ info->hNext = HICON_16(hFirstIcon);
+ GlobalUnlock16( HICON_16(hCurIcon) );
+ }
+
+ // and cleanup
+ HeapFree( GetProcessHeap(), 0, frames );
+ }
+
+ return hFirstIcon;
+ }
+ else /* get the hotspot */
{
POINT16 *pt = (POINT16 *)bits;
hotspot = *pt;
@@ -1464,7 +1614,13 @@ HCURSOR WINAPI SetCursor( HCURSOR hCursor /* [in] Handle of cursor to show */ )
/* Change the cursor shape only if it is visible */
if (thread_info->cursor_count >= 0)
{
- USER_Driver->pSetCursor( (CURSORICONINFO*)GlobalLock16(HCURSOR_16(hCursor)) );
+ CURSORICONINFO *info = (CURSORICONINFO*)GlobalLock16(HCURSOR_16(hCursor));
+ if (info->hNext && !animate_timer_started) {
+ animate_timer_started = TRUE;
+ SetTimer(NULL, 0, 55, animate_cursor);
+ }
+
+ USER_Driver->pSetCursor( info );
GlobalUnlock16(HCURSOR_16(hCursor));
}
return hOldCursor;
diff --git a/include/wine/winuser16.h b/include/wine/winuser16.h
index 0a05bdd..db7cc32 100644
--- a/include/wine/winuser16.h
+++ b/include/wine/winuser16.h
@@ -156,6 +156,7 @@ typedef struct tagCURSORICONINFO
WORD nWidthBytes;
BYTE bPlanes;
BYTE bBitsPerPixel;
+ HICON16 hNext;
} CURSORICONINFO;
typedef struct {
--
1.4.4.3
More information about the wine-patches
mailing list