2 * Copyright 2001-2010, Haiku.
3 * Distributed under the terms of the MIT License.
6 * DarkWyrm <bpmagic@columbus.rr.com>
10 #include "CursorSet.h"
11 #include "ServerCursor.h"
13 #include <AppServerLink.h>
15 #include <ServerProtocol.h>
26 \name Name of the cursor set.
28 CursorSet::CursorSet(const char *name
)
31 AddString("name", name
!= NULL
? name
: "Untitled");
36 \brief Saves the data in the cursor set to a file
37 \param path Path of the file to save to.
38 \param saveflags BFile open file flags. B_READ_WRITE is implied.
40 - \c B_OK: Everything went fine.
41 - \c B_BAD_VALUE: path is NULL
42 - \c other value: See BFile::SetTo and BMessage::Flatten return codes
45 CursorSet::Save(const char *path
, int32 saveFlags
)
51 status_t status
= file
.SetTo(path
, B_READ_WRITE
| saveFlags
);
55 return Flatten(&file
);
60 \brief Loads the data into the cursor set from a file
61 \param path Path of the file to load from.
63 - \c B_OK: Everything went fine.
64 - \c B_BAD_VALUE: path is NULL
65 - \c other value: See BFile::SetTo and BMessage::Flatten return codes
68 CursorSet::Load(const char *path
)
74 status_t status
= file
.SetTo(path
, B_READ_ONLY
);
78 return Unflatten(&file
);
83 \brief Adds the cursor to the set and replaces any existing entry for the given specifier
84 \param which System cursor specifier defined in CursorSet.h
85 \param cursor BBitmap to represent the new cursor. Size should be 48x48 or less.
86 \param hotspot The recipient of the hotspot for the cursor
88 - \c B_OK: Everything went fine.
89 - \c B_BAD_VALUE: cursor is NULL
90 - \c other value: See BMessage::AddMessage return codes.
93 CursorSet::AddCursor(BCursorID which
, const BBitmap
*cursor
,
94 const BPoint
&hotspot
)
99 // Remove the data if it exists already
100 RemoveData(_CursorWhichToString(which
));
102 // Actually add the data to our set
103 BMessage
message((int32
)which
);
105 message
.AddString("class", "bitmap");
106 message
.AddRect("_frame", cursor
->Bounds());
107 message
.AddInt32("_cspace", cursor
->ColorSpace());
109 message
.AddInt32("_bmflags", 0);
110 message
.AddInt32("_rowbytes", cursor
->BytesPerRow());
111 message
.AddPoint("hotspot", hotspot
);
112 message
.AddData("_data", B_RAW_TYPE
, cursor
->Bits(), cursor
->BitsLength());
114 return AddMessage(_CursorWhichToString(which
), &message
);
119 \brief Adds the cursor to the set and replaces any existing entry for the given specifier
120 \param which System cursor specifier defined in CursorSet.h
121 \param data R5 cursor data pointer
122 \return B_BAD_VALUE if data is NULL, otherwise B_OK
124 When possible, it is better to use the BBitmap version of AddCursor because this
125 function must convert the R5 cursor data into a BBitmap
128 CursorSet::AddCursor(BCursorID which
, uint8
*data
)
130 // Convert cursor data to a bitmap because all cursors are internally stored
135 BBitmap
*bitmap
= _CursorDataToBitmap(data
);
136 BPoint
hotspot(data
[2], data
[3]);
138 status_t result
= AddCursor(which
, bitmap
, hotspot
);
146 \brief Removes the data associated with the specifier from the cursor set
147 \param which System cursor specifier defined in CursorSet.h
150 CursorSet::RemoveCursor(BCursorID which
)
152 RemoveData(_CursorWhichToString(which
));
157 \brief Retrieves a cursor from the set.
158 \param which System cursor specifier defined in CursorSet.h
159 \param cursor Bitmap** to receive a newly-allocated BBitmap containing the appropriate data
160 \param hotspot The recipient of the hotspot for the cursor
163 - \c B_BAD_VALUE: a NULL parameter was passed
164 - \c B_NAME_NOT_FOUND: The specified cursor does not exist in this set
165 - \c B_ERROR: An internal error occurred
167 BBitmaps created by this function are the responsibility of the caller.
170 CursorSet::FindCursor(BCursorID which
, BBitmap
**_cursor
, BPoint
*_hotspot
)
172 if (_cursor
== NULL
|| _hotspot
== NULL
)
176 if (FindMessage(_CursorWhichToString(which
), &message
) != B_OK
)
177 return B_NAME_NOT_FOUND
;
179 const char *className
;
180 if (message
.FindString("class", &className
) != B_OK
181 || strcmp(className
, "cursor") != 0) {
186 if (message
.FindPoint("hotspot", &hotspot
) != B_OK
)
191 if (message
.FindData("_data", B_RAW_TYPE
, (const void **)&buffer
,
192 (ssize_t
*)&bufferLength
) != B_OK
) {
196 BBitmap
*bitmap
= new(std::nothrow
) BBitmap(message
.FindRect("_frame"),
197 (color_space
)message
.FindInt32("_cspace"), true);
201 memcpy(bitmap
->Bits(), buffer
,
202 min_c(bufferLength
, bitmap
->BitsLength()));
211 \brief Retrieves a cursor from the set.
212 \param which System cursor specifier defined in CursorSet.h
213 \param cursor ServerCursor** to receive a newly-allocated ServerCursor containing the appropriate data
216 - \c B_BAD_VALUE: a NULL parameter was passed
217 - \c B_NAME_NOT_FOUND: The specified cursor does not exist in this set
218 - \c B_ERROR: An internal error occurred
220 BBitmaps created by this function are the responsibility of the caller.
223 CursorSet::FindCursor(BCursorID which
, ServerCursor
**_cursor
) const
229 if (FindMessage(_CursorWhichToString(which
), &message
) != B_OK
)
230 return B_NAME_NOT_FOUND
;
232 const char *className
;
233 if (message
.FindString("class", &className
) != B_OK
234 || strcmp(className
, "cursor") != 0) {
239 if (message
.FindPoint("hotspot", &hotspot
) != B_OK
)
244 if (message
.FindData("_data", B_RAW_TYPE
, (const void **)&buffer
,
245 (ssize_t
*)&bufferLength
) != B_OK
) {
249 ServerCursor
*cursor
= new(std::nothrow
) ServerCursor(
250 message
.FindRect("_frame"), (color_space
)message
.FindInt32("_cspace"),
255 memcpy(cursor
->Bits(), buffer
,
256 min_c(bufferLength
, (ssize_t
)cursor
->BitsLength()));
264 \brief Returns the name of the set
265 \return The name of the set
271 if (FindString("name", &name
) == B_OK
)
279 \brief Renames the cursor set
280 \param name new name of the set.
282 This function will fail if given a NULL name
285 CursorSet::SetName(const char *name
)
291 AddString("name", name
);
296 \brief Returns a string for the specified cursor attribute
297 \param which System cursor specifier defined in CursorSet.h
298 \return Name for the cursor specifier
301 CursorSet::_CursorWhichToString(BCursorID which
) const
304 case B_CURSOR_ID_SYSTEM_DEFAULT
:
305 return "System default";
306 case B_CURSOR_ID_CONTEXT_MENU
:
307 return "Context menu";
308 case B_CURSOR_ID_COPY
:
310 case B_CURSOR_ID_CROSS_HAIR
:
312 case B_CURSOR_ID_NO_CURSOR
:
314 case B_CURSOR_ID_FOLLOW_LINK
:
315 return "Follow link";
316 case B_CURSOR_ID_GRAB
:
318 case B_CURSOR_ID_GRABBING
:
320 case B_CURSOR_ID_HELP
:
322 case B_CURSOR_ID_I_BEAM
:
324 case B_CURSOR_ID_I_BEAM_HORIZONTAL
:
325 return "I-beam horizontal";
326 case B_CURSOR_ID_MOVE
:
328 case B_CURSOR_ID_NOT_ALLOWED
:
329 return "Not allowed";
330 case B_CURSOR_ID_PROGRESS
:
332 case B_CURSOR_ID_RESIZE_NORTH
:
333 return "Resize North";
334 case B_CURSOR_ID_RESIZE_EAST
:
335 return "Resize East";
336 case B_CURSOR_ID_RESIZE_SOUTH
:
337 return "Resize South";
338 case B_CURSOR_ID_RESIZE_WEST
:
339 return "Resize West";
340 case B_CURSOR_ID_RESIZE_NORTH_EAST
:
341 return "Resize North East";
342 case B_CURSOR_ID_RESIZE_NORTH_WEST
:
343 return "Resize North West";
344 case B_CURSOR_ID_RESIZE_SOUTH_EAST
:
345 return "Resize South East";
346 case B_CURSOR_ID_RESIZE_SOUTH_WEST
:
347 return "Resize South West";
348 case B_CURSOR_ID_RESIZE_NORTH_SOUTH
:
349 return "Resize North South";
350 case B_CURSOR_ID_RESIZE_EAST_WEST
:
351 return "Resize East West";
352 case B_CURSOR_ID_RESIZE_NORTH_EAST_SOUTH_WEST
:
353 return "Resize North East South West";
354 case B_CURSOR_ID_RESIZE_NORTH_WEST_SOUTH_EAST
:
355 return "Resize North West South East";
356 case B_CURSOR_ID_ZOOM_IN
:
358 case B_CURSOR_ID_ZOOM_OUT
:
366 \brief Creates a new BBitmap from R5 cursor data
367 \param data Pointer to data in the R5 cursor data format
368 \return NULL if data was NULL, otherwise a new BBitmap
370 BBitmaps returned by this function are always in the RGBA32 color space
373 CursorSet::_CursorDataToBitmap(uint8
*data
)
375 // 68-byte array used in R5 for holding cursors.
376 // This API has serious problems and should be deprecated (but supported)
382 // Now that we have all the setup, we're going to map (for now) the cursor
383 // to RGBA32. Eventually, there will be support for 16 and 8-bit depths
385 = new(std::nothrow
) BBitmap(BRect(0,0,15,15), B_RGBA32
, 0);
389 const uint32 black
= 0xff000000;
390 const uint32 white
= 0xffffffff;
392 uint8
*buffer
= (uint8
*)bitmap
->Bits();
393 uint16
*cursorPosition
= (uint16
*)(data
+ 4);
394 uint16
*maskPosition
= (uint16
*)(data
+ 36);
396 // for each row in the cursor data
397 for (uint8 y
= 0; y
< 16; y
++) {
398 uint32
*bitmapPosition
399 = (uint32
*)(buffer
+ y
* bitmap
->BytesPerRow());
401 // TODO: use proper byteswap macros
402 // On intel, our bytes end up swapped, so we must swap them back
403 uint16 cursorFlip
= (cursorPosition
[y
] & 0xff) << 8;
404 cursorFlip
|= (cursorPosition
[y
] & 0xff00) >> 8;
406 uint16 maskFlip
= (maskPosition
[y
] & 0xff) << 8;
407 maskFlip
|= (maskPosition
[y
] & 0xff00) >> 8;
409 // for each column in each row of cursor data
410 for (uint8 x
= 0; x
< 16; x
++) {
411 // Get the values and dump them to the bitmap
412 uint16 bit
= 1 << (15 - x
);
413 bitmapPosition
[x
] = ((cursorFlip
& bit
) != 0 ? black
: white
)
414 & ((maskFlip
& bit
) != 0 ? 0xffffffff : 0x00ffffff);