diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c
index d528bee..11c48ea 100644
--- a/dlls/user32/cursoricon.c
+++ b/dlls/user32/cursoricon.c
@@ -664,6 +664,93 @@ static CURSORICONFILEDIRENTRY *CURSORICON_FindBestIconFile( CURSORICONFILEDIR *d
     return &dir->idEntries[n];
 }
 
+/* 
+ * Functions for decoding animated cursors.
+ * Currently doesn't support well ANIs with SEQUENCE or RATE chunks.
+ * see: http://www.oreilly.com/www/centers/gff/formats/micriff/
+ */
+
+typedef DWORD FOURCC;
+typedef FOURCC CKID;
+typedef DWORD CKSIZE;
+
+typedef struct {
+    CKID     ckID;
+    CKSIZE   ckSize;
+    BYTE     ckData[1];
+} 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;
+
+typedef struct 
+{
+    ANIHEADER *anih;
+    LPBYTE *ani_frames;
+    DWORD ani_frame_idx;
+} ANIRIFFDATA;
+
+static void decodeRIFF(LPBYTE bytes, DWORD size, ANIRIFFDATA *data)
+{
+    CK *chunk = (CK*)bytes;
+    CKSIZE sizeWithPad = chunk->ckSize % 2 ? chunk->ckSize + 1 : chunk->ckSize;
+    switch(chunk->ckID) 
+    {
+    case 0x46464952:  /* RIFF */
+        decodeRIFF(chunk->ckData + 4, chunk->ckSize - 4, data);
+        break;
+    case 0x5453494c:  /* LIST */
+        decodeRIFF(chunk->ckData + 4, chunk->ckSize - 4, data);
+        break;
+    case 0x68696e61: /* anih */
+        data->anih = (ANIHEADER*)chunk->ckData;
+        data->ani_frames = (LPBYTE *)HeapAlloc( GetProcessHeap(), 0, sizeof(LPBYTE) * data->anih->NumFrames );
+        break;
+    case 0x6e6f6369: /* icon */
+        if (data->anih && data->ani_frame_idx < data->anih->NumFrames)
+            data->ani_frames[data->ani_frame_idx++] = chunk->ckData;
+        break;
+    }
+    if (sizeWithPad + 8 < size)
+        decodeRIFF(bytes + 8 + sizeWithPad, size - 8 - sizeWithPad, data);
+}
+
+/* frames and nFrames are out parameters, it is the caller's responsibility to 
+ * free *frames when done.  Do not use *frames after freeing data.
+ */
+static void decodeAnimatedCursor(LPBYTE bits, DWORD size, LPBYTE **frames, DWORD *nFrames, DWORD *delay)
+{
+    ANIRIFFDATA data;
+    data.anih = NULL;
+    data.ani_frames = NULL;
+    data.ani_frame_idx = 0;
+
+    decodeRIFF(bits, size, &data);
+
+    *nFrames = 0;
+    if (data.anih) 
+    {
+        *frames = data.ani_frames;
+        *nFrames = data.anih->NumFrames;
+        *delay = data.anih->DisplayRate * 1000 / 60;
+    }
+}
+
+static BOOL isAnimatedCursor(LPBYTE bits)
+{
+    return bits[0] == 'R' && bits[1] == 'I' && bits[2] == 'F' && bits[3] == 'F';
+}
+
 /**********************************************************************
  *		CreateIconFromResourceEx (USER32.@)
  *
@@ -699,7 +786,66 @@ 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;
+        DWORD delay;
+        decodeAnimatedCursor(bits, cbSize, &frames, &nFrames, &delay);
+
+        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) 
+                    {
+                        continue;
+                    } 
+                    else 
+                    {
+                        if (hCurIcon) 
+                        {
+                            CURSORICONINFO *info = (CURSORICONINFO *)GlobalLock16( HICON_16(hCurIcon) );
+                            CURSORICONINFO_NEXT(info) = HICON_16(hNextIcon);
+                            CURSORICONINFO_DELAY(info) = delay;
+                            GlobalUnlock16( HICON_16(hCurIcon) );
+                        }
+                        hCurIcon = hNextIcon;
+                    }
+                    
+                    if (i == 0)
+                        hFirstIcon = hNextIcon;
+                }
+            }
+
+            if (hCurIcon) 
+            {
+                CURSORICONINFO *info = (CURSORICONINFO *)GlobalLock16( HICON_16(hCurIcon) );
+                CURSORICONINFO_DELAY(info) = delay;
+                GlobalUnlock16( HICON_16(hCurIcon) );
+            }
+
+            /* and cleanup */
+            HeapFree( GetProcessHeap(), 0, frames );
+        }
+
+        return hFirstIcon;
+    }
+    else /* get the hotspot */ 
     {
         POINT16 *pt = (POINT16 *)bits;
         hotspot = *pt;
@@ -848,7 +994,8 @@ HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
     sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
 
     hObj = GlobalAlloc16( GMEM_MOVEABLE,
-                     sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
+                     sizeof(CURSORICONINFO) + sizeXor + sizeAnd + 
+                     sizeof(HICON16) + sizeof(DWORD) );
     if (hObj)
     {
         CURSORICONINFO *info;
@@ -863,9 +1010,13 @@ HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
         info->bBitsPerPixel = bmpXor.bmBitsPixel;
 
         /* Transfer the bitmap bits to the CURSORICONINFO structure */
-
         GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
         GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
+
+        /* Set animated sequence info to none */
+        CURSORICONINFO_NEXT(info) = 0;
+        CURSORICONINFO_DELAY(info) = 0;
+
         GlobalUnlock16( hObj );
     }
 
@@ -884,7 +1035,6 @@ HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
     return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
 }
 
-
 static HICON CURSORICON_LoadFromFile( LPCWSTR filename,
                              INT width, INT height, INT colors,
                              BOOL fCursor, UINT loadflags)
@@ -901,6 +1051,14 @@ static HICON CURSORICON_LoadFromFile( LPCWSTR filename,
     if (!bits)
         return hIcon;
 
+    if (isAnimatedCursor(bits))
+    {
+        hIcon = CreateIconFromResourceEx( bits, filesize, !fCursor, 0x00030000, 
+                                            0, 0, loadflags );
+        UnmapViewOfFile( bits );
+        return hIcon;
+    }
+
     dir = (CURSORICONFILEDIR*) bits;
     if ( filesize < sizeof(*dir) )
         goto end;
@@ -1464,7 +1622,8 @@ 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));
+        USER_Driver->pSetCursor( info );
         GlobalUnlock16(HCURSOR_16(hCursor));
     }
     return hOldCursor;
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index 86dad89..44eb390 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -32,6 +32,9 @@ static void *xcursor_handle;
 MAKE_FUNCPTR(XcursorImageCreate);
 MAKE_FUNCPTR(XcursorImageDestroy);
 MAKE_FUNCPTR(XcursorImageLoadCursor);
+MAKE_FUNCPTR(XcursorImagesCreate);
+MAKE_FUNCPTR(XcursorImagesDestroy);
+MAKE_FUNCPTR(XcursorImagesLoadCursor);
 # undef MAKE_FUNCPTR
 #endif /* SONAME_LIBXCURSOR */
 
@@ -109,6 +112,9 @@ void X11DRV_Xcursor_Init(void)
     LOAD_FUNCPTR(XcursorImageCreate);
     LOAD_FUNCPTR(XcursorImageDestroy);
     LOAD_FUNCPTR(XcursorImageLoadCursor);
+    LOAD_FUNCPTR(XcursorImagesCreate);
+    LOAD_FUNCPTR(XcursorImagesDestroy);
+    LOAD_FUNCPTR(XcursorImagesLoadCursor);
 #undef LOAD_FUNCPTR
 #endif /* SONAME_LIBXCURSOR */
 }
@@ -503,7 +509,6 @@ static XcursorImage *create_cursor_image( CURSORICONINFO *ptr )
     return image;
 }
 
-
 /***********************************************************************
  *              create_xcursor_cursor
  *
@@ -513,6 +518,9 @@ static Cursor create_xcursor_cursor( Display *display, CURSORICONINFO *ptr )
 {
     Cursor cursor;
     XcursorImage *image;
+    XcursorImages *images;
+    int nframes;
+    HICON16 hNext, hNextNext;
 
     if (!ptr) /* Create an empty cursor */
     {
@@ -526,23 +534,68 @@ static Cursor create_xcursor_cursor( Display *display, CURSORICONINFO *ptr )
         return cursor;
     }
 
-    image = create_cursor_image( ptr );
-    if (!image) return 0;
+    nframes = 0;
+    hNext = 0;
+    do {
+        if (hNext == 0)
+            hNext = CURSORICONINFO_NEXT(ptr);
+        else 
+        {
+            CURSORICONINFO *p = GlobalLock16(hNext);
+            if (p)
+            {
+                hNextNext = CURSORICONINFO_NEXT(p);
+                GlobalUnlock16(hNext);
+                hNext = hNextNext;
+            }
+            else
+                hNext = 0;
+        }
+    
+        nframes++;
+    } while (hNext);
 
-    /* Make sure hotspot is valid */
-    image->xhot = ptr->ptHotSpot.x;
-    image->yhot = ptr->ptHotSpot.y;
-    if (image->xhot < 0 || image->xhot >= image->width ||
-        image->yhot < 0 || image->yhot >= image->height)
-    {
-        image->xhot = image->width / 2;
-        image->yhot = image->height / 2;
-    }
+    images = pXcursorImagesCreate( nframes ); 
+
+    hNext = 0;
+    do {
+        CURSORICONINFO *info = ptr;
+        if (hNext)
+        {
+            info = GlobalLock16(hNext);
+            if (!info)
+                break;
+        }
+
+        image = create_cursor_image( info );
+        if (!image) 
+        {
+            pXcursorImagesDestroy( images );
+            GlobalUnlock16(hNext);
+            return 0;
+        }
+
+        /* Make sure hotspot is valid */
+        image->xhot = info->ptHotSpot.x;
+        image->yhot = info->ptHotSpot.y;
+        if (image->xhot < 0 || image->xhot >= image->width ||
+            image->yhot < 0 || image->yhot >= image->height)
+        {
+            image->xhot = image->width / 2;
+            image->yhot = image->height / 2;
+        }
+
+        image->delay = CURSORICONINFO_DELAY(info);
+
+        images->images[images->nimage++] = image;
 
-    image->delay = 0;
+        hNextNext = CURSORICONINFO_NEXT(info);
+        GlobalUnlock16(hNext);
+        hNext = hNextNext;
+    } while (hNext);
 
-    cursor = pXcursorImageLoadCursor( display, image );
-    pXcursorImageDestroy( image );
+    cursor = pXcursorImagesLoadCursor( display, images );
+    pXcursorImagesDestroy( images );
 
     return cursor;
 }
diff --git a/include/wine/winuser16.h b/include/wine/winuser16.h
index 0a05bdd..643b67e 100644
--- a/include/wine/winuser16.h
+++ b/include/wine/winuser16.h
@@ -157,6 +157,9 @@ typedef struct tagCURSORICONINFO
     BYTE    bPlanes;
     BYTE    bBitsPerPixel;
 } CURSORICONINFO;
+#define CURSORICONINFO_END(x) ((BYTE*)(x) + sizeof(CURSORICONINFO) + (x)->nHeight * (x)->nWidthBytes + (x)->nHeight * (x)->nWidth / 8)
+#define CURSORICONINFO_NEXT(x) *(HICON16*)(CURSORICONINFO_END(x))
+#define CURSORICONINFO_DELAY(x) *(DWORD*)(CURSORICONINFO_END(x) + sizeof(HICON16))
 
 typedef struct {
 	BOOL16		fIcon;
