2 * Copyright 2001-2016, Haiku.
3 * Distributed under the terms of the MIT License.
6 * DarkWyrm <bpmagic@columbus.rr.com>
10 /*! Handles the system's cursor infrastructure */
13 #include "CursorManager.h"
15 #include "CursorData.h"
16 #include "ServerCursor.h"
17 #include "ServerConfig.h"
18 #include "ServerTokenSpace.h"
21 #include <Directory.h>
28 CursorManager::CursorManager()
30 BLocker("CursorManager")
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));
97 //! Does all the teardown
98 CursorManager::~CursorManager()
100 for (int32 i
= 0; i
< fCursorList
.CountItems(); i
++)
101 delete (ServerCursor
*)fCursorList
.ItemAtFast(i
);
106 CursorManager::CreateCursor(team_id clientTeam
, const uint8
* cursorData
)
111 ServerCursor
* cursor
= _FindCursor(clientTeam
, cursorData
);
114 cursor
= new (std::nothrow
) ServerCursor(cursorData
);
116 cursor
->SetOwningTeam(clientTeam
);
117 if (AddCursor(cursor
) < B_OK
) {
123 cursor
->AcquireReference();
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
136 CursorManager::AddCursor(ServerCursor
* cursor
, int32 token
)
143 if (!fCursorList
.AddItem(cursor
)) {
149 token
= fTokenSpace
.NewToken(kCursorToken
, cursor
);
151 fTokenSpace
.SetToken(token
, kCursorToken
, cursor
);
153 cursor
->fToken
= token
;
154 cursor
->AttachedToManager(this);
162 /*! \brief Removes a cursor if it's not referenced anymore.
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.
168 CursorManager::RemoveCursor(ServerCursor
* cursor
)
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
180 _RemoveCursor(cursor
);
187 /*! \brief Removes and deletes all of an application's cursors
188 \param signature Signature to which the cursors belong
191 CursorManager::DeleteCursors(team_id team
)
196 for (int32 index
= fCursorList
.CountItems(); index
-- > 0;) {
197 ServerCursor
* cursor
= (ServerCursor
*)fCursorList
.ItemAtFast(index
);
198 if (cursor
->OwningTeam() == team
)
199 cursor
->ReleaseReference();
206 /*! \brief Sets all the cursors from a specified CursorSet
207 \param path Path to the cursor set
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.
215 CursorManager::SetCursorSet(const char* path
)
217 BAutolock
locker (this);
219 CursorSet
cursorSet(NULL
);
221 if (!path
|| cursorSet
.Load(path
) != B_OK
)
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
);
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
270 CursorManager::GetCursor(BCursorID which
)
272 BAutolock
locker(this);
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
:
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
:
289 case B_CURSOR_ID_GRABBING
:
290 return fCursorGrabbing
;
291 case B_CURSOR_ID_HELP
:
293 case B_CURSOR_ID_I_BEAM
:
295 case B_CURSOR_ID_I_BEAM_HORIZONTAL
:
296 return fCursorIBeamHorizontal
;
297 case B_CURSOR_ID_MOVE
:
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
;
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
345 CursorManager::FindCursor(int32 token
)
350 ServerCursor
* cursor
;
351 if (fTokenSpace
.GetToken(token
, kCursorToken
, (void**)&cursor
) != B_OK
)
360 /*! \brief Initializes a predefined system cursor.
362 This method must only be called in the CursorManager's constructor,
363 as it may throw exceptions.
366 CursorManager::_InitCursor(ServerCursor
*& cursorMember
,
367 const uint8
* cursorBits
, BCursorID id
, const BPoint
& hotSpot
)
370 cursorMember
= new ServerCursor(cursorBits
, kCursorWidth
,
371 kCursorHeight
, kCursorFormat
);
373 cursorMember
= new ServerCursor(kCursorNoCursor
, 1, 1, kCursorFormat
);
375 cursorMember
->SetHotSpot(hotSpot
);
376 AddCursor(cursorMember
, id
);
381 CursorManager::_LoadCursor(ServerCursor
*& cursorMember
, const CursorSet
& set
,
384 ServerCursor
* cursor
;
385 if (set
.FindCursor(id
, &cursor
) == B_OK
) {
386 int32 index
= fCursorList
.IndexOf(cursorMember
);
388 ServerCursor
* items
= reinterpret_cast<ServerCursor
*>(
389 fCursorList
.Items());
390 items
[index
] = cursor
;
393 cursorMember
= cursor
;
399 CursorManager::_FindCursor(team_id clientTeam
, const uint8
* cursorData
)
401 int32 count
= fCursorList
.CountItems();
402 for (int32 i
= 0; i
< count
; i
++) {
403 ServerCursor
* cursor
= (ServerCursor
*)fCursorList
.ItemAtFast(i
);
404 if (cursor
->OwningTeam() == clientTeam
405 && cursor
->CursorData()
406 && memcmp(cursor
->CursorData(), cursorData
, 68) == 0) {
415 CursorManager::_RemoveCursor(ServerCursor
* cursor
)
417 fCursorList
.RemoveItem(cursor
);
418 fTokenSpace
.RemoveToken(cursor
->fToken
);