1 /* 2 * Copyright 2001-2009, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * DarkWyrm <bpmagic@columbus.rr.com> 7 */ 8 9 10 /*! Handles the system's cursor infrastructure */ 11 12 13 #include "CursorManager.h" 14 15 #include "CursorData.h" 16 #include "ServerCursor.h" 17 #include "ServerConfig.h" 18 #include "ServerTokenSpace.h" 19 20 #include <Autolock.h> 21 #include <Directory.h> 22 #include <String.h> 23 24 #include <new> 25 #include <stdio.h> 26 27 28 CursorManager::CursorManager() 29 : 30 BLocker("CursorManager") 31 { 32 // Init system cursors 33 const BPoint kHandHotspot(1, 1); 34 const BPoint kResizeHotspot(8, 8); 35 _InitCursor(fCursorSystemDefault, kCursorSystemDefaultBits, 36 B_CURSOR_ID_SYSTEM_DEFAULT, kHandHotspot); 37 _InitCursor(fCursorContextMenu, kCursorContextMenuBits, 38 B_CURSOR_ID_CONTEXT_MENU, kHandHotspot); 39 _InitCursor(fCursorCopy, kCursorCopyBits, 40 B_CURSOR_ID_COPY, kHandHotspot); 41 _InitCursor(fCursorCreateLink, kCursorCreateLinkBits, 42 B_CURSOR_ID_CREATE_LINK, kHandHotspot); 43 _InitCursor(fCursorCrossHair, kCursorCrossHairBits, 44 B_CURSOR_ID_CROSS_HAIR, BPoint(10, 10)); 45 _InitCursor(fCursorFollowLink, kCursorFollowLinkBits, 46 B_CURSOR_ID_FOLLOW_LINK, BPoint(5, 0)); 47 _InitCursor(fCursorGrab, kCursorGrabBits, 48 B_CURSOR_ID_GRAB, kHandHotspot); 49 _InitCursor(fCursorGrabbing, kCursorGrabbingBits, 50 B_CURSOR_ID_GRABBING, kHandHotspot); 51 _InitCursor(fCursorHelp, kCursorHelpBits, 52 B_CURSOR_ID_HELP, BPoint(0, 8)); 53 _InitCursor(fCursorIBeam, kCursorIBeamBits, 54 B_CURSOR_ID_I_BEAM, BPoint(7, 9)); 55 _InitCursor(fCursorIBeamHorizontal, kCursorIBeamHorizontalBits, 56 B_CURSOR_ID_I_BEAM_HORIZONTAL, BPoint(8, 8)); 57 _InitCursor(fCursorMove, kCursorMoveBits, 58 B_CURSOR_ID_MOVE, kResizeHotspot); 59 _InitCursor(fCursorNoCursor, 0, B_CURSOR_ID_NO_CURSOR, BPoint(0, 0)); 60 _InitCursor(fCursorNotAllowed, kCursorNotAllowedBits, 61 B_CURSOR_ID_NOT_ALLOWED, BPoint(8, 8)); 62 _InitCursor(fCursorProgress, kCursorProgressBits, 63 B_CURSOR_ID_PROGRESS, BPoint(7, 10)); 64 _InitCursor(fCursorResizeEast, kCursorResizeEastBits, 65 B_CURSOR_ID_RESIZE_EAST, kResizeHotspot); 66 _InitCursor(fCursorResizeEastWest, kCursorResizeEastWestBits, 67 B_CURSOR_ID_RESIZE_EAST_WEST, kResizeHotspot); 68 _InitCursor(fCursorResizeNorth, kCursorResizeNorthBits, 69 B_CURSOR_ID_RESIZE_NORTH, kResizeHotspot); 70 _InitCursor(fCursorResizeNorthEast, kCursorResizeNorthEastBits, 71 B_CURSOR_ID_RESIZE_NORTH_EAST, kResizeHotspot); 72 _InitCursor(fCursorResizeNorthEastSouthWest, 73 kCursorResizeNorthEastSouthWestBits, 74 B_CURSOR_ID_RESIZE_NORTH_EAST_SOUTH_WEST, kResizeHotspot); 75 _InitCursor(fCursorResizeNorthSouth, kCursorResizeNorthSouthBits, 76 B_CURSOR_ID_RESIZE_NORTH_SOUTH, kResizeHotspot); 77 _InitCursor(fCursorResizeNorthWest, kCursorResizeNorthWestBits, 78 B_CURSOR_ID_RESIZE_NORTH_WEST, kResizeHotspot); 79 _InitCursor(fCursorResizeNorthWestSouthEast, 80 kCursorResizeNorthWestSouthEastBits, 81 B_CURSOR_ID_RESIZE_NORTH_WEST_SOUTH_EAST, kResizeHotspot); 82 _InitCursor(fCursorResizeSouth, kCursorResizeSouthBits, 83 B_CURSOR_ID_RESIZE_SOUTH, kResizeHotspot); 84 _InitCursor(fCursorResizeSouthEast, kCursorResizeSouthEastBits, 85 B_CURSOR_ID_RESIZE_SOUTH_EAST, kResizeHotspot); 86 _InitCursor(fCursorResizeSouthWest, kCursorResizeSouthWestBits, 87 B_CURSOR_ID_RESIZE_SOUTH_WEST, kResizeHotspot); 88 _InitCursor(fCursorResizeWest, kCursorResizeWestBits, 89 B_CURSOR_ID_RESIZE_WEST, kResizeHotspot); 90 _InitCursor(fCursorZoomIn, kCursorZoomInBits, 91 B_CURSOR_ID_ZOOM_IN, BPoint(6, 6)); 92 _InitCursor(fCursorZoomOut, kCursorZoomOutBits, 93 B_CURSOR_ID_ZOOM_OUT, BPoint(6, 6)); 94 } 95 96 97 //! Does all the teardown 98 CursorManager::~CursorManager() 99 { 100 for (int32 i = 0; i < fCursorList.CountItems(); i++) 101 delete (ServerCursor*)fCursorList.ItemAtFast(i); 102 } 103 104 105 ServerCursor* 106 CursorManager::CreateCursor(team_id clientTeam, const uint8* cursorData) 107 { 108 if (!Lock()) 109 return NULL; 110 111 ServerCursor* cursor = _FindCursor(clientTeam, cursorData); 112 113 if (!cursor) { 114 cursor = new (std::nothrow) ServerCursor(cursorData); 115 if (cursor) { 116 cursor->SetOwningTeam(clientTeam); 117 if (AddCursor(cursor) < B_OK) { 118 delete cursor; 119 cursor = NULL; 120 } 121 } 122 } else 123 cursor->AcquireReference(); 124 125 Unlock(); 126 127 return cursor; 128 } 129 130 131 /*! \brief Registers a cursor with the manager. 132 \param cursor ServerCursor object to register 133 \return The token assigned to the cursor or B_ERROR if cursor is NULL 134 */ 135 int32 136 CursorManager::AddCursor(ServerCursor* cursor, int32 token) 137 { 138 if (!cursor) 139 return B_BAD_VALUE; 140 if (!Lock()) 141 return B_ERROR; 142 143 if (!fCursorList.AddItem(cursor)) { 144 Unlock(); 145 return B_NO_MEMORY; 146 } 147 148 if (token == -1) 149 token = fTokenSpace.NewToken(kCursorToken, cursor); 150 else 151 fTokenSpace.SetToken(token, kCursorToken, cursor); 152 153 cursor->fToken = token; 154 cursor->AttachedToManager(this); 155 156 Unlock(); 157 158 return token; 159 } 160 161 162 /*! \brief Removes a cursor if it's not referenced anymore. 163 164 If this was the last reference to this cursor, it will be deleted. 165 Only if the cursor is deleted, \c true is returned. 166 */ 167 bool 168 CursorManager::RemoveCursor(ServerCursor* cursor) 169 { 170 if (!Lock()) 171 return false; 172 173 // TODO: this doesn't work as it looks like, and it's not safe! 174 if (cursor->CountReferences() > 0) { 175 // cursor has been referenced again in the mean time 176 Unlock(); 177 return false; 178 } 179 180 _RemoveCursor(cursor); 181 182 Unlock(); 183 return true; 184 } 185 186 187 /*! \brief Removes and deletes all of an application's cursors 188 \param signature Signature to which the cursors belong 189 */ 190 void 191 CursorManager::DeleteCursors(team_id team) 192 { 193 if (!Lock()) 194 return; 195 196 for (int32 index = fCursorList.CountItems(); index-- > 0;) { 197 ServerCursor* cursor = (ServerCursor*)fCursorList.ItemAtFast(index); 198 if (cursor->OwningTeam() == team) 199 cursor->ReleaseReference(); 200 } 201 202 Unlock(); 203 } 204 205 206 /*! \brief Sets all the cursors from a specified CursorSet 207 \param path Path to the cursor set 208 209 All cursors in the set will be assigned. If the set does not specify a 210 cursor for a particular cursor specifier, it will remain unchanged. 211 This function will fail if passed a NULL path, an invalid path, or the 212 path to a non-CursorSet file. 213 */ 214 void 215 CursorManager::SetCursorSet(const char* path) 216 { 217 BAutolock locker (this); 218 219 CursorSet cursorSet(NULL); 220 221 if (!path || cursorSet.Load(path) != B_OK) 222 return; 223 224 _LoadCursor(fCursorSystemDefault, cursorSet, B_CURSOR_ID_SYSTEM_DEFAULT); 225 _LoadCursor(fCursorContextMenu, cursorSet, B_CURSOR_ID_CONTEXT_MENU); 226 _LoadCursor(fCursorCopy, cursorSet, B_CURSOR_ID_COPY); 227 _LoadCursor(fCursorCreateLink, cursorSet, B_CURSOR_ID_CREATE_LINK); 228 _LoadCursor(fCursorCrossHair, cursorSet, B_CURSOR_ID_CROSS_HAIR); 229 _LoadCursor(fCursorFollowLink, cursorSet, B_CURSOR_ID_FOLLOW_LINK); 230 _LoadCursor(fCursorGrab, cursorSet, B_CURSOR_ID_GRAB); 231 _LoadCursor(fCursorGrabbing, cursorSet, B_CURSOR_ID_GRABBING); 232 _LoadCursor(fCursorHelp, cursorSet, B_CURSOR_ID_HELP); 233 _LoadCursor(fCursorIBeam, cursorSet, B_CURSOR_ID_I_BEAM); 234 _LoadCursor(fCursorIBeamHorizontal, cursorSet, 235 B_CURSOR_ID_I_BEAM_HORIZONTAL); 236 _LoadCursor(fCursorMove, cursorSet, B_CURSOR_ID_MOVE); 237 _LoadCursor(fCursorNotAllowed, cursorSet, B_CURSOR_ID_NOT_ALLOWED); 238 _LoadCursor(fCursorProgress, cursorSet, B_CURSOR_ID_PROGRESS); 239 _LoadCursor(fCursorResizeEast, cursorSet, B_CURSOR_ID_RESIZE_EAST); 240 _LoadCursor(fCursorResizeEastWest, cursorSet, 241 B_CURSOR_ID_RESIZE_EAST_WEST); 242 _LoadCursor(fCursorResizeNorth, cursorSet, B_CURSOR_ID_RESIZE_NORTH); 243 _LoadCursor(fCursorResizeNorthEast, cursorSet, 244 B_CURSOR_ID_RESIZE_NORTH_EAST); 245 _LoadCursor(fCursorResizeNorthEastSouthWest, cursorSet, 246 B_CURSOR_ID_RESIZE_NORTH_EAST_SOUTH_WEST); 247 _LoadCursor(fCursorResizeNorthSouth, cursorSet, 248 B_CURSOR_ID_RESIZE_NORTH_SOUTH); 249 _LoadCursor(fCursorResizeNorthWest, cursorSet, 250 B_CURSOR_ID_RESIZE_NORTH_WEST); 251 _LoadCursor(fCursorResizeNorthWestSouthEast, cursorSet, 252 B_CURSOR_ID_RESIZE_NORTH_WEST_SOUTH_EAST); 253 _LoadCursor(fCursorResizeSouth, cursorSet, B_CURSOR_ID_RESIZE_SOUTH); 254 _LoadCursor(fCursorResizeSouthEast, cursorSet, 255 B_CURSOR_ID_RESIZE_SOUTH_EAST); 256 _LoadCursor(fCursorResizeSouthWest, cursorSet, 257 B_CURSOR_ID_RESIZE_SOUTH_WEST); 258 _LoadCursor(fCursorResizeWest, cursorSet, B_CURSOR_ID_RESIZE_WEST); 259 _LoadCursor(fCursorZoomIn, cursorSet, B_CURSOR_ID_ZOOM_IN); 260 _LoadCursor(fCursorZoomOut, cursorSet, B_CURSOR_ID_ZOOM_OUT); 261 } 262 263 264 /*! \brief Acquire the cursor which is used for a particular system cursor 265 \param which Which system cursor to get 266 \return Pointer to the particular cursor used or NULL if which is 267 invalid or the cursor has not been assigned 268 */ 269 ServerCursor* 270 CursorManager::GetCursor(BCursorID which) 271 { 272 BAutolock locker(this); 273 274 switch (which) { 275 case B_CURSOR_ID_SYSTEM_DEFAULT: 276 return fCursorSystemDefault; 277 case B_CURSOR_ID_CONTEXT_MENU: 278 return fCursorContextMenu; 279 case B_CURSOR_ID_COPY: 280 return fCursorCopy; 281 case B_CURSOR_ID_CREATE_LINK: 282 return fCursorCreateLink; 283 case B_CURSOR_ID_CROSS_HAIR: 284 return fCursorCrossHair; 285 case B_CURSOR_ID_FOLLOW_LINK: 286 return fCursorFollowLink; 287 case B_CURSOR_ID_GRAB: 288 return fCursorGrab; 289 case B_CURSOR_ID_GRABBING: 290 return fCursorGrabbing; 291 case B_CURSOR_ID_HELP: 292 return fCursorHelp; 293 case B_CURSOR_ID_I_BEAM: 294 return fCursorIBeam; 295 case B_CURSOR_ID_I_BEAM_HORIZONTAL: 296 return fCursorIBeamHorizontal; 297 case B_CURSOR_ID_MOVE: 298 return fCursorMove; 299 case B_CURSOR_ID_NO_CURSOR: 300 return fCursorNoCursor; 301 case B_CURSOR_ID_NOT_ALLOWED: 302 return fCursorNotAllowed; 303 case B_CURSOR_ID_PROGRESS: 304 return fCursorProgress; 305 case B_CURSOR_ID_RESIZE_EAST: 306 return fCursorResizeEast; 307 case B_CURSOR_ID_RESIZE_EAST_WEST: 308 return fCursorResizeEastWest; 309 case B_CURSOR_ID_RESIZE_NORTH: 310 return fCursorResizeNorth; 311 case B_CURSOR_ID_RESIZE_NORTH_EAST: 312 return fCursorResizeNorthEast; 313 case B_CURSOR_ID_RESIZE_NORTH_EAST_SOUTH_WEST: 314 return fCursorResizeNorthEastSouthWest; 315 case B_CURSOR_ID_RESIZE_NORTH_SOUTH: 316 return fCursorResizeNorthSouth; 317 case B_CURSOR_ID_RESIZE_NORTH_WEST: 318 return fCursorResizeNorthWest; 319 case B_CURSOR_ID_RESIZE_NORTH_WEST_SOUTH_EAST: 320 return fCursorResizeNorthWestSouthEast; 321 case B_CURSOR_ID_RESIZE_SOUTH: 322 return fCursorResizeSouth; 323 case B_CURSOR_ID_RESIZE_SOUTH_EAST: 324 return fCursorResizeSouthEast; 325 case B_CURSOR_ID_RESIZE_SOUTH_WEST: 326 return fCursorResizeSouthWest; 327 case B_CURSOR_ID_RESIZE_WEST: 328 return fCursorResizeWest; 329 case B_CURSOR_ID_ZOOM_IN: 330 return fCursorZoomIn; 331 case B_CURSOR_ID_ZOOM_OUT: 332 return fCursorZoomOut; 333 334 default: 335 return NULL; 336 } 337 } 338 339 340 /*! \brief Internal function which finds the cursor with a particular ID 341 \param token ID of the cursor to find 342 \return The cursor or NULL if not found 343 */ 344 ServerCursor * 345 CursorManager::FindCursor(int32 token) 346 { 347 if (!Lock()) 348 return NULL; 349 350 ServerCursor* cursor; 351 if (fTokenSpace.GetToken(token, kCursorToken, (void**)&cursor) != B_OK) 352 cursor = NULL; 353 354 Unlock(); 355 356 return cursor; 357 } 358 359 360 void 361 CursorManager::_InitCursor(ServerCursor*& cursorMember, 362 const uint8* cursorBits, BCursorID id, const BPoint& hotSpot) 363 { 364 if (cursorBits) { 365 cursorMember = new ServerCursor(cursorBits, kCursorWidth, 366 kCursorHeight, kCursorFormat); 367 } else 368 cursorMember = new ServerCursor(kCursorNoCursor, 1, 1, kCursorFormat); 369 370 cursorMember->SetHotSpot(hotSpot); 371 AddCursor(cursorMember, id); 372 } 373 374 375 void 376 CursorManager::_LoadCursor(ServerCursor*& cursorMember, const CursorSet& set, 377 BCursorID id) 378 { 379 ServerCursor* cursor; 380 if (set.FindCursor(id, &cursor) == B_OK) { 381 int32 index = fCursorList.IndexOf(cursorMember); 382 if (index >= 0) { 383 ServerCursor* items = reinterpret_cast<ServerCursor*>( 384 fCursorList.Items()); 385 items[index] = cursor; 386 } 387 delete cursorMember; 388 cursorMember = cursor; 389 } 390 } 391 392 393 ServerCursor* 394 CursorManager::_FindCursor(team_id clientTeam, const uint8* cursorData) 395 { 396 int32 count = fCursorList.CountItems(); 397 for (int32 i = 0; i < count; i++) { 398 ServerCursor* cursor = (ServerCursor*)fCursorList.ItemAtFast(i); 399 if (cursor->OwningTeam() == clientTeam 400 && cursor->CursorData() 401 && memcmp(cursor->CursorData(), cursorData, 68) == 0) { 402 return cursor; 403 } 404 } 405 return NULL; 406 } 407 408 409 void 410 CursorManager::_RemoveCursor(ServerCursor* cursor) 411 { 412 fCursorList.RemoveItem(cursor); 413 fTokenSpace.RemoveToken(cursor->fToken); 414 } 415