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 /** Handles the system's cursor infrastructure */ 10 11 #include "CursorManager.h" 12 13 #include "CursorData.h" 14 #include "HaikuSystemCursor.h" 15 #include "ServerCursor.h" 16 #include "ServerConfig.h" 17 #include "ServerTokenSpace.h" 18 19 #include <Autolock.h> 20 #include <Directory.h> 21 #include <String.h> 22 23 #include <new> 24 #include <stdio.h> 25 26 27 CursorManager::CursorManager() 28 : BLocker("CursorManager") 29 { 30 // Set system cursors to "unassigned" 31 // ToDo: decide about default cursor 32 33 #if 1 34 fDefaultCursor = new ServerCursor(kHaikuCursorBits, kHaikuCursorWidth, 35 kHaikuCursorHeight, kHaikuCursorFormat); 36 // we just happen to know where the hotspot is 37 fDefaultCursor->SetHotSpot(BPoint(1, 0)); 38 #else 39 fDefaultCursor = new ServerCursor(default_cursor_data); 40 #endif 41 AddCursor(fDefaultCursor, B_CURSOR_DEFAULT); 42 43 fTextCursor = new ServerCursor(default_text_data); 44 AddCursor(fTextCursor, B_CURSOR_TEXT); 45 46 fMoveCursor = new ServerCursor(default_move_data); 47 AddCursor(fMoveCursor); 48 49 fDragCursor = new ServerCursor(default_drag_data); 50 AddCursor(fDragCursor); 51 52 fResizeCursor = new ServerCursor(default_resize_data); 53 AddCursor(fResizeCursor); 54 55 fNWSECursor = new ServerCursor(default_resize_nwse_data); 56 AddCursor(fNWSECursor); 57 58 fNESWCursor = new ServerCursor(default_resize_nesw_data); 59 AddCursor(fNESWCursor); 60 61 fNSCursor = new ServerCursor(default_resize_ns_data); 62 AddCursor(fNSCursor); 63 64 fEWCursor = new ServerCursor(default_resize_ew_data); 65 AddCursor(fEWCursor); 66 } 67 68 69 //! Does all the teardown 70 CursorManager::~CursorManager() 71 { 72 for (int32 i = 0; i < fCursorList.CountItems(); i++) { 73 delete (ServerCursor*)fCursorList.ItemAtFast(i); 74 } 75 } 76 77 ServerCursor* 78 CursorManager::CreateCursor(team_id clientTeam, const uint8* cursorData) 79 { 80 if (!Lock()) 81 return NULL; 82 83 ServerCursor* cursor = _FindCursor(clientTeam, cursorData); 84 85 if (!cursor) { 86 cursor = new (std::nothrow) ServerCursor(cursorData); 87 if (cursor) { 88 cursor->SetOwningTeam(clientTeam); 89 if (AddCursor(cursor) < B_OK) { 90 delete cursor; 91 cursor = NULL; 92 } 93 } 94 } else { 95 cursor->Acquire(); 96 } 97 98 Unlock(); 99 100 return cursor; 101 } 102 103 104 /*! 105 \brief Registers a cursor with the manager. 106 \param cursor ServerCursor object to register 107 \return The token assigned to the cursor or B_ERROR if cursor is NULL 108 */ 109 int32 110 CursorManager::AddCursor(ServerCursor* cursor, int32 token) 111 { 112 if (!cursor || !Lock()) 113 return B_ERROR; 114 115 if (!fCursorList.AddItem(cursor)) { 116 Unlock(); 117 return B_ERROR; 118 } 119 120 if (token == -1) { 121 token = fTokenSpace.NewToken(kCursorToken, cursor); 122 } else { 123 fTokenSpace.SetToken(token, kCursorToken, cursor); 124 } 125 126 cursor->fToken = token; 127 cursor->AttachedToManager(this); 128 129 Unlock(); 130 131 return token; 132 } 133 134 135 /*! 136 \brief Removes a cursor if it's not referenced anymore. 137 138 If this was the last reference to this cursor, it will be deleted. 139 Only if the cursor is deleted, \c true is returned. 140 */ 141 bool 142 CursorManager::RemoveCursor(ServerCursor* cursor) 143 { 144 if (!Lock()) 145 return false; 146 147 // TODO: this doesn't work as it looks like, and it's not safe! 148 if (cursor->ReferenceCount() > 0) { 149 // cursor has been referenced again in the mean time 150 Unlock(); 151 return false; 152 } 153 154 _RemoveCursor(cursor); 155 156 Unlock(); 157 return true; 158 } 159 160 161 /*! 162 \brief Removes and deletes all of an application's cursors 163 \param signature Signature to which the cursors belong 164 */ 165 void 166 CursorManager::DeleteCursors(team_id team) 167 { 168 if (!Lock()) 169 return; 170 171 for (int32 index = fCursorList.CountItems(); index-- > 0;) { 172 ServerCursor *cursor = (ServerCursor*)fCursorList.ItemAtFast(index); 173 if (cursor->OwningTeam() == team) 174 cursor->Release(); 175 } 176 177 Unlock(); 178 } 179 180 181 /*! 182 \brief Sets all the cursors from a specified CursorSet 183 \param path Path to the cursor set 184 185 All cursors in the set will be assigned. If the set does not specify a 186 cursor for a particular cursor specifier, it will remain unchanged. 187 This function will fail if passed a NULL path, an invalid path, or the 188 path to a non-CursorSet file. 189 */ 190 void 191 CursorManager::SetCursorSet(const char *path) 192 { 193 BAutolock locker (this); 194 195 CursorSet cursorSet(NULL); 196 197 if (!path || cursorSet.Load(path) != B_OK) 198 return; 199 200 ServerCursor *cursor = NULL; 201 202 if (cursorSet.FindCursor(B_CURSOR_DEFAULT, &cursor) == B_OK) { 203 if (fDefaultCursor) 204 delete fDefaultCursor; 205 fDefaultCursor = cursor; 206 } 207 208 if (cursorSet.FindCursor(B_CURSOR_TEXT, &cursor) == B_OK) { 209 if (fTextCursor) 210 delete fTextCursor; 211 fTextCursor = cursor; 212 } 213 214 if (cursorSet.FindCursor(B_CURSOR_MOVE, &cursor) == B_OK) { 215 if (fMoveCursor) 216 delete fMoveCursor; 217 fMoveCursor = cursor; 218 } 219 220 if (cursorSet.FindCursor(B_CURSOR_DRAG, &cursor) == B_OK) { 221 if (fDragCursor) 222 delete fDragCursor; 223 fDragCursor = cursor; 224 } 225 226 if (cursorSet.FindCursor(B_CURSOR_RESIZE, &cursor) == B_OK) { 227 if (fResizeCursor) 228 delete fResizeCursor; 229 fResizeCursor = cursor; 230 } 231 232 if (cursorSet.FindCursor(B_CURSOR_RESIZE_NWSE, &cursor) == B_OK) { 233 if (fNWSECursor) 234 delete fNWSECursor; 235 fNWSECursor = cursor; 236 } 237 238 if (cursorSet.FindCursor(B_CURSOR_RESIZE_NESW, &cursor) == B_OK) { 239 if (fNESWCursor) 240 delete fNESWCursor; 241 fNESWCursor = cursor; 242 } 243 244 if (cursorSet.FindCursor(B_CURSOR_RESIZE_NS, &cursor) == B_OK) { 245 if (fNSCursor) 246 delete fNSCursor; 247 fNSCursor = cursor; 248 } 249 250 if (cursorSet.FindCursor(B_CURSOR_RESIZE_EW, &cursor) == B_OK) { 251 if (fEWCursor) 252 delete fEWCursor; 253 fEWCursor = cursor; 254 } 255 } 256 257 258 /*! 259 \brief Acquire the cursor which is used for a particular system cursor 260 \param which Which system cursor to get 261 \return Pointer to the particular cursor used or NULL if which is 262 invalid or the cursor has not been assigned 263 */ 264 ServerCursor * 265 CursorManager::GetCursor(cursor_which which) 266 { 267 BAutolock locker(this); 268 269 switch (which) { 270 case B_CURSOR_DEFAULT: 271 return fDefaultCursor; 272 case B_CURSOR_TEXT: 273 return fTextCursor; 274 case B_CURSOR_MOVE: 275 return fMoveCursor; 276 case B_CURSOR_DRAG: 277 return fDragCursor; 278 case B_CURSOR_RESIZE: 279 return fResizeCursor; 280 case B_CURSOR_RESIZE_NWSE: 281 return fNWSECursor; 282 case B_CURSOR_RESIZE_NESW: 283 return fNESWCursor; 284 case B_CURSOR_RESIZE_NS: 285 return fNSCursor; 286 case B_CURSOR_RESIZE_EW: 287 return fEWCursor; 288 289 default: 290 return NULL; 291 } 292 } 293 294 295 /*! 296 \brief Gets the current system cursor value 297 \return The current cursor value or CURSOR_OTHER if some non-system cursor 298 */ 299 cursor_which 300 CursorManager::GetCursorWhich() 301 { 302 Lock(); 303 304 // ToDo: Where is fCurrentWhich set? 305 cursor_which which; 306 which = fCurrentWhich; 307 308 Unlock(); 309 return which; 310 } 311 312 313 /*! 314 \brief Sets the specified system cursor to the a particular cursor 315 \param which Which system cursor to change 316 \param token The ID of the cursor to become the new one 317 318 A word of warning: once a cursor has been assigned to the system, the 319 system will take ownership of the cursor and deleting the cursor 320 will have no effect on the system. 321 */ 322 void 323 CursorManager::ChangeCursor(cursor_which which, int32 token) 324 { 325 Lock(); 326 327 // Find the cursor, based on the token 328 ServerCursor *cursor = FindCursor(token); 329 330 // Did we find a cursor with this token? 331 if (!cursor) { 332 Unlock(); 333 return; 334 } 335 336 // Do the assignment 337 switch (which) { 338 case B_CURSOR_DEFAULT: 339 delete fDefaultCursor; 340 fDefaultCursor = cursor; 341 break; 342 343 case B_CURSOR_TEXT: 344 delete fTextCursor; 345 fTextCursor = cursor; 346 break; 347 348 case B_CURSOR_MOVE: 349 delete fMoveCursor; 350 fMoveCursor = cursor; 351 break; 352 353 case B_CURSOR_DRAG: 354 delete fDragCursor; 355 fDragCursor = cursor; 356 break; 357 358 case B_CURSOR_RESIZE: 359 delete fResizeCursor; 360 fResizeCursor = cursor; 361 break; 362 363 case B_CURSOR_RESIZE_NWSE: 364 delete fNWSECursor; 365 fNWSECursor = cursor; 366 break; 367 368 case B_CURSOR_RESIZE_NESW: 369 delete fNESWCursor; 370 fNESWCursor = cursor; 371 break; 372 373 case B_CURSOR_RESIZE_NS: 374 delete fNSCursor; 375 fNSCursor = cursor; 376 break; 377 378 case B_CURSOR_RESIZE_EW: 379 delete fEWCursor; 380 fEWCursor = cursor; 381 break; 382 383 default: 384 Unlock(); 385 return; 386 } 387 388 fCursorList.RemoveItem(cursor); 389 Unlock(); 390 } 391 392 393 //! Sets the cursors to the defaults and saves them to CURSOR_SETTINGS_DIR/"d 394 void 395 CursorManager::SetDefaults() 396 { 397 Lock(); 398 CursorSet cursorSet("Default"); 399 cursorSet.AddCursor(B_CURSOR_DEFAULT, default_cursor_data); 400 cursorSet.AddCursor(B_CURSOR_TEXT, default_text_data); 401 cursorSet.AddCursor(B_CURSOR_MOVE, default_move_data); 402 cursorSet.AddCursor(B_CURSOR_DRAG, default_drag_data); 403 cursorSet.AddCursor(B_CURSOR_RESIZE, default_resize_data); 404 cursorSet.AddCursor(B_CURSOR_RESIZE_NWSE, default_resize_nwse_data); 405 cursorSet.AddCursor(B_CURSOR_RESIZE_NESW, default_resize_nesw_data); 406 cursorSet.AddCursor(B_CURSOR_RESIZE_NS, default_resize_ns_data); 407 cursorSet.AddCursor(B_CURSOR_RESIZE_EW, default_resize_ew_data); 408 #if 0 409 BDirectory dir; 410 if (dir.SetTo(CURSOR_SET_DIR) == B_ENTRY_NOT_FOUND) 411 create_directory(CURSOR_SET_DIR, 0777); 412 413 BString string(CURSOR_SET_DIR); 414 string += "Default"; 415 cursorSet.Save(string.String(), B_CREATE_FILE | B_FAIL_IF_EXISTS); 416 417 SetCursorSet(string.String()); 418 #endif 419 Unlock(); 420 } 421 422 423 /*! 424 \brief Internal function which finds the cursor with a particular ID 425 \param token ID of the cursor to find 426 \return The cursor or NULL if not found 427 */ 428 ServerCursor * 429 CursorManager::FindCursor(int32 token) 430 { 431 if (!Lock()) 432 return NULL; 433 434 ServerCursor* cursor; 435 if (fTokenSpace.GetToken(token, kCursorToken, (void**)&cursor) != B_OK) 436 cursor = NULL; 437 438 Unlock(); 439 440 return cursor; 441 } 442 443 444 ServerCursor * 445 CursorManager::_FindCursor(team_id clientTeam, const uint8* cursorData) 446 { 447 int32 count = fCursorList.CountItems(); 448 for (int32 i = 0; i < count; i++) { 449 ServerCursor* cursor = (ServerCursor*)fCursorList.ItemAtFast(i); 450 if (cursor->OwningTeam() == clientTeam 451 && cursor->CursorData() 452 && memcmp(cursor->CursorData(), cursorData, 68) == 0) { 453 //printf("found already existing cursor\n"); 454 return cursor; 455 } 456 } 457 return NULL; 458 } 459 460 461 void 462 CursorManager::_RemoveCursor(ServerCursor* cursor) 463 { 464 fCursorList.RemoveItem(cursor); 465 fTokenSpace.RemoveToken(cursor->fToken); 466 } 467 468 469 //ServerCursor* 470 //CursorManager::_RemoveCursor(int32 index) 471 //{ 472 // ServerCursor* cursor = (ServerCursor*)fCursorList.RemoveItem(index); 473 // if (cursor != NULL) 474 // fTokenSpace.RemoveToken(cursor->fToken); 475 // 476 // return cursor; 477 //} 478 479 480