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 Releases a reference to a cursor 137 138 If this was the last reference to this cursor, it will be deleted. 139 */ 140 void 141 CursorManager::RemoveCursor(ServerCursor* cursor) 142 { 143 if (!Lock()) 144 return; 145 146 _RemoveCursor(cursor); 147 148 Unlock(); 149 } 150 151 152 /*! 153 \brief Removes and deletes all of an application's cursors 154 \param signature Signature to which the cursors belong 155 */ 156 void 157 CursorManager::DeleteCursors(team_id team) 158 { 159 if (!Lock()) 160 return; 161 162 for (int32 index = fCursorList.CountItems(); index-- > 0;) { 163 ServerCursor *cursor = (ServerCursor*)fCursorList.ItemAtFast(index); 164 if (cursor->OwningTeam() == team) 165 cursor->Release(); 166 } 167 168 Unlock(); 169 } 170 171 172 /*! 173 \brief Sets all the cursors from a specified CursorSet 174 \param path Path to the cursor set 175 176 All cursors in the set will be assigned. If the set does not specify a 177 cursor for a particular cursor specifier, it will remain unchanged. 178 This function will fail if passed a NULL path, an invalid path, or the 179 path to a non-CursorSet file. 180 */ 181 void 182 CursorManager::SetCursorSet(const char *path) 183 { 184 BAutolock locker (this); 185 186 CursorSet cursorSet(NULL); 187 188 if (!path || cursorSet.Load(path) != B_OK) 189 return; 190 191 ServerCursor *cursor = NULL; 192 193 if (cursorSet.FindCursor(B_CURSOR_DEFAULT, &cursor) == B_OK) { 194 if (fDefaultCursor) 195 delete fDefaultCursor; 196 fDefaultCursor = cursor; 197 } 198 199 if (cursorSet.FindCursor(B_CURSOR_TEXT, &cursor) == B_OK) { 200 if (fTextCursor) 201 delete fTextCursor; 202 fTextCursor = cursor; 203 } 204 205 if (cursorSet.FindCursor(B_CURSOR_MOVE, &cursor) == B_OK) { 206 if (fMoveCursor) 207 delete fMoveCursor; 208 fMoveCursor = cursor; 209 } 210 211 if (cursorSet.FindCursor(B_CURSOR_DRAG, &cursor) == B_OK) { 212 if (fDragCursor) 213 delete fDragCursor; 214 fDragCursor = cursor; 215 } 216 217 if (cursorSet.FindCursor(B_CURSOR_RESIZE, &cursor) == B_OK) { 218 if (fResizeCursor) 219 delete fResizeCursor; 220 fResizeCursor = cursor; 221 } 222 223 if (cursorSet.FindCursor(B_CURSOR_RESIZE_NWSE, &cursor) == B_OK) { 224 if (fNWSECursor) 225 delete fNWSECursor; 226 fNWSECursor = cursor; 227 } 228 229 if (cursorSet.FindCursor(B_CURSOR_RESIZE_NESW, &cursor) == B_OK) { 230 if (fNESWCursor) 231 delete fNESWCursor; 232 fNESWCursor = cursor; 233 } 234 235 if (cursorSet.FindCursor(B_CURSOR_RESIZE_NS, &cursor) == B_OK) { 236 if (fNSCursor) 237 delete fNSCursor; 238 fNSCursor = cursor; 239 } 240 241 if (cursorSet.FindCursor(B_CURSOR_RESIZE_EW, &cursor) == B_OK) { 242 if (fEWCursor) 243 delete fEWCursor; 244 fEWCursor = cursor; 245 } 246 } 247 248 249 /*! 250 \brief Acquire the cursor which is used for a particular system cursor 251 \param which Which system cursor to get 252 \return Pointer to the particular cursor used or NULL if which is 253 invalid or the cursor has not been assigned 254 */ 255 ServerCursor * 256 CursorManager::GetCursor(cursor_which which) 257 { 258 BAutolock locker(this); 259 260 switch (which) { 261 case B_CURSOR_DEFAULT: 262 return fDefaultCursor; 263 case B_CURSOR_TEXT: 264 return fTextCursor; 265 case B_CURSOR_MOVE: 266 return fMoveCursor; 267 case B_CURSOR_DRAG: 268 return fDragCursor; 269 case B_CURSOR_RESIZE: 270 return fResizeCursor; 271 case B_CURSOR_RESIZE_NWSE: 272 return fNWSECursor; 273 case B_CURSOR_RESIZE_NESW: 274 return fNESWCursor; 275 case B_CURSOR_RESIZE_NS: 276 return fNSCursor; 277 case B_CURSOR_RESIZE_EW: 278 return fEWCursor; 279 280 default: 281 return NULL; 282 } 283 } 284 285 286 /*! 287 \brief Gets the current system cursor value 288 \return The current cursor value or CURSOR_OTHER if some non-system cursor 289 */ 290 cursor_which 291 CursorManager::GetCursorWhich() 292 { 293 Lock(); 294 295 // ToDo: Where is fCurrentWhich set? 296 cursor_which which; 297 which = fCurrentWhich; 298 299 Unlock(); 300 return which; 301 } 302 303 304 /*! 305 \brief Sets the specified system cursor to the a particular cursor 306 \param which Which system cursor to change 307 \param token The ID of the cursor to become the new one 308 309 A word of warning: once a cursor has been assigned to the system, the 310 system will take ownership of the cursor and deleting the cursor 311 will have no effect on the system. 312 */ 313 void 314 CursorManager::ChangeCursor(cursor_which which, int32 token) 315 { 316 Lock(); 317 318 // Find the cursor, based on the token 319 ServerCursor *cursor = FindCursor(token); 320 321 // Did we find a cursor with this token? 322 if (!cursor) { 323 Unlock(); 324 return; 325 } 326 327 // Do the assignment 328 switch (which) { 329 case B_CURSOR_DEFAULT: 330 delete fDefaultCursor; 331 fDefaultCursor = cursor; 332 break; 333 334 case B_CURSOR_TEXT: 335 delete fTextCursor; 336 fTextCursor = cursor; 337 break; 338 339 case B_CURSOR_MOVE: 340 delete fMoveCursor; 341 fMoveCursor = cursor; 342 break; 343 344 case B_CURSOR_DRAG: 345 delete fDragCursor; 346 fDragCursor = cursor; 347 break; 348 349 case B_CURSOR_RESIZE: 350 delete fResizeCursor; 351 fResizeCursor = cursor; 352 break; 353 354 case B_CURSOR_RESIZE_NWSE: 355 delete fNWSECursor; 356 fNWSECursor = cursor; 357 break; 358 359 case B_CURSOR_RESIZE_NESW: 360 delete fNESWCursor; 361 fNESWCursor = cursor; 362 break; 363 364 case B_CURSOR_RESIZE_NS: 365 delete fNSCursor; 366 fNSCursor = cursor; 367 break; 368 369 case B_CURSOR_RESIZE_EW: 370 delete fEWCursor; 371 fEWCursor = cursor; 372 break; 373 374 default: 375 Unlock(); 376 return; 377 } 378 379 fCursorList.RemoveItem(cursor); 380 Unlock(); 381 } 382 383 384 //! Sets the cursors to the defaults and saves them to CURSOR_SETTINGS_DIR/"d 385 void 386 CursorManager::SetDefaults() 387 { 388 Lock(); 389 CursorSet cursorSet("Default"); 390 cursorSet.AddCursor(B_CURSOR_DEFAULT, default_cursor_data); 391 cursorSet.AddCursor(B_CURSOR_TEXT, default_text_data); 392 cursorSet.AddCursor(B_CURSOR_MOVE, default_move_data); 393 cursorSet.AddCursor(B_CURSOR_DRAG, default_drag_data); 394 cursorSet.AddCursor(B_CURSOR_RESIZE, default_resize_data); 395 cursorSet.AddCursor(B_CURSOR_RESIZE_NWSE, default_resize_nwse_data); 396 cursorSet.AddCursor(B_CURSOR_RESIZE_NESW, default_resize_nesw_data); 397 cursorSet.AddCursor(B_CURSOR_RESIZE_NS, default_resize_ns_data); 398 cursorSet.AddCursor(B_CURSOR_RESIZE_EW, default_resize_ew_data); 399 #if 0 400 BDirectory dir; 401 if (dir.SetTo(CURSOR_SET_DIR) == B_ENTRY_NOT_FOUND) 402 create_directory(CURSOR_SET_DIR, 0777); 403 404 BString string(CURSOR_SET_DIR); 405 string += "Default"; 406 cursorSet.Save(string.String(), B_CREATE_FILE | B_FAIL_IF_EXISTS); 407 408 SetCursorSet(string.String()); 409 #endif 410 Unlock(); 411 } 412 413 414 /*! 415 \brief Internal function which finds the cursor with a particular ID 416 \param token ID of the cursor to find 417 \return The cursor or NULL if not found 418 */ 419 ServerCursor * 420 CursorManager::FindCursor(int32 token) 421 { 422 if (!Lock()) 423 return NULL; 424 425 ServerCursor* cursor; 426 if (fTokenSpace.GetToken(token, kCursorToken, (void**)&cursor) != B_OK) 427 cursor = NULL; 428 429 Unlock(); 430 431 return cursor; 432 } 433 434 435 ServerCursor * 436 CursorManager::_FindCursor(team_id clientTeam, const uint8* cursorData) 437 { 438 int32 count = fCursorList.CountItems(); 439 for (int32 i = 0; i < count; i++) { 440 ServerCursor* cursor = (ServerCursor*)fCursorList.ItemAtFast(i); 441 if (cursor->OwningTeam() == clientTeam 442 && cursor->CursorData() 443 && memcmp(cursor->CursorData(), cursorData, 68) == 0) { 444 //printf("found already existing cursor\n"); 445 return cursor; 446 } 447 } 448 return NULL; 449 } 450 451 452 void 453 CursorManager::_RemoveCursor(ServerCursor* cursor) 454 { 455 fCursorList.RemoveItem(cursor); 456 fTokenSpace.RemoveToken(cursor->fToken); 457 } 458 459 460 //ServerCursor* 461 //CursorManager::_RemoveCursor(int32 index) 462 //{ 463 // ServerCursor* cursor = (ServerCursor*)fCursorList.RemoveItem(index); 464 // if (cursor != NULL) 465 // fTokenSpace.RemoveToken(cursor->fToken); 466 // 467 // return cursor; 468 //} 469 470 471