1 /* 2 * Copyright 2001-2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * DarkWyrm <bpmagic@columbus.rr.com> 7 */ 8 9 10 #include "CursorSet.h" 11 #include "ServerCursor.h" 12 13 #include <AppServerLink.h> 14 #include <PortLink.h> 15 #include <ServerProtocol.h> 16 17 #include <OS.h> 18 #include <String.h> 19 #include <File.h> 20 21 22 /*! 23 \brief Constructor 24 \name Name of the cursor set. 25 */ 26 CursorSet::CursorSet(const char *name) 27 : BMessage() 28 { 29 AddString("name", name ? name : "Untitled"); 30 } 31 32 33 /*! 34 \brief Saves the data in the cursor set to a file 35 \param path Path of the file to save to. 36 \param saveflags BFile open file flags. B_READ_WRITE is implied. 37 \return 38 - \c B_OK: Everything went fine. 39 - \c B_BAD_VALUE: path is NULL 40 - \c other value: See BFile::SetTo and BMessage::Flatten return codes 41 */ 42 status_t 43 CursorSet::Save(const char *path, int32 saveFlags) 44 { 45 if (!path) 46 return B_BAD_VALUE; 47 48 BFile file; 49 status_t status = file.SetTo(path, B_READ_WRITE | saveFlags); 50 if (status != B_OK) 51 return status; 52 53 return Flatten(&file); 54 } 55 56 57 /*! 58 \brief Loads the data into the cursor set from a file 59 \param path Path of the file to load from. 60 \return 61 - \c B_OK: Everything went fine. 62 - \c B_BAD_VALUE: path is NULL 63 - \c other value: See BFile::SetTo and BMessage::Flatten return codes 64 */ 65 status_t 66 CursorSet::Load(const char *path) 67 { 68 if (!path) 69 return B_BAD_VALUE; 70 71 BFile file; 72 status_t status = file.SetTo(path, B_READ_ONLY); 73 if (status != B_OK) 74 return status; 75 76 return Unflatten(&file); 77 } 78 79 80 /*! 81 \brief Adds the cursor to the set and replaces any existing entry for the given specifier 82 \param which System cursor specifier defined in CursorSet.h 83 \param cursor BBitmap to represent the new cursor. Size should be 48x48 or less. 84 \param hotspot The recipient of the hotspot for the cursor 85 \return B_BAD_VALUE if cursor is NULL, otherwise B_OK 86 */ 87 status_t 88 CursorSet::AddCursor(cursor_which which, const BBitmap *cursor, const BPoint &hotspot) 89 { 90 if (!cursor) 91 return B_BAD_VALUE; 92 93 // Remove the data if it exists already 94 RemoveData(_CursorWhichToString(which)); 95 96 // Actually add the data to our set 97 BMessage msg((int32)which); 98 99 msg.AddString("class","bitmap"); 100 msg.AddRect("_frame",cursor->Bounds()); 101 msg.AddInt32("_cspace",cursor->ColorSpace()); 102 103 msg.AddInt32("_bmflags",0); 104 msg.AddInt32("_rowbytes",cursor->BytesPerRow()); 105 msg.AddPoint("hotspot",hotspot); 106 msg.AddData("_data",B_RAW_TYPE,cursor->Bits(), cursor->BitsLength()); 107 AddMessage(_CursorWhichToString(which),&msg); 108 109 return B_OK; 110 } 111 112 113 /*! 114 \brief Adds the cursor to the set and replaces any existing entry for the given specifier 115 \param which System cursor specifier defined in CursorSet.h 116 \param data R5 cursor data pointer 117 \return B_BAD_VALUE if data is NULL, otherwise B_OK 118 119 When possible, it is better to use the BBitmap version of AddCursor because this 120 function must convert the R5 cursor data into a BBitmap 121 */ 122 status_t 123 CursorSet::AddCursor(cursor_which which, uint8 *data) 124 { 125 // Convert cursor data to a bitmap because all cursors are internally stored 126 // as bitmaps 127 if (!data) 128 return B_BAD_VALUE; 129 130 BBitmap *bmp = _CursorDataToBitmap(data); 131 BPoint pt(data[2],data[3]); 132 133 status_t stat = AddCursor(which,bmp,pt); 134 135 delete bmp; 136 return stat; 137 } 138 139 140 /*! 141 \brief Removes the data associated with the specifier from the cursor set 142 \param which System cursor specifier defined in CursorSet.h 143 */ 144 void 145 CursorSet::RemoveCursor(cursor_which which) 146 { 147 RemoveData(_CursorWhichToString(which)); 148 } 149 150 151 /*! 152 \brief Retrieves a cursor from the set. 153 \param which System cursor specifier defined in CursorSet.h 154 \param cursor Bitmap** to receive a newly-allocated BBitmap containing the appropriate data 155 \param hotspot The recipient of the hotspot for the cursor 156 \return 157 - \c B_OK: Success 158 - \c B_BAD_VALUE: a NULL parameter was passed 159 - \c B_NAME_NOT_FOUND: The specified cursor does not exist in this set 160 - \c B_ERROR: An internal error occurred 161 162 BBitmaps created by this function are the responsibility of the caller. 163 */ 164 status_t 165 CursorSet::FindCursor(cursor_which which, BBitmap **cursor, BPoint *hotspot) 166 { 167 if (!cursor || !hotspot); 168 return B_BAD_VALUE; 169 170 BMessage msg; 171 if (FindMessage(_CursorWhichToString(which), &msg) != B_OK) 172 return B_NAME_NOT_FOUND; 173 174 const void *buffer; 175 const char *tempstr; 176 int32 bufferLength; 177 BBitmap *bmp; 178 BPoint hotpt; 179 180 if (msg.FindString("class", &tempstr) != B_OK) 181 return B_ERROR; 182 183 if (msg.FindPoint("hotspot", &hotpt) != B_OK) 184 return B_ERROR; 185 186 if (strcmp(tempstr, "cursor") == 0) { 187 bmp = new BBitmap(msg.FindRect("_frame"), 188 (color_space)msg.FindInt32("_cspace"), true); 189 msg.FindData("_data", B_RAW_TYPE, (const void **)&buffer, 190 (ssize_t *)&bufferLength); 191 memcpy(bmp->Bits(), buffer, bufferLength); 192 193 *cursor = bmp; 194 *hotspot = hotpt; 195 return B_OK; 196 } 197 return B_ERROR; 198 } 199 200 201 /*! 202 \brief Retrieves a cursor from the set. 203 \param which System cursor specifier defined in CursorSet.h 204 \param cursor ServerCursor** to receive a newly-allocated ServerCursor containing the appropriate data 205 \return 206 - \c B_OK: Success 207 - \c B_BAD_VALUE: a NULL parameter was passed 208 - \c B_NAME_NOT_FOUND: The specified cursor does not exist in this set 209 - \c B_ERROR: An internal error occurred 210 211 BBitmaps created by this function are the responsibility of the caller. 212 */ 213 status_t 214 CursorSet::FindCursor(cursor_which which, ServerCursor **_cursor) 215 { 216 BMessage msg; 217 if (FindMessage(_CursorWhichToString(which), &msg) != B_OK) 218 return B_NAME_NOT_FOUND; 219 220 const char *className; 221 BPoint hotspot; 222 223 if (msg.FindString("class", &className) != B_OK) 224 return B_ERROR; 225 226 if (msg.FindPoint("hotspot", &hotspot) != B_OK) 227 return B_ERROR; 228 229 if (strcmp(className, "cursor") == 0) { 230 ServerCursor *cursor = new ServerCursor(msg.FindRect("_frame"), 231 (color_space)msg.FindInt32("_cspace"), 0, hotspot); 232 233 const void *buffer; 234 int32 bufferLength; 235 msg.FindData("_data",B_RAW_TYPE, (const void **)&buffer, 236 (ssize_t *)&bufferLength); 237 memcpy(cursor->Bits(), buffer, bufferLength); 238 239 *_cursor = cursor; 240 return B_OK; 241 } 242 return B_ERROR; 243 } 244 245 246 /*! 247 \brief Returns the name of the set 248 \return The name of the set 249 */ 250 const char * 251 CursorSet::GetName(void) 252 { 253 const char *name; 254 if (FindString("name", &name) == B_OK) 255 return name; 256 257 return NULL; 258 } 259 260 261 /*! 262 \brief Renames the cursor set 263 \param name new name of the set. 264 265 This function will fail if given a NULL name 266 */ 267 void 268 CursorSet::SetName(const char *name) 269 { 270 if (!name) 271 return; 272 273 RemoveData("name"); 274 AddString("name", name); 275 } 276 277 278 /*! 279 \brief Returns a string for the specified cursor attribute 280 \param which System cursor specifier defined in CursorSet.h 281 \return Name for the cursor specifier 282 */ 283 const char * 284 CursorSet::_CursorWhichToString(cursor_which which) 285 { 286 switch (which) { 287 case B_CURSOR_DEFAULT: 288 return "Default"; 289 case B_CURSOR_TEXT: 290 return "Text"; 291 case B_CURSOR_MOVE: 292 return "Move"; 293 case B_CURSOR_DRAG: 294 return "Drag"; 295 case B_CURSOR_RESIZE: 296 return "Resize"; 297 case B_CURSOR_RESIZE_NWSE: 298 return "Resize NWSE"; 299 case B_CURSOR_RESIZE_NESW: 300 return "Resize NESW"; 301 case B_CURSOR_RESIZE_NS: 302 return "Resize NS"; 303 case B_CURSOR_RESIZE_EW: 304 return "Resize EW"; 305 case B_CURSOR_OTHER: 306 return "Other"; 307 default: 308 return "Invalid"; 309 } 310 } 311 312 /*! 313 \brief Creates a new BBitmap from R5 cursor data 314 \param data Pointer to data in the R5 cursor data format 315 \return NULL if data was NULL, otherwise a new BBitmap 316 317 BBitmaps returned by this function are always in the RGBA32 color space 318 */ 319 BBitmap * 320 CursorSet::_CursorDataToBitmap(uint8 *data) 321 { 322 // 68-byte array used in R5 for holding cursors. 323 // This API has serious problems and should be deprecated(but supported) in R2 324 325 // Now that we have all the setup, we're going to map (for now) the cursor 326 // to RGBA32. Eventually, there will be support for 16 and 8-bit depths 327 if (data) { 328 BBitmap *bmp = new BBitmap(BRect(0,0,15,15),B_RGBA32,0); 329 uint32 black = 0xFF000000, white=0xFFFFFFFF, *bmppos; 330 uint16 *cursorpos, *maskpos, cursorflip, maskflip; 331 uint16 cursorval, maskval, powval; 332 uint8 i, j, *_buffer; 333 334 _buffer=(uint8*)bmp->Bits(); 335 cursorpos=(uint16*)(data+4); 336 maskpos=(uint16*)(data+36); 337 338 // for each row in the cursor data 339 for (j = 0; j < 16; j++) { 340 bmppos = (uint32*)(_buffer+ (j*bmp->BytesPerRow()) ); 341 342 // On intel, our bytes end up swapped, so we must swap them back 343 cursorflip = (cursorpos[j] & 0xFF) << 8; 344 cursorflip |= (cursorpos[j] & 0xFF00) >> 8; 345 346 maskflip = (maskpos[j] & 0xFF) << 8; 347 maskflip |= (maskpos[j] & 0xFF00) >> 8; 348 349 // for each column in each row of cursor data 350 for (i = 0; i < 16; i++) { 351 // Get the values and dump them to the bitmap 352 powval = 1 << (15-i); 353 cursorval = cursorflip & powval; 354 maskval = maskflip & powval; 355 bmppos[i] = (cursorval != 0 ? black : white) 356 & (maskval > 0 ? 0xFFFFFFFF : 0x00FFFFFF); 357 } 358 } 359 return bmp; 360 } 361 362 return NULL; 363 } 364