diff -urN wine-1.0.orig/dlls/user32/cursoricon.c wine-1.0/dlls/user32/cursoricon.c --- wine-1.0.orig/dlls/user32/cursoricon.c 2008-06-17 16:07:31.000000000 +0200 +++ wine-1.0/dlls/user32/cursoricon.c 2008-06-27 15:53:37.000000000 +0200 @@ -5,6 +5,7 @@ * 1996 Martin Von Loewis * 1997 Alex Korobka * 1998 Turchanov Sergey + * 2007 Henri Verbeet * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,7 +25,9 @@ /* * Theory: * - * Cursors and icons are stored in a global heap block, with the + * 32-bit cursors and icons are stored in the server. + * + * 16-bit cursors and icons are stored in a global heap block, with the * following layout: * * CURSORICONINFO info; @@ -46,6 +49,8 @@ #include #include +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "wingdi.h" @@ -54,6 +59,8 @@ #include "wine/winuser16.h" #include "wine/exception.h" #include "wine/debug.h" +#include "wine/list.h" +#include "wine/server.h" #include "user_private.h" WINE_DEFAULT_DEBUG_CHANNEL(cursor); @@ -126,6 +133,344 @@ static const WORD ICON_HOTSPOT = 0x4242; +/* What is a good table size? */ +#define CURSOR_HASH_SIZE 97 + +typedef struct { + HCURSOR16 cursor16; + HCURSOR cursor32; + struct list entry16; + struct list entry32; +} cursor_map_entry_t; + +static int get_bitmap_width_bytes( int width, int bpp ); + +static struct list cursor16to32[CURSOR_HASH_SIZE]; +static struct list cursor32to16[CURSOR_HASH_SIZE]; + +static inline int hash_cursor_handle( DWORD handle ) +{ + return handle % CURSOR_HASH_SIZE; +} + +static void add_cursor16to32_entry( cursor_map_entry_t *entry ) +{ + int idx = hash_cursor_handle( entry->cursor16 ); + + if (!cursor16to32[idx].next) list_init( &cursor16to32[idx] ); + + list_add_head( &cursor16to32[idx], &entry->entry16 ); +} + +static void add_cursor32to16_entry( cursor_map_entry_t *entry ) +{ + int idx = hash_cursor_handle( (DWORD)entry->cursor32 ); + + if (!cursor32to16[idx].next) list_init( &cursor32to16[idx] ); + + list_add_head( &cursor32to16[idx], &entry->entry32 ); +} + +static cursor_map_entry_t *remove_cursor16to32_entry( HCURSOR16 cursor16 ) +{ + cursor_map_entry_t *entry = NULL; + int idx = hash_cursor_handle( cursor16 ); + + if (cursor16to32[idx].next) + { + LIST_FOR_EACH_ENTRY( entry, &cursor16to32[idx], cursor_map_entry_t, entry16 ) + if (entry->cursor16 == cursor16) + { + list_remove( &entry->entry16 ); + return entry; + } + } + + return entry; +} + +static cursor_map_entry_t *remove_cursor32to16_entry( HCURSOR cursor32 ) +{ + cursor_map_entry_t *entry = NULL; + int idx = hash_cursor_handle( (DWORD)cursor32 ); + + if (cursor32to16[idx].next) + { + LIST_FOR_EACH_ENTRY( entry, &cursor32to16[idx], cursor_map_entry_t, entry32 ) + if (entry->cursor32 == cursor32) + { + list_remove( &entry->entry32 ); + return entry; + } + } + + return entry; +} + +/* Ask the server for a cursor */ +static HCURSOR create_cursor( unsigned int num_frames, unsigned int delay ) +{ + HCURSOR cursor = 0; + + SERVER_START_REQ(create_cursor) + { + req->num_frames = num_frames; + req->delay = delay; + if (!wine_server_call_err( req )) cursor = reply->handle; + } + SERVER_END_REQ; + + return cursor; +} + +/* Tell the server to kill a cursor */ +static HCURSOR16 destroy_cursor( HCURSOR cursor ) +{ + cursor_map_entry_t *entry; + HCURSOR16 cursor16 = 0; + + if (!cursor) return 0; + + SERVER_START_REQ(destroy_cursor) + { + req->handle = cursor; + wine_server_call( req ); + } + SERVER_END_REQ; + + entry = remove_cursor32to16_entry( cursor ); + if (entry) + { + cursor16 = entry->cursor16; + remove_cursor16to32_entry( cursor16 ); + HeapFree( GetProcessHeap(), 0, entry ); + } + + return GlobalFree16( cursor16 ); +} + +/* Upload a cursor frame to the server */ +static void set_cursor_frame( HCURSOR cursor, unsigned int frame_idx, cursor_frame_t *frame ) +{ + SERVER_START_REQ(set_cursor_frame) + { + req->handle = cursor; + req->frame_idx = frame_idx; + req->xhot = frame->xhot; + req->yhot = frame->yhot; + req->width = frame->width; + req->height = frame->height; + req->and_width_bytes = frame->and_width_bytes; + req->xor_width_bytes = frame->xor_width_bytes; + req->planes = frame->planes; + req->bpp = frame->bpp; + wine_server_add_data( req, frame->bits, (frame->and_width_bytes + frame->xor_width_bytes) * frame->height ); + wine_server_call( req ); + } + SERVER_END_REQ; +} + +/* Download a cursor frame from the server */ +static BOOL get_cursor_frame( HCURSOR cursor, unsigned int frame_idx, cursor_frame_t *frame ) +{ + NTSTATUS res; + /* Enough for a 32-bits 32x32 cursor / icon. */ + unsigned int buffer_size = 4224; + unsigned int count = 0; + + do + { + frame->bits = HeapAlloc(GetProcessHeap(), 0, buffer_size); + SERVER_START_REQ(get_cursor_frame) + { + req->handle = cursor; + req->frame_idx = frame_idx; + wine_server_set_reply( req, frame->bits, buffer_size); + if (!(res = wine_server_call_err( req ))) + { + frame->xhot = reply->xhot; + frame->yhot = reply->yhot; + frame->width = reply->width; + frame->height = reply->height; + frame->and_width_bytes = reply->and_width_bytes; + frame->xor_width_bytes = reply->xor_width_bytes; + frame->planes = reply->planes; + frame->bpp = reply->bpp; + } else { + HeapFree( GetProcessHeap(), 0, frame->bits ); + buffer_size = (reply->and_width_bytes + reply->xor_width_bytes) * reply->height; + } + } + SERVER_END_REQ; + } while (res == STATUS_BUFFER_OVERFLOW && !count++); + + if (!frame->height) + { + HeapFree( GetProcessHeap(), 0, frame->bits ); + + return FALSE; + } + + return TRUE; +} + +/* Retrieve a cursor and all its frames from the server */ +static cursor_t *get_cursor_object( HCURSOR handle ) +{ + unsigned int i; + cursor_t *cursor = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(cursor_t) ); + + SERVER_START_REQ(get_cursor_info) + { + req->handle = handle; + if (!wine_server_call_err( req )) + { + cursor->num_frames = reply->num_frames; + cursor->delay = reply->delay; + } + } + SERVER_END_REQ; + + if (!cursor->num_frames) + { + HeapFree( GetProcessHeap(), 0, cursor ); + return NULL; + } + + cursor->frames = HeapAlloc( GetProcessHeap(), 0, cursor->num_frames * sizeof(cursor_frame_t) ); + for (i = 0; i < cursor->num_frames; ++i) + { + if (!get_cursor_frame( handle, i, &cursor->frames[i] )) + { + unsigned int j; + + for (j = 0; j < i; ++j) + { + HeapFree( GetProcessHeap(), 0, cursor->frames[j].bits ); + } + HeapFree( GetProcessHeap(), 0, cursor->frames ); + HeapFree( GetProcessHeap(), 0, cursor ); + + return NULL; + } + } + + return cursor; +} + +static void destroy_cursor_object( cursor_t *cursor ) +{ + unsigned int i; + + if (!cursor) return; + + for (i = 0; i < cursor->num_frames; ++i) + { + HeapFree( GetProcessHeap(), 0, cursor->frames[i].bits ); + } + HeapFree( GetProcessHeap(), 0, cursor->frames ); + HeapFree( GetProcessHeap(), 0, cursor ); +} + +/* Lookup the cursor's 16-bit handle. Create one if it doesn't already exist. */ +HCURSOR16 get_cursor_handle16( HCURSOR cursor32, BOOL create ) +{ + cursor_map_entry_t *entry; + int idx = hash_cursor_handle( (DWORD)cursor32 ); + + if (!cursor32) return 0; + + if (cursor32to16[idx].next) + { + LIST_FOR_EACH_ENTRY( entry, &cursor32to16[idx], cursor_map_entry_t, entry32 ) + if (entry->cursor32 == cursor32) return entry->cursor16; + } + + /* 16-bit cursor handle not found, create one */ + if (create) + { + size_t bits_size; + HCURSOR16 cursor16; + cursor_frame_t frame; + + if (!get_cursor_frame( cursor32, 0, &frame )) return 0; + + entry = HeapAlloc( GetProcessHeap(), 0, sizeof(cursor_map_entry_t) ); + bits_size = (frame.and_width_bytes + frame.xor_width_bytes) * frame.height; + cursor16 = GlobalAlloc16( GMEM_MOVEABLE, sizeof(CURSORICONINFO) + bits_size ); + if (cursor16) + { + CURSORICONINFO *info; + + info = (CURSORICONINFO *)GlobalLock16( cursor16 ); + info->ptHotSpot.x = frame.xhot; + info->ptHotSpot.y = frame.yhot; + info->nWidth = frame.width; + info->nHeight = frame.height; + info->nWidthBytes = frame.xor_width_bytes; + info->bPlanes = frame.planes; + info->bBitsPerPixel = frame.bpp; + CopyMemory( info + 1, frame.bits, bits_size ); + GlobalUnlock16( cursor16 ); + } + HeapFree( GetProcessHeap(), 0, frame.bits ); + + entry->cursor16 = cursor16; + entry->cursor32 = cursor32; + add_cursor16to32_entry( entry ); + add_cursor32to16_entry( entry ); + + return cursor16; + } + + return 0; +} + +HCURSOR get_cursor_handle32( HCURSOR16 cursor16 ) +{ + cursor_map_entry_t *entry; + int idx = hash_cursor_handle( cursor16 ); + + if (!cursor16) return 0; + + if (cursor16to32[idx].next) + { + LIST_FOR_EACH_ENTRY( entry, &cursor16to32[idx], cursor_map_entry_t, entry16 ) + if (entry->cursor16 == cursor16) return entry->cursor32; + } + + return 0; +} + +static void update_cursor_32from16( HCURSOR cursor32 ) +{ + size_t bits_size; + HCURSOR16 cursor16; + cursor_frame_t frame; + CURSORICONINFO *info; + + if (!cursor32) return; + + cursor16 = get_cursor_handle16( cursor32, FALSE ); + if (!cursor16) return; + + info = (CURSORICONINFO *)GlobalLock16( cursor16 ); + frame.xhot = info->ptHotSpot.x; + frame.yhot = info->ptHotSpot.y; + frame.width = info->nWidth; + frame.height = info->nHeight; + frame.and_width_bytes = get_bitmap_width_bytes( info->nWidth, 1 ); + frame.xor_width_bytes = info->nWidthBytes; + frame.planes = info->bPlanes; + frame.bpp = info->bBitsPerPixel; + bits_size = (frame.and_width_bytes + frame.xor_width_bytes) * frame.height; + frame.bits = HeapAlloc( GetProcessHeap(), 0, bits_size ); + CopyMemory( frame.bits, info + 1, bits_size ); + GlobalUnlock16( cursor16 ); + + set_cursor_frame( cursor32, 0, &frame ); + HeapFree( GetProcessHeap(), 0, frame.bits ); +} /*********************************************************************** * map_fileW @@ -462,7 +807,7 @@ ICONCACHE *freePtr = *ptr; *ptr = freePtr->next; - GlobalFree16(HICON_16(freePtr->hIcon)); + destroy_cursor( freePtr->hIcon ); HeapFree( GetProcessHeap(), 0, freePtr ); continue; } @@ -660,47 +1005,27 @@ return &dir->idEntries[n]; } -/********************************************************************** - * CreateIconFromResourceEx (USER32.@) - * - * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something - * with cbSize parameter as well. - */ -HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize, - BOOL bIcon, DWORD dwVersion, - INT width, INT height, - UINT cFlag ) +static BOOL load_cursor_frame( LPBYTE bits, UINT cbSize, POINT16 hotspot, DWORD dwVersion, + INT width, INT height, UINT cFlag, cursor_frame_t *frame ) { - HGLOBAL16 hObj; static HDC hdcMem; int sizeAnd, sizeXor; HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */ BITMAP bmpXor, bmpAnd; - POINT16 hotspot; BITMAPINFO *bmi; BOOL DoStretch; INT size; - hotspot.x = ICON_HOTSPOT; - hotspot.y = ICON_HOTSPOT; - - TRACE_(cursor)("%p (%u bytes), ver %08x, %ix%i %s %s\n", - bits, cbSize, dwVersion, width, height, - bIcon ? "icon" : "cursor", (cFlag & LR_MONOCHROME) ? "mono" : "" ); + TRACE_(cursor)("%p (%u bytes), ver %08x, %ix%i %s\n", + bits, cbSize, dwVersion, width, height, + (cFlag & LR_MONOCHROME) ? "mono" : "" ); if (dwVersion == 0x00020000) { FIXME_(cursor)("\t2.xx resources are not supported\n"); - return 0; + return FALSE; } - if (bIcon) - bmi = (BITMAPINFO *)bits; - else /* get the hotspot */ - { - POINT16 *pt = (POINT16 *)bits; - hotspot = *pt; - bmi = (BITMAPINFO *)(pt + 1); - } + bmi = (BITMAPINFO *)bits; /* Check bitmap header */ @@ -709,7 +1034,7 @@ bmi->bmiHeader.biCompression != BI_RGB) ) { WARN_(cursor)("\tinvalid resource bitmap header.\n"); - return 0; + return FALSE; } size = bitmap_info_size( bmi, DIB_RGB_COLORS ); @@ -719,6 +1044,13 @@ DoStretch = (bmi->bmiHeader.biHeight/2 != height) || (bmi->bmiHeader.biWidth != width); + /* Scale the hotspot */ + if (DoStretch && hotspot.x != ICON_HOTSPOT && hotspot.y != ICON_HOTSPOT) + { + hotspot.x = (hotspot.x * width) / bmi->bmiHeader.biWidth; + hotspot.y = (hotspot.y * height) / (bmi->bmiHeader.biWidth / 2); + } + if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL ); if (screen_dc) { @@ -744,14 +1076,7 @@ /* Create the XOR bitmap */ if (DoStretch) { - if(bIcon) - { - hXorBits = CreateCompatibleBitmap(screen_dc, width, height); - } - else - { - hXorBits = CreateBitmap(width, height, 1, 1, NULL); - } + hXorBits = CreateCompatibleBitmap(screen_dc, width, height); if(hXorBits) { HBITMAP hOld; @@ -772,6 +1097,10 @@ hXorBits = CreateBitmap(width, height, 1, 1, NULL); SetDIBits(screen_dc, hXorBits, 0, height, (char*)bmi + size, pInfo, DIB_RGB_COLORS); + } else if (bmi->bmiHeader.biBitCount == 32) { + hXorBits = CreateDIBSection(screen_dc, pInfo, DIB_RGB_COLORS, NULL, NULL, 0); + SetDIBits(screen_dc, hXorBits, 0, height, + (char*)bmi + size, pInfo, DIB_RGB_COLORS); } else hXorBits = CreateDIBitmap(screen_dc, &pInfo->bmiHeader, @@ -835,40 +1164,313 @@ if( !hXorBits || !hAndBits ) { WARN_(cursor)("\tunable to create an icon bitmap.\n"); - return 0; + return FALSE; } - /* Now create the CURSORICONINFO structure */ + /* Setup a cursor frame, send it to the server */ GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor ); GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd ); sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes; sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes; - hObj = GlobalAlloc16( GMEM_MOVEABLE, - sizeof(CURSORICONINFO) + sizeXor + sizeAnd ); - if (hObj) - { - CURSORICONINFO *info; - - info = (CURSORICONINFO *)GlobalLock16( hObj ); - info->ptHotSpot.x = hotspot.x; - info->ptHotSpot.y = hotspot.y; - info->nWidth = bmpXor.bmWidth; - info->nHeight = bmpXor.bmHeight; - info->nWidthBytes = bmpXor.bmWidthBytes; - info->bPlanes = bmpXor.bmPlanes; - 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 ); - GlobalUnlock16( hObj ); - } + frame->xhot = hotspot.x; + frame->yhot = hotspot.y; + frame->width = bmpXor.bmWidth; + frame->height = bmpXor.bmHeight; + frame->and_width_bytes = bmpAnd.bmWidthBytes; + frame->xor_width_bytes = bmpXor.bmWidthBytes; + frame->planes = bmpXor.bmPlanes; + frame->bpp = bmpXor.bmBitsPixel; + frame->bits = HeapAlloc( GetProcessHeap(), 0, sizeAnd + sizeXor ); + GetBitmapBits( hAndBits, sizeAnd, frame->bits ); + GetBitmapBits( hXorBits, sizeXor, frame->bits + sizeAnd ); DeleteObject( hAndBits ); DeleteObject( hXorBits ); - return HICON_32(hObj); + + return TRUE; +} + +/********************************************************************** + * .ANI cursor support + */ +#define RIFF_FOURCC( c0, c1, c2, c3 ) \ + ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \ + ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) ) + +#define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F') +#define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T') +#define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N') +#define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h') +#define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ') +#define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm') + +#define ANI_FLAG_ICON 0x1 +#define ANI_FLAG_SEQUENCE 0x2 + +typedef struct { + DWORD header_size; + DWORD num_frames; + DWORD num_steps; + DWORD width; + DWORD height; + DWORD bpp; + DWORD num_planes; + DWORD display_rate; + DWORD flags; +} ani_header; + +typedef struct { + DWORD data_size; + const unsigned char *data; +} riff_chunk_t; + +static void dump_ani_header( const ani_header *header ) +{ + TRACE(" header size: %d\n", header->header_size); + TRACE(" frames: %d\n", header->num_frames); + TRACE(" steps: %d\n", header->num_steps); + TRACE(" width: %d\n", header->width); + TRACE(" height: %d\n", header->height); + TRACE(" bpp: %d\n", header->bpp); + TRACE(" planes: %d\n", header->num_planes); + TRACE(" display rate: %d\n", header->display_rate); + TRACE(" flags: 0x%08x\n", header->flags); +} + + +/* + * RIFF: + * DWORD "RIFF" + * DWORD size + * DWORD riff_id + * BYTE[] data + * + * LIST: + * DWORD "LIST" + * DWORD size + * DWORD list_id + * BYTE[] data + * + * CHUNK: + * DWORD chunk_id + * DWORD size + * BYTE[] data + */ +static void riff_find_chunk( DWORD chunk_id, DWORD chunk_type, const riff_chunk_t *parent_chunk, riff_chunk_t *chunk ) +{ + const unsigned char *ptr = parent_chunk->data; + const unsigned char *end = parent_chunk->data + (parent_chunk->data_size - (2 * sizeof(DWORD))); + + if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) end -= sizeof(DWORD); + + while (ptr < end) + { + if ((!chunk_type && *(DWORD *)ptr == chunk_id ) + || (chunk_type && *(DWORD *)ptr == chunk_type && *((DWORD *)ptr + 2) == chunk_id )) + { + ptr += sizeof(DWORD); + chunk->data_size = *(DWORD *)ptr; + ptr += sizeof(DWORD); + if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) ptr += sizeof(DWORD); + chunk->data = ptr; + + return; + } + + ptr += sizeof(DWORD); + ptr += *(DWORD *)ptr; + ptr += sizeof(DWORD); + } +} + + +/* + * .ANI layout: + * + * RIFF:'ACON' RIFF chunk + * |- CHUNK:'anih' Header + * |- CHUNK:'seq ' Sequence information (optional) + * \- LIST:'fram' Frame list + * |- CHUNK:icon Cursor frames + * |- CHUNK:icon + * |- ... + * \- CHUNK:icon + */ +static HCURSOR load_ani( const LPBYTE bits, DWORD bits_size, INT width, INT height ) +{ + int i; + WORD max_count = 0; + HCURSOR cursor; + CURSORICONFILEDIR *dir = 0; + ani_header header = {0}; + DWORD *frame_seq = 0; + cursor_frame_t *frames; + unsigned int frame_bits_size = 0; + LPBYTE frame_bits = 0; + POINT16 hotspot; + + riff_chunk_t root_chunk = { bits_size, bits }; + riff_chunk_t ACON_chunk = {0}; + riff_chunk_t anih_chunk = {0}; + riff_chunk_t fram_chunk = {0}; + const unsigned char *icon_chunk; + const unsigned char *icon_data; + + TRACE("bits %p, bits_size %d\n", bits, bits_size); + + if (!bits) return 0; + + riff_find_chunk( ANI_ACON_ID, ANI_RIFF_ID, &root_chunk, &ACON_chunk ); + if (!ACON_chunk.data) + { + ERR("Failed to get root chunk.\n"); + return 0; + } + + riff_find_chunk( ANI_anih_ID, 0, &ACON_chunk, &anih_chunk ); + if (!anih_chunk.data) + { + ERR("Failed to get 'anih' chunk.\n"); + return 0; + } + memcpy( &header, anih_chunk.data, sizeof(header) ); + dump_ani_header( &header ); + + if (header.flags & ANI_FLAG_SEQUENCE) + { + riff_chunk_t seq_chunk = {0}; + + TRACE("Loading sequence data.\n"); + riff_find_chunk( ANI_seq__ID, 0, &ACON_chunk, &seq_chunk ); + if (!seq_chunk.data) + { + ERR("Failed to get 'seq ' chunk\n"); + return 0; + } + frame_seq = HeapAlloc( GetProcessHeap(), 0, sizeof(DWORD) * header.num_steps ); + memcpy( frame_seq, seq_chunk.data, sizeof(DWORD) * header.num_steps ); + } + + riff_find_chunk( ANI_fram_ID, ANI_LIST_ID, &ACON_chunk, &fram_chunk ); + if (!fram_chunk.data) + { + ERR("Failed to get icon list\n"); + return 0; + } + + icon_chunk = fram_chunk.data; + icon_data = icon_chunk + (2 * sizeof(DWORD)); + /* The .ANI stores the display rate in 1/60s, we store the delay between frames in ms */ + cursor = create_cursor( header.num_steps, (100 * header.display_rate) / 6 ); + frames = HeapAlloc( GetProcessHeap(), 0, header.num_frames * sizeof(cursor_frame_t) ); + + for (i = 0; i < header.num_frames; ++i) + { + WORD count; + CURSORICONFILEDIRENTRY *entry; + DWORD chunk_size = *(DWORD *)(icon_chunk + sizeof(DWORD)); + + /* Read icon count, skip magic */ + memcpy( &count, icon_data + sizeof(DWORD), sizeof(WORD) ); + + /* There's a decent chance the amount of entries will be the same for each icon */ + if (count > max_count) + { + HeapFree( GetProcessHeap(), 0, dir ); + /* sizeof(CURSORICONFILEDIRENTRY) for each entry, +6 for magic & count */ + dir = HeapAlloc( GetProcessHeap(), 0, (count * sizeof(CURSORICONFILEDIRENTRY)) + 6 ); + max_count = count; + } + + /* sizeof(CURSORICONFILEDIRENTRY) for each entry, +6 for magic & count */ + memcpy( dir, icon_data, (count * sizeof(CURSORICONFILEDIRENTRY)) + 6 ); + entry = CURSORICON_FindBestCursorFile( dir, width, height, 1 ); + + if (frame_bits_size < entry->dwDIBSize) + { + frame_bits_size = entry->dwDIBSize; + HeapFree( GetProcessHeap(), 0, frame_bits ); + frame_bits = HeapAlloc( GetProcessHeap(), 0, frame_bits_size ); + } + + if (!header.width || !header.height) + { + header.width = entry->bWidth; + header.height = entry->bHeight; + } + + hotspot.x = entry->xHotspot; + hotspot.y = entry->yHotspot; + + memcpy( frame_bits, icon_data + entry->dwDIBOffset, entry->dwDIBSize ); + + load_cursor_frame( frame_bits, entry->dwDIBSize, hotspot, 0x00030000, header.width, header.height, 0, &frames[i] ); + + /* Advance to the next chunk */ + icon_chunk += chunk_size + (2 * sizeof(DWORD)); + icon_data = icon_chunk + (2 * sizeof(DWORD)); + } + HeapFree( GetProcessHeap(), 0, dir ); + + /* Set the frames in the correct sequence */ + for (i = 0; i < header.num_steps; ++i) + { + int frame_idx = (frame_seq ? frame_seq[i] : i); + set_cursor_frame( cursor, i, &frames[frame_idx] ); + } + + /* Cleanup */ + for (i = 0; i < header.num_frames; ++i) + { + HeapFree( GetProcessHeap(), 0, frames[i].bits ); + } + HeapFree( GetProcessHeap(), 0, frame_seq ); + HeapFree( GetProcessHeap(), 0, frames ); + + return cursor; +} + + +/********************************************************************** + * CreateIconFromResourceEx (USER32.@) + * + * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something + * with cbSize parameter as well. + */ +HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize, + BOOL bIcon, DWORD dwVersion, + INT width, INT height, + UINT cFlag ) +{ + POINT16 hotspot; + HCURSOR cursor = create_cursor( 1, 0 ); + cursor_frame_t frame = {0}; + + if (bIcon) + { + hotspot.x = ICON_HOTSPOT; + hotspot.y = ICON_HOTSPOT; + } + else + { + hotspot = *(POINT16 *)bits; + bits = (LPBYTE)(((POINT16 *)bits) + 1); + } + + if (load_cursor_frame( bits, cbSize, hotspot, dwVersion, width, height, cFlag, &frame )) + { + set_cursor_frame( cursor, 0, &frame ); + } + else + { + destroy_cursor( cursor ); + cursor = 0; + } + + HeapFree( GetProcessHeap(), 0, frame.bits ); + + return cursor; } @@ -887,9 +1489,11 @@ BOOL fCursor, UINT loadflags) { CURSORICONFILEDIRENTRY *entry; + cursor_frame_t frame = {0}; CURSORICONFILEDIR *dir; DWORD filesize = 0; HICON hIcon = 0; + POINT16 hotspot; LPBYTE bits; TRACE("loading %s\n", debugstr_w( filename )); @@ -898,10 +1502,15 @@ if (!bits) return hIcon; + /* If the data contains the magic for an .ICO it's an .ICO, + * regardless of what fCursor says. */ + if (!memcmp( bits, "\x00\x00\x01\x00", 4 )) fCursor = FALSE; + /* Same thing for .CUR */ + else if (!memcmp( bits, "\x00\x00\x02\x00", 4 )) fCursor = TRUE; /* Check for .ani. */ - if (memcmp( bits, "RIFF", 4 ) == 0) + else if (!memcmp( bits, "RIFF", 4 )) { - FIXME("No support for .ani cursors.\n"); + hIcon = load_ani( bits, filesize, width, height ); goto end; } @@ -926,8 +1535,23 @@ if ( entry->dwDIBOffset + entry->dwDIBSize > filesize ) goto end; - hIcon = CreateIconFromResourceEx( &bits[entry->dwDIBOffset], entry->dwDIBSize, - !fCursor, 0x00030000, width, height, loadflags ); + if ( fCursor ) + { + hotspot.x = entry->xHotspot; + hotspot.y = entry->yHotspot; + } + else + { + hotspot.x = ICON_HOTSPOT; + hotspot.y = ICON_HOTSPOT; + } + + hIcon = create_cursor( 1, 0 ); + load_cursor_frame( &bits[entry->dwDIBOffset], entry->dwDIBSize, hotspot, + 0x00030000, width, height, loadflags, &frame ); + set_cursor_frame( hIcon, 0, &frame ); + HeapFree( GetProcessHeap(), 0, frame.bits ); + end: TRACE("loaded %s -> %p\n", debugstr_w( filename ), hIcon ); UnmapViewOfFile( bits ); @@ -1016,21 +1640,20 @@ */ static HICON CURSORICON_Copy( HINSTANCE16 hInst16, HICON hIcon ) { - char *ptrOld, *ptrNew; - int size; - HICON16 hOld = HICON_16(hIcon); - HICON16 hNew; + /* Should animated cursors be copyable like this as well? */ + HCURSOR new_cursor; + cursor_frame_t frame; + + if (!hIcon || !get_cursor_frame( hIcon, 0, &frame )) + { + return 0; + } + + new_cursor = create_cursor( 1, 0 ); + set_cursor_frame( new_cursor, 0, &frame ); + HeapFree( GetProcessHeap(), 0, frame.bits ); - if (!(ptrOld = (char *)GlobalLock16( hOld ))) return 0; - if (hInst16 && !(hInst16 = GetExePtr( hInst16 ))) return 0; - size = GlobalSize16( hOld ); - hNew = GlobalAlloc16( GMEM_MOVEABLE, size ); - FarSetOwner16( hNew, hInst16 ); - ptrNew = (char *)GlobalLock16( hNew ); - memcpy( ptrNew, ptrOld, size ); - GlobalUnlock16( hOld ); - GlobalUnlock16( hNew ); - return HICON_32(hNew); + return new_cursor; } /************************************************************************* @@ -1281,25 +1904,31 @@ LPCVOID lpANDbits, LPCVOID lpXORbits ) { - HGLOBAL16 handle; - char *ptr; + HCURSOR cursor; + cursor_frame_t frame; int sizeAnd, sizeXor; - hInstance = GetExePtr( hInstance ); /* Make it a module handle */ if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0; info->nWidthBytes = get_bitmap_width_bytes(info->nWidth,info->bBitsPerPixel); sizeXor = info->nHeight * info->nWidthBytes; sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 ); - if (!(handle = GlobalAlloc16( GMEM_MOVEABLE, - sizeof(CURSORICONINFO) + sizeXor + sizeAnd))) - return 0; - FarSetOwner16( handle, hInstance ); - ptr = (char *)GlobalLock16( handle ); - memcpy( ptr, info, sizeof(*info) ); - memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd ); - memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor ); - GlobalUnlock16( handle ); - return handle; + + cursor = create_cursor( 1, 0 ); + frame.xhot = info->ptHotSpot.x; + frame.yhot = info->ptHotSpot.y; + frame.width = info->nWidth; + frame.height = info->nHeight; + frame.and_width_bytes = get_bitmap_width_bytes( info->nWidth, 1 ); + frame.xor_width_bytes = info->nWidthBytes; + frame.planes = info->bPlanes; + frame.bpp = info->bBitsPerPixel; + frame.bits = HeapAlloc( GetProcessHeap(), 0, sizeAnd + sizeXor ); + CopyMemory( frame.bits, lpANDbits, sizeAnd ); + CopyMemory( frame.bits + sizeAnd, lpXORbits, sizeXor ); + set_cursor_frame( cursor, 0, &frame ); + HeapFree( GetProcessHeap(), 0, frame.bits ); + + return HICON_16(cursor); } @@ -1368,7 +1997,7 @@ /* Now assume non-shared cursor/icon */ - retv = GlobalFree16( handle ); + retv = destroy_cursor( HCURSOR_32(handle) ); return (flags & CID_RESOURCE)? retv : TRUE; } @@ -1468,8 +2097,12 @@ /* Change the cursor shape only if it is visible */ if (thread_info->cursor_count >= 0) { - USER_Driver->pSetCursor( (CURSORICONINFO*)GlobalLock16(HCURSOR_16(hCursor)) ); - GlobalUnlock16(HCURSOR_16(hCursor)); + cursor_t *cursor; + + update_cursor_32from16( hCursor ); + cursor = get_cursor_object( hCursor ); + USER_Driver->pSetCursor( cursor ); + destroy_cursor_object( cursor ); } return hOldCursor; } @@ -1487,8 +2120,12 @@ { if (++thread_info->cursor_count == 0) /* Show it */ { - USER_Driver->pSetCursor((CURSORICONINFO*)GlobalLock16(HCURSOR_16(thread_info->cursor))); - GlobalUnlock16(HCURSOR_16(thread_info->cursor)); + cursor_t *cursor; + + update_cursor_32from16( thread_info->cursor ); + cursor = get_cursor_object( thread_info->cursor ); + USER_Driver->pSetCursor( cursor ); + destroy_cursor_object( cursor ); } } else @@ -1790,9 +2427,10 @@ */ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo) { + HCURSOR cursor; + cursor_frame_t frame; DIBSECTION bmpXor; BITMAP bmpAnd; - HICON16 hObj; int xor_objsize = 0, sizeXor = 0, sizeAnd, planes, bpp; TRACE("color %p, mask %p, hotspot %ux%u, fIcon %d\n", @@ -1821,94 +2459,90 @@ sizeAnd = bmpAnd.bmHeight * get_bitmap_width_bytes(bmpAnd.bmWidth, 1); - hObj = GlobalAlloc16( GMEM_MOVEABLE, - sizeof(CURSORICONINFO) + sizeXor + sizeAnd ); - if (hObj) - { - CURSORICONINFO *info; - - info = (CURSORICONINFO *)GlobalLock16( hObj ); + cursor = create_cursor( 1, 0 ); - /* If we are creating an icon, the hotspot is unused */ - if (iconinfo->fIcon) - { - info->ptHotSpot.x = ICON_HOTSPOT; - info->ptHotSpot.y = ICON_HOTSPOT; - } - else - { - info->ptHotSpot.x = iconinfo->xHotspot; - info->ptHotSpot.y = iconinfo->yHotspot; - } + /* If we are creating an icon, the hotspot is unused */ + if (iconinfo->fIcon) + { + frame.xhot = ICON_HOTSPOT; + frame.yhot = ICON_HOTSPOT; + } + else + { + frame.xhot = iconinfo->xHotspot; + frame.yhot = iconinfo->yHotspot; + } - if (iconinfo->hbmColor) - { - info->nWidth = bmpXor.dsBm.bmWidth; - info->nHeight = bmpXor.dsBm.bmHeight; - info->nWidthBytes = bmpXor.dsBm.bmWidthBytes; - info->bPlanes = planes; - info->bBitsPerPixel = bpp; - } - else - { - info->nWidth = bmpAnd.bmWidth; - info->nHeight = bmpAnd.bmHeight / 2; - info->nWidthBytes = get_bitmap_width_bytes(bmpAnd.bmWidth, 1); - info->bPlanes = 1; - info->bBitsPerPixel = 1; - } + if (iconinfo->hbmColor) + { + frame.width = bmpXor.dsBm.bmWidth; + frame.height = bmpXor.dsBm.bmHeight; + frame.and_width_bytes = bmpAnd.bmWidthBytes; + frame.xor_width_bytes = bmpXor.dsBm.bmWidthBytes; + frame.planes = planes; + frame.bpp = bpp; + } + else + { + frame.width = bmpAnd.bmWidth; + frame.height = bmpAnd.bmHeight / 2; + frame.and_width_bytes = get_bitmap_width_bytes(bmpAnd.bmWidth, 1); + frame.xor_width_bytes = 0; + frame.planes = 1; + frame.bpp = 1; + } - /* Transfer the bitmap bits to the CURSORICONINFO structure */ + frame.bits = HeapAlloc( GetProcessHeap(), 0, sizeAnd + sizeXor ); - /* Some apps pass a color bitmap as a mask, convert it to b/w */ - if (bmpAnd.bmBitsPixel == 1) - { - GetBitmapBits( iconinfo->hbmMask, sizeAnd, (char*)(info + 1) ); - } - else - { - HDC hdc, hdc_mem; - HBITMAP hbmp_old, hbmp_mem_old, hbmp_mono; + /* Some apps pass a color bitmap as a mask, convert it to b/w */ + if (bmpAnd.bmBitsPixel == 1) + { + GetBitmapBits( iconinfo->hbmMask, sizeAnd, frame.bits ); + } + else + { + HDC hdc, hdc_mem; + HBITMAP hbmp_old, hbmp_mem_old, hbmp_mono; - hdc = GetDC( 0 ); - hdc_mem = CreateCompatibleDC( hdc ); + hdc = GetDC( 0 ); + hdc_mem = CreateCompatibleDC( hdc ); - hbmp_mono = CreateBitmap( bmpAnd.bmWidth, bmpAnd.bmHeight, 1, 1, NULL ); + hbmp_mono = CreateBitmap( bmpAnd.bmWidth, bmpAnd.bmHeight, 1, 1, NULL ); - hbmp_old = SelectObject( hdc, iconinfo->hbmMask ); - hbmp_mem_old = SelectObject( hdc_mem, hbmp_mono ); + hbmp_old = SelectObject( hdc, iconinfo->hbmMask ); + hbmp_mem_old = SelectObject( hdc_mem, hbmp_mono ); - BitBlt( hdc_mem, 0, 0, bmpAnd.bmWidth, bmpAnd.bmHeight, hdc, 0, 0, SRCCOPY ); + BitBlt( hdc_mem, 0, 0, bmpAnd.bmWidth, bmpAnd.bmHeight, hdc, 0, 0, SRCCOPY ); - SelectObject( hdc, hbmp_old ); - SelectObject( hdc_mem, hbmp_mem_old ); + SelectObject( hdc, hbmp_old ); + SelectObject( hdc_mem, hbmp_mem_old ); - DeleteDC( hdc_mem ); - ReleaseDC( 0, hdc ); + DeleteDC( hdc_mem ); + ReleaseDC( 0, hdc ); - GetBitmapBits( hbmp_mono, sizeAnd, (char*)(info + 1) ); - DeleteObject( hbmp_mono ); - } + GetBitmapBits( hbmp_mono, sizeAnd, frame.bits ); + DeleteObject( hbmp_mono ); + } if (iconinfo->hbmColor) { - char *dst_bits = (char*)(info + 1) + sizeAnd; + char *dst_bits = frame.bits + sizeAnd; if (bmpXor.dsBm.bmPlanes == planes && bmpXor.dsBm.bmBitsPixel == bpp) GetBitmapBits( iconinfo->hbmColor, sizeXor, dst_bits ); else { BITMAPINFO bminfo; - int dib_width = get_dib_width_bytes( info->nWidth, info->bBitsPerPixel ); - int bitmap_width = get_bitmap_width_bytes( info->nWidth, info->bBitsPerPixel ); + int dib_width = get_dib_width_bytes( frame.width, frame.bpp ); + int bitmap_width = get_bitmap_width_bytes( frame.width, frame.bpp ); bminfo.bmiHeader.biSize = sizeof(bminfo); - bminfo.bmiHeader.biWidth = info->nWidth; - bminfo.bmiHeader.biHeight = info->nHeight; - bminfo.bmiHeader.biPlanes = info->bPlanes; - bminfo.bmiHeader.biBitCount = info->bBitsPerPixel; + bminfo.bmiHeader.biWidth = frame.width; + bminfo.bmiHeader.biHeight = frame.height; + bminfo.bmiHeader.biPlanes = frame.planes; + bminfo.bmiHeader.biBitCount = frame.bpp; bminfo.bmiHeader.biCompression = BI_RGB; - bminfo.bmiHeader.biSizeImage = info->nHeight * dib_width; + bminfo.bmiHeader.biSizeImage = frame.height * dib_width; bminfo.bmiHeader.biXPelsPerMeter = 0; bminfo.bmiHeader.biYPelsPerMeter = 0; bminfo.bmiHeader.biClrUsed = 0; @@ -1922,23 +2556,24 @@ { char *src_bits = HeapAlloc( GetProcessHeap(), 0, bminfo.bmiHeader.biSizeImage ); - if (src_bits && GetDIBits( screen_dc, iconinfo->hbmColor, 0, info->nHeight, + if (src_bits && GetDIBits( screen_dc, iconinfo->hbmColor, 0, frame.height, src_bits, &bminfo, DIB_RGB_COLORS )) { int y; - for (y = 0; y < info->nHeight; y++) + for (y = 0; y < frame.height; y++) memcpy( dst_bits + y * bitmap_width, src_bits + y * dib_width, bitmap_width ); } HeapFree( GetProcessHeap(), 0, src_bits ); } else - GetDIBits( screen_dc, iconinfo->hbmColor, 0, info->nHeight, + GetDIBits( screen_dc, iconinfo->hbmColor, 0, frame.height, dst_bits, &bminfo, DIB_RGB_COLORS ); } } - GlobalUnlock16( hObj ); - } - return HICON_32(hObj); + set_cursor_frame( cursor, 0, &frame ); + HeapFree( GetProcessHeap(), 0, frame.bits ); + + return cursor; } /****************************************************************************** diff -urN wine-1.0.orig/dlls/user32/display.c wine-1.0/dlls/user32/display.c --- wine-1.0.orig/dlls/user32/display.c 2008-06-17 16:07:31.000000000 +0200 +++ wine-1.0/dlls/user32/display.c 2008-06-27 15:53:24.000000000 +0200 @@ -50,7 +50,7 @@ /*********************************************************************** * SetCursor (DISPLAY.102) */ -VOID WINAPI DISPLAY_SetCursor( struct tagCURSORICONINFO *lpCursor ) +VOID WINAPI DISPLAY_SetCursor( const struct cursor_t *lpCursor ) { USER_Driver->pSetCursor(lpCursor); } diff -urN wine-1.0.orig/dlls/user32/driver.c wine-1.0/dlls/user32/driver.c --- wine-1.0.orig/dlls/user32/driver.c 2008-06-17 16:07:31.000000000 +0200 +++ wine-1.0/dlls/user32/driver.c 2008-06-27 15:53:24.000000000 +0200 @@ -215,7 +215,7 @@ return -1; } -static void nulldrv_SetCursor( struct tagCURSORICONINFO *info ) +static void nulldrv_SetCursor( const struct cursor_t *cursor ) { } @@ -544,9 +544,9 @@ return load_driver()->pVkKeyScanEx( ch, layout ); } -static void loaderdrv_SetCursor( struct tagCURSORICONINFO *info ) +static void loaderdrv_SetCursor( const struct cursor_t *cursor ) { - load_driver()->pSetCursor( info ); + load_driver()->pSetCursor( cursor ); } static BOOL loaderdrv_GetCursorPos( LPPOINT pt ) diff -urN wine-1.0.orig/dlls/user32/user_private.h wine-1.0/dlls/user32/user_private.h --- wine-1.0.orig/dlls/user32/user_private.h 2008-06-17 16:07:31.000000000 +0200 +++ wine-1.0/dlls/user32/user_private.h 2008-06-27 15:53:24.000000000 +0200 @@ -99,7 +99,7 @@ WM_WINE_LAST_DRIVER_MSG = 0x80001fff }; -struct tagCURSORICONINFO; +struct cursor_t; typedef struct tagUSER_DRIVER { /* keyboard functions */ @@ -117,7 +117,7 @@ BOOL (*pUnloadKeyboardLayout)(HKL); SHORT (*pVkKeyScanEx)(WCHAR, HKL); /* mouse functions */ - void (*pSetCursor)(struct tagCURSORICONINFO *); + void (*pSetCursor)(const struct cursor_t *); BOOL (*pGetCursorPos)(LPPOINT); BOOL (*pSetCursorPos)(INT,INT); BOOL (*pClipCursor)(LPCRECT); @@ -302,12 +302,15 @@ extern int SPY_Init(void) DECLSPEC_HIDDEN; /* HANDLE16 <-> HANDLE conversions */ -#define HCURSOR_16(h32) (LOWORD(h32)) -#define HICON_16(h32) (LOWORD(h32)) +HCURSOR16 get_cursor_handle16( HCURSOR cursor32, BOOL create ); +HCURSOR get_cursor_handle32( HCURSOR16 cursor16 ); + +#define HCURSOR_16(h32) get_cursor_handle16(h32, TRUE) +#define HICON_16(h32) get_cursor_handle16(h32, TRUE) #define HINSTANCE_16(h32) (LOWORD(h32)) -#define HCURSOR_32(h16) ((HCURSOR)(ULONG_PTR)(h16)) -#define HICON_32(h16) ((HICON)(ULONG_PTR)(h16)) +#define HCURSOR_32(h16) get_cursor_handle32(h16) +#define HICON_32(h16) get_cursor_handle32(h16) #define HINSTANCE_32(h16) ((HINSTANCE)(ULONG_PTR)(h16)) #define HMODULE_32(h16) ((HMODULE)(ULONG_PTR)(h16)) diff -urN wine-1.0.orig/dlls/user32/wnd16.c wine-1.0/dlls/user32/wnd16.c --- wine-1.0.orig/dlls/user32/wnd16.c 2008-06-17 16:07:31.000000000 +0200 +++ wine-1.0/dlls/user32/wnd16.c 2008-06-27 15:53:22.000000000 +0200 @@ -647,7 +647,17 @@ */ WORD WINAPI GetClassWord16( HWND16 hwnd, INT16 offset ) { - return GetClassWord( WIN_Handle32(hwnd), offset ); + WORD ret = GetClassWord( WIN_Handle32(hwnd), offset ); + + switch (offset) + { + case GCLP_HCURSOR: + case GCLP_HICON: + case GCLP_HICONSM: + return HCURSOR_16((HCURSOR)(LONG_PTR)ret); + default: + return ret; + } } @@ -656,7 +666,15 @@ */ WORD WINAPI SetClassWord16( HWND16 hwnd, INT16 offset, WORD newval ) { - return SetClassWord( WIN_Handle32(hwnd), offset, newval ); + switch (offset) + { + case GCLP_HCURSOR: + case GCLP_HICON: + case GCLP_HICONSM: + return HCURSOR_16((HCURSOR)SetClassLongW( WIN_Handle32(hwnd), offset, (LONG_PTR)HCURSOR_32(newval) )); + default: + return SetClassWord( WIN_Handle32(hwnd), offset, newval ); + } } @@ -669,6 +687,10 @@ switch( offset ) { + case GCLP_HCURSOR: + case GCLP_HICON: + case GCLP_HICONSM: + return HCURSOR_16((HCURSOR)ret); case GCLP_WNDPROC: return (LONG_PTR)WINPROC_GetProc16( (WNDPROC)ret, FALSE ); case GCLP_MENUNAME: @@ -686,6 +708,10 @@ { switch( offset ) { + case GCLP_HCURSOR: + case GCLP_HICON: + case GCLP_HICONSM: + return HCURSOR_16((HCURSOR)SetClassLongW( WIN_Handle32(hwnd16), offset, (LONG_PTR)HCURSOR_32( newval ) )); case GCLP_WNDPROC: { WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval ); diff -urN wine-1.0.orig/dlls/winex11.drv/mouse.c wine-1.0/dlls/winex11.drv/mouse.c --- wine-1.0.orig/dlls/winex11.drv/mouse.c 2008-06-17 16:07:31.000000000 +0200 +++ wine-1.0/dlls/winex11.drv/mouse.c 2008-06-27 15:53:25.000000000 +0200 @@ -32,6 +32,9 @@ MAKE_FUNCPTR(XcursorImageCreate); MAKE_FUNCPTR(XcursorImageDestroy); MAKE_FUNCPTR(XcursorImageLoadCursor); +MAKE_FUNCPTR(XcursorImagesCreate); +MAKE_FUNCPTR(XcursorImagesDestroy); +MAKE_FUNCPTR(XcursorImagesLoadCursor); # undef MAKE_FUNCPTR #endif /* SONAME_LIBXCURSOR */ @@ -112,6 +115,9 @@ LOAD_FUNCPTR(XcursorImageCreate); LOAD_FUNCPTR(XcursorImageDestroy); LOAD_FUNCPTR(XcursorImageLoadCursor); + LOAD_FUNCPTR(XcursorImagesCreate); + LOAD_FUNCPTR(XcursorImagesDestroy); + LOAD_FUNCPTR(XcursorImagesLoadCursor); #undef LOAD_FUNCPTR #endif /* SONAME_LIBXCURSOR */ } @@ -404,29 +410,25 @@ /*********************************************************************** * create_cursor_image * - * Create an XcursorImage from a CURSORICONINFO + * Create an XcursorImage from a cursor_frame_t */ -static XcursorImage *create_cursor_image( CURSORICONINFO *ptr ) +static XcursorImage *create_cursor_image( cursor_frame_t *frame ) { int x, xmax; int y, ymax; int and_size; unsigned char *and_bits, *and_ptr, *xor_bits, *xor_ptr; - int and_width_bytes, xor_width_bytes; XcursorPixel *pixel_ptr; XcursorImage *image; BOOL alpha_zero = TRUE; - ymax = (ptr->nHeight > 32) ? 32 : ptr->nHeight; - xmax = (ptr->nWidth > 32) ? 32 : ptr->nWidth; + ymax = (frame->height > 32) ? 32 : frame->height; + xmax = (frame->width > 32) ? 32 : frame->width; - and_width_bytes = xmax / 8; - xor_width_bytes = and_width_bytes * ptr->bBitsPerPixel; + and_size = frame->and_width_bytes * frame->height; + and_ptr = and_bits = frame->bits; - and_size = ptr->nWidth * ptr->nHeight / 8; - and_ptr = and_bits = (unsigned char *)(ptr + 1); - - xor_ptr = xor_bits = and_ptr + and_size; + xor_ptr = xor_bits = frame->bits + and_size; image = pXcursorImageCreate( xmax, ymax ); pixel_ptr = image->pixels; @@ -445,11 +447,11 @@ * * Non-32 bit bitmaps always use the AND mask */ - if(ptr->bBitsPerPixel == 32) + if(frame->bpp == 32) { for (y = 0; alpha_zero && y < ymax; ++y) { - xor_ptr = xor_bits + (y * xor_width_bytes); + xor_ptr = xor_bits + (y * frame->xor_width_bytes); for (x = 0; x < xmax; ++x) { if (xor_ptr[3] != 0x00) @@ -478,13 +480,13 @@ */ for (y = 0; y < ymax; ++y) { - and_ptr = and_bits + (y * and_width_bytes); - xor_ptr = xor_bits + (y * xor_width_bytes); + and_ptr = and_bits + (y * frame->and_width_bytes); + xor_ptr = xor_bits + (y * frame->xor_width_bytes); for (x = 0; x < xmax; ++x) { /* Xcursor pixel data is in ARGB format, with A in the high byte */ - switch (ptr->bBitsPerPixel) + switch (frame->bpp) { case 32: /* BGRA, 8 bits each */ @@ -517,7 +519,7 @@ break; default: - FIXME("Currently no support for cursors with %d bits per pixel\n", ptr->bBitsPerPixel); + FIXME("Currently no support for cursors with %d bits per pixel\n", frame->bpp); return 0; } @@ -548,12 +550,14 @@ * * Use Xcursor to create an X cursor from a Windows one. */ -static Cursor create_xcursor_cursor( Display *display, CURSORICONINFO *ptr ) +static Cursor create_xcursor_cursor( Display *display, const cursor_t *cursor_object ) { + unsigned int i; Cursor cursor; XcursorImage *image; + XcursorImages *images; - if (!ptr) /* Create an empty cursor */ + if (!cursor_object) /* Create an empty cursor */ { image = pXcursorImageCreate( 1, 1 ); image->xhot = 0; @@ -565,23 +569,30 @@ return cursor; } - image = create_cursor_image( ptr ); - if (!image) return 0; - - /* Make sure hotspot is valid */ - image->xhot = ptr->ptHotSpot.x; - image->yhot = ptr->ptHotSpot.y; - if (image->xhot >= image->width || - image->yhot >= image->height) + images = pXcursorImagesCreate( cursor_object->num_frames ); + for (i = 0; i < cursor_object->num_frames; ++i) { - image->xhot = image->width / 2; - image->yhot = image->height / 2; - } + cursor_frame_t *frame = &cursor_object->frames[i]; + image = create_cursor_image( frame ); + if (!image) return 0; - image->delay = 0; + /* Make sure hotspot is valid */ + image->xhot = frame->xhot; + image->yhot = frame->yhot; + if (image->xhot >= image->width || + image->yhot >= image->height) + { + image->xhot = image->width / 2; + image->yhot = image->height / 2; + } - cursor = pXcursorImageLoadCursor( display, image ); - pXcursorImageDestroy( image ); + image->delay = cursor_object->delay; + + images->images[images->nimage++] = image; + } + + cursor = pXcursorImagesLoadCursor( display, images ); + pXcursorImagesDestroy( images ); return cursor; } @@ -594,7 +605,7 @@ * * Create an X cursor from a Windows one. */ -static Cursor create_cursor( Display *display, CURSORICONINFO *ptr ) +static Cursor create_cursor( Display *display, const cursor_t *ptr ) { Pixmap pixmapBits, pixmapMask, pixmapMaskInv = 0, pixmapAll; XColor fg, bg; @@ -621,12 +632,13 @@ } else /* Create the X cursor from the bits */ { + cursor_frame_t *frame = &ptr->frames[0]; XImage *image; GC gc; TRACE("Bitmap %dx%d planes=%d bpp=%d bytesperline=%d\n", - ptr->nWidth, ptr->nHeight, ptr->bPlanes, ptr->bBitsPerPixel, - ptr->nWidthBytes); + frame->width, frame->height, frame->planes, frame->bpp, + frame->xor_width_bytes); /* Create a pixmap and transfer all the bits to it */ @@ -639,11 +651,11 @@ * the mask and the second is the image. */ if (!(pixmapAll = XCreatePixmap( display, root_window, - ptr->nWidth, ptr->nHeight * 2, 1 ))) + frame->width, frame->height * 2, 1 ))) return 0; if (!(image = XCreateImage( display, visual, - 1, ZPixmap, 0, (char *)(ptr + 1), ptr->nWidth, - ptr->nHeight * 2, 16, ptr->nWidthBytes/ptr->bBitsPerPixel))) + 1, ZPixmap, 0, (char *)frame->bits, frame->width, + frame->height * 2, 16, frame->xor_width_bytes/frame->bpp))) { XFreePixmap( display, pixmapAll ); return 0; @@ -654,13 +666,13 @@ image->bitmap_bit_order = MSBFirst; image->bitmap_unit = 16; _XInitImageFuncPtrs(image); - if (ptr->bPlanes * ptr->bBitsPerPixel == 1) + if (frame->planes * frame->bpp == 1) { /* A plain old white on black cursor. */ fg.red = fg.green = fg.blue = 0xffff; bg.red = bg.green = bg.blue = 0x0000; XPutImage( display, pixmapAll, gc, image, - 0, 0, 0, 0, ptr->nWidth, ptr->nHeight * 2 ); + 0, 0, 0, 0, frame->width, frame->height * 2 ); } else { @@ -672,11 +684,11 @@ int threshold, fgBits, bgBits, bitShifted; BYTE pXorBits[128]; /* Up to 32x32 icons */ - switch (ptr->bBitsPerPixel) + switch (frame->bpp) { case 32: bitMask32 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - ptr->nWidth * ptr->nHeight / 8 ); + frame->width * frame->height / 8 ); /* Fallthrough */ case 24: rbits = 8; @@ -692,7 +704,7 @@ break; default: FIXME("Currently no support for cursors with %d bits per pixel\n", - ptr->bBitsPerPixel); + frame->bpp); XFreePixmap( display, pixmapAll ); XFreeGC( display, gc ); image->data = NULL; @@ -700,22 +712,22 @@ return 0; } /* The location of the mask. */ - theMask = (unsigned char *)(ptr + 1); + theMask = frame->bits; /* The mask should still be 1 bit per pixel. The color image * should immediately follow the mask. */ - theImage = &theMask[ptr->nWidth/8 * ptr->nHeight]; + theImage = &theMask[frame->width/8 * frame->height]; rfg = gfg = bfg = rbg = gbg = bbg = 0; byteIndex = 0; xorIndex = 0; fgBits = 0; bitShifted = 0x01; - xmax = (ptr->nWidth > 32) ? 32 : ptr->nWidth; - if (ptr->nWidth > 32) { + xmax = (frame->width > 32) ? 32 : frame->width; + if (frame->width > 32) { ERR("Got a %dx%d cursor. Cannot handle larger than 32x32.\n", - ptr->nWidth, ptr->nHeight); + frame->width, frame->height); } - ymax = (ptr->nHeight > 32) ? 32 : ptr->nHeight; + ymax = (frame->height > 32) ? 32 : frame->height; memset(pXorBits, 0, 128); for (y=0; ybBitsPerPixel) + switch (frame->bpp) { case 32: theChar = theImage[byteIndex++]; @@ -811,11 +823,11 @@ /* Put the mask. */ XPutImage( display, pixmapAll, gc, image, - 0, 0, 0, 0, ptr->nWidth, ptr->nHeight ); + 0, 0, 0, 0, frame->width, frame->height ); XSetFunction( display, gc, GXcopy ); /* Put the image */ XCopyArea( display, pixmapBits, pixmapAll, gc, - 0, 0, xmax, ymax, 0, ptr->nHeight ); + 0, 0, xmax, ymax, 0, frame->height ); XFreePixmap( display, pixmapBits ); } image->data = NULL; @@ -823,11 +835,11 @@ /* Now create the 2 pixmaps for bits and mask */ - pixmapBits = XCreatePixmap( display, root_window, ptr->nWidth, ptr->nHeight, 1 ); - if (ptr->bBitsPerPixel != 32) + pixmapBits = XCreatePixmap( display, root_window, frame->width, frame->height, 1 ); + if (frame->bpp != 32) { - pixmapMaskInv = XCreatePixmap( display, root_window, ptr->nWidth, ptr->nHeight, 1 ); - pixmapMask = XCreatePixmap( display, root_window, ptr->nWidth, ptr->nHeight, 1 ); + pixmapMaskInv = XCreatePixmap( display, root_window, frame->width, frame->height, 1 ); + pixmapMask = XCreatePixmap( display, root_window, frame->width, frame->height, 1 ); /* Make sure everything went OK so far */ if (pixmapBits && pixmapMask && pixmapMaskInv) @@ -856,45 +868,45 @@ */ XSetFunction( display, gc, GXcopy ); XCopyArea( display, pixmapAll, pixmapBits, gc, - 0, 0, ptr->nWidth, ptr->nHeight, 0, 0 ); + 0, 0, frame->width, frame->height, 0, 0 ); XCopyArea( display, pixmapAll, pixmapMask, gc, - 0, 0, ptr->nWidth, ptr->nHeight, 0, 0 ); + 0, 0, frame->width, frame->height, 0, 0 ); XCopyArea( display, pixmapAll, pixmapMaskInv, gc, - 0, 0, ptr->nWidth, ptr->nHeight, 0, 0 ); + 0, 0, frame->width, frame->height, 0, 0 ); XSetFunction( display, gc, GXand ); XCopyArea( display, pixmapAll, pixmapMaskInv, gc, - 0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 ); + 0, frame->height, frame->width, frame->height, 0, 0 ); XSetFunction( display, gc, GXandReverse ); XCopyArea( display, pixmapAll, pixmapBits, gc, - 0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 ); + 0, frame->height, frame->width, frame->height, 0, 0 ); XSetFunction( display, gc, GXorReverse ); XCopyArea( display, pixmapAll, pixmapMask, gc, - 0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 ); + 0, frame->height, frame->width, frame->height, 0, 0 ); /* Additional white */ XSetFunction( display, gc, GXor ); XCopyArea( display, pixmapMaskInv, pixmapMask, gc, - 0, 0, ptr->nWidth, ptr->nHeight, 1, 1 ); + 0, 0, frame->width, frame->height, 1, 1 ); XCopyArea( display, pixmapMaskInv, pixmapBits, gc, - 0, 0, ptr->nWidth, ptr->nHeight, 1, 1 ); + 0, 0, frame->width, frame->height, 1, 1 ); XSetFunction( display, gc, GXcopy ); } } else { pixmapMask = XCreateBitmapFromData( display, root_window, - bitMask32, ptr->nWidth, - ptr->nHeight ); + bitMask32, frame->width, + frame->height ); HeapFree( GetProcessHeap(), 0, bitMask32 ); } /* Make sure hotspot is valid */ - hotspot.x = ptr->ptHotSpot.x; - hotspot.y = ptr->ptHotSpot.y; - if (hotspot.x < 0 || hotspot.x >= ptr->nWidth || - hotspot.y < 0 || hotspot.y >= ptr->nHeight) + hotspot.x = frame->xhot; + hotspot.y = frame->yhot; + if (hotspot.x < 0 || hotspot.x >= frame->width || + hotspot.y < 0 || hotspot.y >= frame->height) { - hotspot.x = ptr->nWidth / 2; - hotspot.y = ptr->nHeight / 2; + hotspot.x = frame->width / 2; + hotspot.y = frame->height / 2; } if (pixmapBits && pixmapMask) diff -urN wine-1.0.orig/dlls/winex11.drv/x11drv.h wine-1.0/dlls/winex11.drv/x11drv.h --- wine-1.0.orig/dlls/winex11.drv/x11drv.h 2008-06-17 16:07:31.000000000 +0200 +++ wine-1.0/dlls/winex11.drv/x11drv.h 2008-06-27 15:53:24.000000000 +0200 @@ -724,7 +724,7 @@ extern void X11DRV_ResetSelectionOwner(void); extern void X11DRV_SetFocus( HWND hwnd ); extern Cursor X11DRV_GetCursor( Display *display, struct tagCURSORICONINFO *ptr ); -extern void X11DRV_SetCursor( struct tagCURSORICONINFO *lpCursor ); +struct cursor_t; extern BOOL X11DRV_ClipCursor( LPCRECT clip ); extern void X11DRV_InitKeyboard( Display *display ); extern void X11DRV_send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time, diff -urN wine-1.0.orig/include/wine/server_protocol.h wine-1.0/include/wine/server_protocol.h --- wine-1.0.orig/include/wine/server_protocol.h 2008-06-17 16:07:31.000000000 +0200 +++ wine-1.0/include/wine/server_protocol.h 2008-06-27 15:53:21.000000000 +0200 @@ -2755,6 +2755,90 @@ +struct create_cursor_request +{ + struct request_header __header; + unsigned int num_frames; + unsigned short delay; +}; +struct create_cursor_reply +{ + struct reply_header __header; + user_handle_t handle; +}; + + + +struct destroy_cursor_request +{ + struct request_header __header; + user_handle_t handle; +}; +struct destroy_cursor_reply +{ + struct reply_header __header; +}; + + + +struct get_cursor_info_request +{ + struct request_header __header; + user_handle_t handle; +}; +struct get_cursor_info_reply +{ + struct reply_header __header; + unsigned int num_frames; + unsigned short delay; +}; + + + +struct get_cursor_frame_request +{ + struct request_header __header; + user_handle_t handle; + unsigned int frame_idx; +}; +struct get_cursor_frame_reply +{ + struct reply_header __header; + unsigned short xhot; + unsigned short yhot; + unsigned short width; + unsigned short height; + unsigned short and_width_bytes; + unsigned short xor_width_bytes; + unsigned char planes; + unsigned char bpp; + /* VARARG(data,bytes); */ +}; + + + +struct set_cursor_frame_request +{ + struct request_header __header; + user_handle_t handle; + unsigned int frame_idx; + unsigned short xhot; + unsigned short yhot; + unsigned short width; + unsigned short height; + unsigned short and_width_bytes; + unsigned short xor_width_bytes; + unsigned char planes; + unsigned char bpp; + /* VARARG(data,bytes); */ +}; +struct set_cursor_frame_reply +{ + struct reply_header __header; +}; + + + struct create_window_request { struct request_header __header; @@ -4421,6 +4505,11 @@ REQ_get_ioctl_result, REQ_create_named_pipe, REQ_get_named_pipe_info, + REQ_create_cursor, + REQ_destroy_cursor, + REQ_get_cursor_info, + REQ_get_cursor_frame, + REQ_set_cursor_frame, REQ_create_window, REQ_destroy_window, REQ_get_desktop_window, @@ -4661,6 +4750,11 @@ struct get_ioctl_result_request get_ioctl_result_request; struct create_named_pipe_request create_named_pipe_request; struct get_named_pipe_info_request get_named_pipe_info_request; + struct create_cursor_request create_cursor_request; + struct destroy_cursor_request destroy_cursor_request; + struct get_cursor_info_request get_cursor_info_request; + struct get_cursor_frame_request get_cursor_frame_request; + struct set_cursor_frame_request set_cursor_frame_request; struct create_window_request create_window_request; struct destroy_window_request destroy_window_request; struct get_desktop_window_request get_desktop_window_request; @@ -4899,6 +4993,11 @@ struct get_ioctl_result_reply get_ioctl_result_reply; struct create_named_pipe_reply create_named_pipe_reply; struct get_named_pipe_info_reply get_named_pipe_info_reply; + struct create_cursor_reply create_cursor_reply; + struct destroy_cursor_reply destroy_cursor_reply; + struct get_cursor_info_reply get_cursor_info_reply; + struct get_cursor_frame_reply get_cursor_frame_reply; + struct set_cursor_frame_reply set_cursor_frame_reply; struct create_window_reply create_window_reply; struct destroy_window_reply destroy_window_reply; struct get_desktop_window_reply get_desktop_window_reply; diff -urN wine-1.0.orig/include/wine/winuser16.h wine-1.0/include/wine/winuser16.h --- wine-1.0.orig/include/wine/winuser16.h 2008-06-17 16:07:31.000000000 +0200 +++ wine-1.0/include/wine/winuser16.h 2008-06-27 15:53:23.000000000 +0200 @@ -148,6 +148,25 @@ /* Cursors / Icons */ +typedef struct { + unsigned short xhot; + unsigned short yhot; + unsigned short width; + unsigned short height; + unsigned short and_width_bytes; + unsigned short xor_width_bytes; + unsigned char planes; + unsigned char bpp; + /* XOR & AND bitmap bits */ + unsigned char *bits; +} cursor_frame_t; + +typedef struct cursor_t { + unsigned int num_frames; + unsigned short delay; + cursor_frame_t *frames; +} cursor_t; + typedef struct tagCURSORICONINFO { POINT16 ptHotSpot; diff -urN wine-1.0.orig/server/cursoricon.c wine-1.0/server/cursoricon.c --- wine-1.0.orig/server/cursoricon.c 1970-01-01 01:00:00.000000000 +0100 +++ wine-1.0/server/cursoricon.c 2008-06-27 15:53:20.000000000 +0200 @@ -0,0 +1,168 @@ +/* + * Server-side cursors / icons + * + * Copyright 2007 Henri Verbeet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "winternl.h" +#include "object.h" +#include "request.h" +#include "user.h" + +typedef struct { + unsigned short xhot; + unsigned short yhot; + unsigned short width; + unsigned short height; + unsigned short and_width_bytes; + unsigned short xor_width_bytes; + unsigned char planes; + unsigned char bpp; + /* bits contains both the AND and XOR bitmap data, in that order */ + unsigned char *bits; +} cursor_frame_t; + +typedef struct { + struct process *process; + unsigned int num_frames; + unsigned int delay; + cursor_frame_t *frames; +} cursor_t; + +void destroy_cursor( cursor_t *cursor ) +{ + unsigned int i; + + for (i = 0; i < cursor->num_frames; ++i) + { + free( cursor->frames[i].bits ); + } + + free( cursor->frames ); + free( cursor ); +} + +/* destroy all cursors belonging to a given process */ +void destroy_process_cursors( struct process *process ) +{ + user_handle_t handle = 0; + cursor_t *cursor; + + while ((cursor = next_user_handle( &handle, USER_CURSOR ))) + { + if (cursor->process != process) continue; + + destroy_cursor( cursor ); + free_user_handle( handle ); + } +} + +/* Create a cursor */ +DECL_HANDLER(create_cursor) +{ + cursor_t *cursor = mem_alloc( sizeof(cursor_t) ); + cursor->process = current->process; + cursor->num_frames = req->num_frames; + cursor->delay = req->delay; + cursor->frames = mem_alloc( req->num_frames * sizeof(cursor_frame_t) ); + memset( cursor->frames, 0, req->num_frames * sizeof(cursor_frame_t) ); + + reply->handle = alloc_user_handle( cursor, USER_CURSOR ); +} + +/* Destroy a cursor */ +DECL_HANDLER(destroy_cursor) +{ + cursor_t *cursor = free_user_handle( req->handle ); + + if (cursor) destroy_cursor( cursor ); +} + +/* Get cursor info */ +DECL_HANDLER(get_cursor_info) +{ + cursor_t *cursor = get_user_object( req->handle, USER_CURSOR ); + + if (!cursor) return; + + reply->num_frames = cursor->num_frames; + reply->delay = cursor->delay; +} + +/* Get frame info & bitmap bits */ +DECL_HANDLER(get_cursor_frame) +{ + unsigned int data_size; + unsigned int frame_idx = req->frame_idx; + cursor_t *cursor = get_user_object( req->handle, USER_CURSOR ); + cursor_frame_t *frame; + + if (!cursor || cursor->num_frames < frame_idx) + { + reply->height = 0; + return; + } + + frame = &cursor->frames[frame_idx]; + + reply->xhot = frame->xhot; + reply->yhot = frame->yhot; + reply->width = frame->width; + reply->height = frame->height; + reply->and_width_bytes = frame->and_width_bytes; + reply->xor_width_bytes = frame->xor_width_bytes; + reply->planes = frame->planes; + reply->bpp = frame->bpp; + + data_size = (frame->and_width_bytes + frame->xor_width_bytes) * frame->height; + if (data_size > get_reply_max_size()) + { + set_error( STATUS_BUFFER_OVERFLOW ); + return; + } + + set_reply_data( frame->bits, data_size ); +} + +/* Set frame info & bitmap bits */ +DECL_HANDLER(set_cursor_frame) +{ + size_t data_size = get_req_data_size(); + unsigned int frame_idx = req->frame_idx; + cursor_t *cursor = get_user_object( req->handle, USER_CURSOR ); + cursor_frame_t *frame; + + if (!cursor || cursor->num_frames < frame_idx || !data_size) return; + + frame = &cursor->frames[frame_idx]; + + frame->xhot = req->xhot; + frame->yhot = req->yhot; + frame->width = req->width; + frame->height = req->height; + frame->and_width_bytes = req->and_width_bytes; + frame->xor_width_bytes = req->xor_width_bytes; + frame->planes = req->planes; + frame->bpp = req->bpp; + + free( frame->bits ); + frame->bits = memdup( get_req_data(), data_size ); +} diff -urN wine-1.0.orig/server/Makefile.in wine-1.0/server/Makefile.in --- wine-1.0.orig/server/Makefile.in 2008-06-17 16:07:31.000000000 +0200 +++ wine-1.0/server/Makefile.in 2008-06-27 15:53:20.000000000 +0200 @@ -19,6 +19,7 @@ context_powerpc.c \ context_sparc.c \ context_x86_64.c \ + cursoricon.c \ debugger.c \ device.c \ directory.c \ diff -urN wine-1.0.orig/server/process.c wine-1.0/server/process.c --- wine-1.0.orig/server/process.c 2008-06-17 16:07:31.000000000 +0200 +++ wine-1.0/server/process.c 2008-06-27 15:53:20.000000000 +0200 @@ -657,6 +657,7 @@ free( dll ); } destroy_process_classes( process ); + destroy_process_cursors( process ); remove_process_locks( process ); set_process_startup_state( process, STARTUP_ABORTED ); finish_process_tracing( process ); diff -urN wine-1.0.orig/server/protocol.def wine-1.0/server/protocol.def --- wine-1.0.orig/server/protocol.def 2008-06-17 16:07:31.000000000 +0200 +++ wine-1.0/server/protocol.def 2008-06-27 15:53:20.000000000 +0200 @@ -2035,6 +2035,63 @@ @END +/* Create a cursor */ +@REQ(create_cursor) + unsigned int num_frames; + unsigned short delay; +@REPLY + user_handle_t handle; +@END + + +/* Destroy a cursor */ +@REQ(destroy_cursor) + user_handle_t handle; +@END + + +/* Get cursor info */ +@REQ(get_cursor_info) + user_handle_t handle; +@REPLY + unsigned int num_frames; + unsigned short delay; +@END + + +/* Get cursor frame */ +@REQ(get_cursor_frame) + user_handle_t handle; + unsigned int frame_idx; +@REPLY + unsigned short xhot; + unsigned short yhot; + unsigned short width; + unsigned short height; + unsigned short and_width_bytes; + unsigned short xor_width_bytes; + unsigned char planes; + unsigned char bpp; + VARARG(data,bytes); +@END + + +/* Set cursor frame */ +@REQ(set_cursor_frame) + user_handle_t handle; + unsigned int frame_idx; + unsigned short xhot; + unsigned short yhot; + unsigned short width; + unsigned short height; + unsigned short and_width_bytes; + unsigned short xor_width_bytes; + unsigned char planes; + unsigned char bpp; + VARARG(data,bytes); +@END + + /* Create a window */ @REQ(create_window) user_handle_t parent; /* parent window */ diff -urN wine-1.0.orig/server/request.h wine-1.0/server/request.h --- wine-1.0.orig/server/request.h 2008-06-17 16:07:31.000000000 +0200 +++ wine-1.0/server/request.h 2008-06-27 15:53:21.000000000 +0200 @@ -249,6 +249,11 @@ DECL_HANDLER(get_ioctl_result); DECL_HANDLER(create_named_pipe); DECL_HANDLER(get_named_pipe_info); +DECL_HANDLER(create_cursor); +DECL_HANDLER(destroy_cursor); +DECL_HANDLER(get_cursor_info); +DECL_HANDLER(get_cursor_frame); +DECL_HANDLER(set_cursor_frame); DECL_HANDLER(create_window); DECL_HANDLER(destroy_window); DECL_HANDLER(get_desktop_window); @@ -488,6 +493,11 @@ (req_handler)req_get_ioctl_result, (req_handler)req_create_named_pipe, (req_handler)req_get_named_pipe_info, + (req_handler)req_create_cursor, + (req_handler)req_destroy_cursor, + (req_handler)req_get_cursor_info, + (req_handler)req_get_cursor_frame, + (req_handler)req_set_cursor_frame, (req_handler)req_create_window, (req_handler)req_destroy_window, (req_handler)req_get_desktop_window, diff -urN wine-1.0.orig/server/trace.c wine-1.0/server/trace.c --- wine-1.0.orig/server/trace.c 2008-06-17 16:07:31.000000000 +0200 +++ wine-1.0/server/trace.c 2008-06-27 15:53:21.000000000 +0200 @@ -2544,6 +2544,69 @@ fprintf( stderr, " insize=%08x", req->insize ); } +static void dump_create_cursor_request( const struct create_cursor_request *req ) +{ + fprintf( stderr, " num_frames=%08x,", req->num_frames ); + fprintf( stderr, " delay=%04x", req->delay ); +} + +static void dump_create_cursor_reply( const struct create_cursor_reply *req ) +{ + fprintf( stderr, " handle=%p", req->handle ); +} + +static void dump_destroy_cursor_request( const struct destroy_cursor_request *req ) +{ + fprintf( stderr, " handle=%p", req->handle ); +} + +static void dump_get_cursor_info_request( const struct get_cursor_info_request *req ) +{ + fprintf( stderr, " handle=%p", req->handle ); +} + +static void dump_get_cursor_info_reply( const struct get_cursor_info_reply *req ) +{ + fprintf( stderr, " num_frames=%08x,", req->num_frames ); + fprintf( stderr, " delay=%04x", req->delay ); +} + +static void dump_get_cursor_frame_request( const struct get_cursor_frame_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " frame_idx=%08x", req->frame_idx ); +} + +static void dump_get_cursor_frame_reply( const struct get_cursor_frame_reply *req ) +{ + fprintf( stderr, " xhot=%04x,", req->xhot ); + fprintf( stderr, " yhot=%04x,", req->yhot ); + fprintf( stderr, " width=%04x,", req->width ); + fprintf( stderr, " height=%04x,", req->height ); + fprintf( stderr, " and_width_bytes=%04x,", req->and_width_bytes ); + fprintf( stderr, " xor_width_bytes=%04x,", req->xor_width_bytes ); + fprintf( stderr, " planes=%02x,", req->planes ); + fprintf( stderr, " bpp=%02x,", req->bpp ); + fprintf( stderr, " data=" ); + dump_varargs_bytes( cur_size ); +} + +static void dump_set_cursor_frame_request( const struct set_cursor_frame_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " frame_idx=%08x,", req->frame_idx ); + fprintf( stderr, " xhot=%04x,", req->xhot ); + fprintf( stderr, " yhot=%04x,", req->yhot ); + fprintf( stderr, " width=%04x,", req->width ); + fprintf( stderr, " height=%04x,", req->height ); + fprintf( stderr, " and_width_bytes=%04x,", req->and_width_bytes ); + fprintf( stderr, " xor_width_bytes=%04x,", req->xor_width_bytes ); + fprintf( stderr, " planes=%02x,", req->planes ); + fprintf( stderr, " bpp=%02x,", req->bpp ); + fprintf( stderr, " data=" ); + dump_varargs_bytes( cur_size ); +} + static void dump_create_window_request( const struct create_window_request *req ) { fprintf( stderr, " parent=%p,", req->parent ); @@ -3921,6 +3984,11 @@ (dump_func)dump_get_ioctl_result_request, (dump_func)dump_create_named_pipe_request, (dump_func)dump_get_named_pipe_info_request, + (dump_func)dump_create_cursor_request, + (dump_func)dump_destroy_cursor_request, + (dump_func)dump_get_cursor_info_request, + (dump_func)dump_get_cursor_frame_request, + (dump_func)dump_set_cursor_frame_request, (dump_func)dump_create_window_request, (dump_func)dump_destroy_window_request, (dump_func)dump_get_desktop_window_request, @@ -4157,6 +4225,11 @@ (dump_func)dump_get_ioctl_result_reply, (dump_func)dump_create_named_pipe_reply, (dump_func)dump_get_named_pipe_info_reply, + (dump_func)dump_create_cursor_reply, + (dump_func)0, + (dump_func)dump_get_cursor_info_reply, + (dump_func)dump_get_cursor_frame_reply, + (dump_func)0, (dump_func)dump_create_window_reply, (dump_func)0, (dump_func)dump_get_desktop_window_reply, @@ -4393,6 +4466,11 @@ "get_ioctl_result", "create_named_pipe", "get_named_pipe_info", + "create_cursor", + "destroy_cursor", + "get_cursor_info", + "get_cursor_frame", + "set_cursor_frame", "create_window", "destroy_window", "get_desktop_window", diff -urN wine-1.0.orig/server/user.h wine-1.0/server/user.h --- wine-1.0.orig/server/user.h 2008-06-17 16:07:31.000000000 +0200 +++ wine-1.0/server/user.h 2008-06-27 15:53:21.000000000 +0200 @@ -35,7 +35,8 @@ enum user_object { USER_WINDOW = 1, - USER_HOOK + USER_HOOK, + USER_CURSOR }; #define DESKTOP_ATOM ((atom_t)32769) @@ -75,6 +76,10 @@ extern void cleanup_clipboard_thread( struct thread *thread ); +/* cursor functions */ + +extern void destroy_process_cursors( struct process *process ); + /* hook functions */ extern void remove_thread_hooks( struct thread *thread );