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(BCursorID 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(BCursorID 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(BCursorID 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(BCursorID 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(BCursorID which, ServerCursor **_cursor) const 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(BCursorID which) const 285 { 286 switch (which) { 287 case B_CURSOR_ID_SYSTEM_DEFAULT: 288 return "System default"; 289 case B_CURSOR_ID_CONTEXT_MENU: 290 return "Context menu"; 291 case B_CURSOR_ID_COPY: 292 return "Copy"; 293 case B_CURSOR_ID_CROSS_HAIR: 294 return "Cross hair"; 295 case B_CURSOR_ID_NO_CURSOR: 296 return "No cursor"; 297 case B_CURSOR_ID_FOLLOW_LINK: 298 return "Follow link"; 299 case B_CURSOR_ID_GRAB: 300 return "Grab"; 301 case B_CURSOR_ID_GRABBING: 302 return "Grabbing"; 303 case B_CURSOR_ID_HELP: 304 return "Help"; 305 case B_CURSOR_ID_I_BEAM: 306 return "I-beam"; 307 case B_CURSOR_ID_I_BEAM_HORIZONTAL: 308 return "I-beam horizontal"; 309 case B_CURSOR_ID_MOVE: 310 return "Move"; 311 case B_CURSOR_ID_NOT_ALLOWED: 312 return "Not allowed"; 313 case B_CURSOR_ID_PROGRESS: 314 return "Progress"; 315 case B_CURSOR_ID_RESIZE_NORTH: 316 return "Resize North"; 317 case B_CURSOR_ID_RESIZE_EAST: 318 return "Resize East"; 319 case B_CURSOR_ID_RESIZE_SOUTH: 320 return "Resize South"; 321 case B_CURSOR_ID_RESIZE_WEST: 322 return "Resize West"; 323 case B_CURSOR_ID_RESIZE_NORTH_EAST: 324 return "Resize North East"; 325 case B_CURSOR_ID_RESIZE_NORTH_WEST: 326 return "Resize North West"; 327 case B_CURSOR_ID_RESIZE_SOUTH_EAST: 328 return "Resize South East"; 329 case B_CURSOR_ID_RESIZE_SOUTH_WEST: 330 return "Resize South West"; 331 case B_CURSOR_ID_RESIZE_NORTH_SOUTH: 332 return "Resize North South"; 333 case B_CURSOR_ID_RESIZE_EAST_WEST: 334 return "Resize East West"; 335 case B_CURSOR_ID_RESIZE_NORTH_EAST_SOUTH_WEST: 336 return "Resize North East South West"; 337 case B_CURSOR_ID_RESIZE_NORTH_WEST_SOUTH_EAST: 338 return "Resize North West South East"; 339 case B_CURSOR_ID_ZOOM_IN: 340 return "Zoom in"; 341 case B_CURSOR_ID_ZOOM_OUT: 342 return "Zoom out"; 343 default: 344 return "Invalid"; 345 } 346 } 347 348 /*! 349 \brief Creates a new BBitmap from R5 cursor data 350 \param data Pointer to data in the R5 cursor data format 351 \return NULL if data was NULL, otherwise a new BBitmap 352 353 BBitmaps returned by this function are always in the RGBA32 color space 354 */ 355 BBitmap * 356 CursorSet::_CursorDataToBitmap(uint8 *data) 357 { 358 // 68-byte array used in R5 for holding cursors. 359 // This API has serious problems and should be deprecated(but supported) in R2 360 361 // Now that we have all the setup, we're going to map (for now) the cursor 362 // to RGBA32. Eventually, there will be support for 16 and 8-bit depths 363 if (data) { 364 BBitmap *bmp = new BBitmap(BRect(0,0,15,15),B_RGBA32,0); 365 uint32 black = 0xFF000000, white=0xFFFFFFFF, *bmppos; 366 uint16 *cursorpos, *maskpos, cursorflip, maskflip; 367 uint16 cursorval, maskval, powval; 368 uint8 i, j, *_buffer; 369 370 _buffer=(uint8*)bmp->Bits(); 371 cursorpos=(uint16*)(data+4); 372 maskpos=(uint16*)(data+36); 373 374 // for each row in the cursor data 375 for (j = 0; j < 16; j++) { 376 bmppos = (uint32*)(_buffer+ (j*bmp->BytesPerRow()) ); 377 378 // On intel, our bytes end up swapped, so we must swap them back 379 cursorflip = (cursorpos[j] & 0xFF) << 8; 380 cursorflip |= (cursorpos[j] & 0xFF00) >> 8; 381 382 maskflip = (maskpos[j] & 0xFF) << 8; 383 maskflip |= (maskpos[j] & 0xFF00) >> 8; 384 385 // for each column in each row of cursor data 386 for (i = 0; i < 16; i++) { 387 // Get the values and dump them to the bitmap 388 powval = 1 << (15-i); 389 cursorval = cursorflip & powval; 390 maskval = maskflip & powval; 391 bmppos[i] = (cursorval != 0 ? black : white) 392 & (maskval > 0 ? 0xFFFFFFFF : 0x00FFFFFF); 393 } 394 } 395 return bmp; 396 } 397 398 return NULL; 399 } 400