Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
274e5db7
Commit
274e5db7
authored
Mar 16, 2011
by
Erich Hoover
Committed by
Alexandre Julliard
Mar 17, 2011
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
user32: Add support for sequence-based animated cursors.
parent
7b333de8
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
112 additions
and
59 deletions
+112
-59
cursoricon.c
dlls/user32/cursoricon.c
+73
-34
cursoricon.c
dlls/user32/tests/cursoricon.c
+39
-25
No files found.
dlls/user32/cursoricon.c
View file @
274e5db7
...
...
@@ -119,13 +119,13 @@ struct animated_cursoricon_object
HICON
frames
[
1
];
/* list of animated cursor frames */
};
static
HICON
alloc_icon_handle
(
BOOL
is_ani
,
UINT
num_
frame
s
)
static
HICON
alloc_icon_handle
(
BOOL
is_ani
,
UINT
num_
step
s
)
{
struct
cursoricon_object
*
obj
;
int
icon_size
;
if
(
is_ani
)
icon_size
=
FIELD_OFFSET
(
struct
animated_cursoricon_object
,
frames
[
num_
frame
s
]
);
icon_size
=
FIELD_OFFSET
(
struct
animated_cursoricon_object
,
frames
[
num_
step
s
]
);
else
icon_size
=
sizeof
(
struct
static_cursoricon_object
);
obj
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
icon_size
);
...
...
@@ -136,8 +136,8 @@ static HICON alloc_icon_handle( BOOL is_ani, UINT num_frames )
{
struct
animated_cursoricon_object
*
ani_icon_data
=
(
struct
animated_cursoricon_object
*
)
obj
;
ani_icon_data
->
num_steps
=
num_
frames
;
/* changed later for some animated cursors */
ani_icon_data
->
num_frames
=
num_
frames
;
ani_icon_data
->
num_steps
=
num_
steps
;
ani_icon_data
->
num_frames
=
num_
steps
;
/* changed later for some animated cursors */
}
return
alloc_user_handle
(
&
obj
->
obj
,
USER_ICON
);
}
...
...
@@ -228,8 +228,22 @@ static BOOL free_icon_handle( HICON handle )
{
struct
animated_cursoricon_object
*
ani_icon_data
=
(
struct
animated_cursoricon_object
*
)
obj
;
for
(
i
=
0
;
i
<
ani_icon_data
->
num_frames
;
i
++
)
free_icon_handle
(
ani_icon_data
->
frames
[
i
]
);
for
(
i
=
0
;
i
<
ani_icon_data
->
num_steps
;
i
++
)
{
HICON
hFrame
=
ani_icon_data
->
frames
[
i
];
if
(
hFrame
)
{
UINT
j
;
free_icon_handle
(
ani_icon_data
->
frames
[
i
]
);
for
(
j
=
0
;
j
<
ani_icon_data
->
num_steps
;
j
++
)
{
if
(
ani_icon_data
->
frames
[
j
]
==
hFrame
)
ani_icon_data
->
frames
[
j
]
=
0
;
}
}
}
}
if
(
!
IS_INTRESOURCE
(
obj
->
resname
))
HeapFree
(
GetProcessHeap
(),
0
,
obj
->
resname
);
HeapFree
(
GetProcessHeap
(),
0
,
obj
);
...
...
@@ -1070,15 +1084,19 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
struct
animated_cursoricon_object
*
ani_icon_data
;
struct
cursoricon_object
*
info
;
DWORD
*
frame_rates
=
NULL
;
DWORD
*
frame_seq
=
NULL
;
ani_header
header
=
{
0
};
BOOL
use_seq
=
FALSE
;
HCURSOR
cursor
=
0
;
UINT
i
,
error
=
0
;
HICON
*
frames
;
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
};
riff_chunk_t
rate_chunk
=
{
0
};
riff_chunk_t
seq_chunk
=
{
0
};
const
unsigned
char
*
icon_chunk
;
const
unsigned
char
*
icon_data
;
...
...
@@ -1107,13 +1125,23 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
}
if
(
header
.
flags
&
ANI_FLAG_SEQUENCE
)
FIXME
(
"Animated icon/cursor sequence data is not currently supported, frames may appear out of sequence.
\n
"
);
{
riff_find_chunk
(
ANI_seq__ID
,
0
,
&
ACON_chunk
,
&
seq_chunk
);
if
(
seq_chunk
.
data
)
{
frame_seq
=
(
DWORD
*
)
seq_chunk
.
data
;
use_seq
=
TRUE
;
}
else
{
FIXME
(
"Sequence data expected but not found, assuming steps == frames.
\n
"
);
header
.
num_steps
=
header
.
num_frames
;
}
}
riff_find_chunk
(
ANI_rate_ID
,
0
,
&
ACON_chunk
,
&
rate_chunk
);
if
(
rate_chunk
.
data
&&
header
.
num_steps
==
header
.
num_frames
)
if
(
rate_chunk
.
data
)
frame_rates
=
(
DWORD
*
)
rate_chunk
.
data
;
else
if
(
rate_chunk
.
data
&&
header
.
num_steps
!=
1
)
FIXME
(
"Animated icon/cursor rate data for sequence-based cursors not supported.
\n
"
);
riff_find_chunk
(
ANI_fram_ID
,
ANI_LIST_ID
,
&
ACON_chunk
,
&
fram_chunk
);
if
(
!
fram_chunk
.
data
)
...
...
@@ -1122,19 +1150,19 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
return
0
;
}
cursor
=
alloc_icon_handle
(
TRUE
,
header
.
num_
frame
s
);
cursor
=
alloc_icon_handle
(
TRUE
,
header
.
num_
step
s
);
if
(
!
cursor
)
return
0
;
frames
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
DWORD
)
*
header
.
num_frames
);
if
(
!
frames
)
{
free_icon_handle
(
cursor
);
return
0
;
}
info
=
get_icon_ptr
(
cursor
);
ani_icon_data
=
(
struct
animated_cursoricon_object
*
)
info
;
info
->
is_icon
=
FALSE
;
if
(
header
.
num_steps
>
header
.
num_frames
)
{
FIXME
(
"More steps than frames and sequence-based cursors not yet supported.
\n
"
);
ani_icon_data
->
num_steps
=
header
.
num_frames
;
}
else
ani_icon_data
->
num_steps
=
header
.
num_steps
;
ani_icon_data
->
num_frames
=
header
.
num_frames
;
/* The .ANI stores the display rate in jiffies (1/60s) */
info
->
delay
=
header
.
display_rate
;
...
...
@@ -1145,10 +1173,8 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
{
const
DWORD
chunk_size
=
*
(
const
DWORD
*
)(
icon_chunk
+
sizeof
(
DWORD
));
const
CURSORICONFILEDIRENTRY
*
entry
;
struct
cursoricon_frame
*
frame
;
INT
frameWidth
,
frameHeight
;
const
BITMAPINFO
*
bmi
;
HICON
hIconFrame
;
entry
=
CURSORICON_FindBestIconFile
((
const
CURSORICONFILEDIR
*
)
icon_data
,
width
,
height
,
depth
,
loadflags
);
...
...
@@ -1168,9 +1194,9 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
}
/* Grab a frame from the animation */
hIconFrame
=
create_icon_from_bmi
(
(
BITMAPINFO
*
)
bmi
,
NULL
,
NULL
,
NULL
,
info
->
hotspot
,
FALSE
,
frameWidth
,
frameHeight
,
loadflags
);
if
(
!
hIconFrame
)
frames
[
i
]
=
create_icon_from_bmi
(
(
BITMAPINFO
*
)
bmi
,
NULL
,
NULL
,
NULL
,
info
->
hotspot
,
FALSE
,
frameWidth
,
frameHeight
,
loadflags
);
if
(
!
frames
[
i
]
)
{
FIXME_
(
cursor
)(
"failed to convert animated cursor frame.
\n
"
);
error
=
TRUE
;
...
...
@@ -1180,20 +1206,12 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
ani_icon_data
->
num_frames
=
0
;
release_icon_ptr
(
cursor
,
info
);
free_icon_handle
(
cursor
);
HeapFree
(
GetProcessHeap
(),
0
,
frames
);
return
0
;
}
break
;
}
/* Setup the animated frame */
ani_icon_data
->
frames
[
i
]
=
hIconFrame
;
frame
=
get_icon_frame
(
info
,
i
);
if
(
frame_rates
)
frame
->
delay
=
frame_rates
[
i
];
else
frame
->
delay
=
~
0
;
release_icon_frame
(
info
,
i
,
frame
);
/* Advance to the next chunk */
icon_chunk
+=
chunk_size
+
(
2
*
sizeof
(
DWORD
));
icon_data
=
icon_chunk
+
(
2
*
sizeof
(
DWORD
));
...
...
@@ -1205,10 +1223,33 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
FIXME_
(
cursor
)(
"Error creating animated cursor, only using first frame!
\n
"
);
for
(
i
=
1
;
i
<
ani_icon_data
->
num_frames
;
i
++
)
free_icon_handle
(
ani_icon_data
->
frames
[
i
]
);
use_seq
=
FALSE
;
info
->
delay
=
0
;
ani_icon_data
->
num_steps
=
1
;
ani_icon_data
->
num_frames
=
1
;
}
/* Setup the animated frames in the correct sequence */
for
(
i
=
0
;
i
<
ani_icon_data
->
num_steps
;
i
++
)
{
DWORD
frame_id
=
use_seq
?
frame_seq
[
i
]
:
i
;
struct
cursoricon_frame
*
frame
;
if
(
frame_id
>=
ani_icon_data
->
num_frames
)
{
frame_id
=
ani_icon_data
->
num_frames
-
1
;
ERR_
(
cursor
)(
"Sequence indicates frame past end of list, corrupt?
\n
"
);
}
ani_icon_data
->
frames
[
i
]
=
frames
[
frame_id
];
frame
=
get_icon_frame
(
info
,
i
);
if
(
frame_rates
)
frame
->
delay
=
frame_rates
[
i
];
else
frame
->
delay
=
~
0
;
release_icon_frame
(
info
,
i
,
frame
);
}
HeapFree
(
GetProcessHeap
(),
0
,
frames
);
release_icon_ptr
(
cursor
,
info
);
return
cursor
;
...
...
@@ -1851,8 +1892,6 @@ HCURSOR WINAPI GetCursorFrameInfo(HCURSOR hCursor, DWORD unk1, DWORD istep, DWOR
FIXME
(
"semi-stub! %p => %d %d %p %p
\n
"
,
hCursor
,
unk1
,
istep
,
rate_jiffies
,
num_steps
);
icon_steps
=
get_icon_steps
(
ptr
);
/* Important Note: Sequences are not currently supported, so this implementation
* will not properly handle all cases. */
if
(
istep
<
icon_steps
||
!
ptr
->
is_ani
)
{
struct
animated_cursoricon_object
*
ani_icon_data
=
(
struct
animated_cursoricon_object
*
)
ptr
;
...
...
dlls/user32/tests/cursoricon.c
View file @
274e5db7
...
...
@@ -135,14 +135,21 @@ typedef struct {
}
riff_rate3_t
;
typedef
struct
{
DWORD
chunk_id
;
/* ANI_seq__ID */
DWORD
chunk_size
;
/* actual size of data */
DWORD
order
[
3
];
/* animated cursor sequence data */
}
riff_seq3_t
;
typedef
struct
{
DWORD
chunk_id
;
/* ANI_RIFF_ID */
DWORD
chunk_size
;
/* actual size of data */
DWORD
chunk_type
;
/* ANI_ACON_ID */
riff_header_t
header
;
/* RIFF animated cursor header */
riff_seq3_t
seq
;
/* sequence data for three cursor frames */
riff_rate3_t
rates
;
/* rate data for three cursor frames */
riff_list_t
frame_list
;
/* RIFF animated cursor frame list info */
riff_icon32x32x32_t
frames
[
3
];
/* array of three animated cursor frames */
}
riff_cursor3_
rate
_t
;
}
riff_cursor3_
seq
_t
;
#define EMPTY_ICON32 \
{ \
...
...
@@ -243,26 +250,31 @@ riff_cursor3_t empty_anicursor3 = {
}
};
riff_cursor3_
rate_t
empty_anicursor3_rate
=
{
riff_cursor3_
seq_t
empty_anicursor3_seq
=
{
ANI_RIFF_ID
,
sizeof
(
empty_anicursor3_
rate
)
-
sizeof
(
DWORD
)
*
2
,
sizeof
(
empty_anicursor3_
seq
)
-
sizeof
(
DWORD
)
*
2
,
ANI_ACON_ID
,
{
ANI_anih_ID
,
sizeof
(
ani_header
),
{
sizeof
(
ani_header
),
3
,
/* frames */
3
,
/* steps */
32
,
/* width */
32
,
/* height */
32
,
/* depth */
1
,
/* planes */
0xbeef
,
/* display rate in jiffies */
ANI_FLAG_ICON
/* flags */
3
,
/* frames */
3
,
/* steps */
32
,
/* width */
32
,
/* height */
32
,
/* depth */
1
,
/* planes */
0xbeef
,
/* display rate in jiffies */
ANI_FLAG_ICON
|
ANI_FLAG_SEQUENCE
/* flags */
}
},
{
ANI_seq__ID
,
sizeof
(
riff_seq3_t
)
-
sizeof
(
DWORD
)
*
2
,
{
2
,
0
,
1
}
/* show frames in a uniquely identifiable order */
},
{
ANI_rate_ID
,
sizeof
(
riff_rate3_t
)
-
sizeof
(
DWORD
)
*
2
,
{
0xc0de
,
0xcafe
,
0xbabe
}
...
...
@@ -1639,41 +1651,43 @@ static void test_GetCursorFrameInfo(void)
ok
(
ret
,
"DestroyCursor() failed (error = %d).
\n
"
,
GetLastError
());
/* Creating a multi-frame animated cursor with rate data. */
for
(
i
=
0
;
i
<
empty_anicursor3_
rate
.
header
.
header
.
num_frames
;
i
++
)
for
(
i
=
0
;
i
<
empty_anicursor3_
seq
.
header
.
header
.
num_frames
;
i
++
)
{
empty_anicursor3_
rate
.
frames
[
i
].
data
.
icon_info
.
idType
=
2
;
/* type: cursor */
empty_anicursor3_
rate
.
frames
[
i
].
data
.
icon_info
.
idEntries
[
0
].
xHotspot
=
3
;
empty_anicursor3_
rate
.
frames
[
i
].
data
.
icon_info
.
idEntries
[
0
].
yHotspot
=
3
;
memcpy
(
&
empty_anicursor3_
rate
.
frames
[
i
].
data
.
bmi_data
.
data
[
0
],
&
frame_identifier
[
i
],
sizeof
(
DWORD
)
);
empty_anicursor3_
seq
.
frames
[
i
].
data
.
icon_info
.
idType
=
2
;
/* type: cursor */
empty_anicursor3_
seq
.
frames
[
i
].
data
.
icon_info
.
idEntries
[
0
].
xHotspot
=
3
;
empty_anicursor3_
seq
.
frames
[
i
].
data
.
icon_info
.
idEntries
[
0
].
yHotspot
=
3
;
memcpy
(
&
empty_anicursor3_
seq
.
frames
[
i
].
data
.
bmi_data
.
data
[
0
],
&
frame_identifier
[
i
],
sizeof
(
DWORD
)
);
}
SetLastError
(
0xdeadbeef
);
h1
=
CreateIconFromResource
((
PBYTE
)
&
empty_anicursor3_
rate
,
sizeof
(
empty_anicursor3_rate
),
FALSE
,
0x00030000
);
h1
=
CreateIconFromResource
((
PBYTE
)
&
empty_anicursor3_
seq
,
sizeof
(
empty_anicursor3_seq
),
FALSE
,
0x00030000
);
ok
(
h1
!=
NULL
,
"Create cursor failed (error = %x).
\n
"
,
GetLastError
());
/* Check number of steps in multi-frame animated cursor with rate data */
i
=
0
;
while
(
DrawIconEx
(
hdc
,
0
,
0
,
h1
,
32
,
32
,
i
,
NULL
,
DI_NORMAL
))
i
++
;
ok
(
i
==
empty_anicursor3_
rate
.
header
.
header
.
num_steps
,
ok
(
i
==
empty_anicursor3_
seq
.
header
.
header
.
num_steps
,
"Unexpected number of steps in cursor (%d != %d)
\n
"
,
i
,
empty_anicursor3_
rate
.
header
.
header
.
num_steps
);
i
,
empty_anicursor3_
seq
.
header
.
header
.
num_steps
);
/* Check GetCursorFrameInfo behavior on a multi-frame animated cursor with rate data */
for
(
i
=
0
;
i
<
empty_anicursor3_
rate
.
header
.
header
.
num_frames
;
i
++
)
for
(
i
=
0
;
i
<
empty_anicursor3_
seq
.
header
.
header
.
num_frames
;
i
++
)
{
int
frame_id
=
empty_anicursor3_seq
.
seq
.
order
[
i
];
unk1
=
unk2
=
unk3
=
unk4
=
0xdead
;
h2
=
pGetCursorFrameInfo
(
h1
,
&
unk1
,
(
VOID
*
)
i
,
&
unk3
,
&
unk4
);
ok
(
h1
!=
h2
&&
h2
!=
0
,
"GetCursorFrameInfo() failed for cursor %p: (%p, %p).
\n
"
,
h1
,
h1
,
h2
);
ret
=
check_cursor_data
(
hdc
,
h2
,
&
frame_identifier
[
i
],
sizeof
(
DWORD
)
);
ret
=
check_cursor_data
(
hdc
,
h2
,
&
frame_identifier
[
frame_id
],
sizeof
(
DWORD
)
);
ok
(
ret
,
"GetCursorFrameInfo() returned wrong cursor data for frame %d.
\n
"
,
i
);
ok
(
unk1
==
0xdead
,
"GetCursorFrameInfo() unexpected param 2 value (0x%x != 0xdead).
\n
"
,
unk1
);
ok
(
unk2
==
0xdead
,
"GetCursorFrameInfo() unexpected param 3 value (0x%x != 0xdead).
\n
"
,
unk2
);
ok
(
unk3
==
empty_anicursor3_
rate
.
rates
.
rate
[
i
],
ok
(
unk3
==
empty_anicursor3_
seq
.
rates
.
rate
[
i
],
"GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x%x).
\n
"
,
unk3
,
empty_anicursor3_
rate
.
rates
.
rate
[
i
]);
ok
(
unk4
==
empty_anicursor3_
rate
.
header
.
header
.
num_steps
,
unk3
,
empty_anicursor3_
seq
.
rates
.
rate
[
i
]);
ok
(
unk4
==
empty_anicursor3_
seq
.
header
.
header
.
num_steps
,
"GetCursorFrameInfo() unexpected param 5 value (%d != %d).
\n
"
,
unk4
,
empty_anicursor3_
rate
.
header
.
header
.
num_steps
);
unk4
,
empty_anicursor3_
seq
.
header
.
header
.
num_steps
);
}
/* Clean up multi-frame animated cursor with rate data. */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment