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