headers/bsd: Add sys/queue.h.
[haiku.git] / src / servers / app / CursorManager.cpp
blob71baafa0228befb63d42cd0daeee51ab173e6664
1 /*
2 * Copyright 2001-2016, Haiku.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * DarkWyrm <bpmagic@columbus.rr.com>
7 */
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"
20 #include <Autolock.h>
21 #include <Directory.h>
22 #include <String.h>
24 #include <new>
25 #include <stdio.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);
105 ServerCursor*
106 CursorManager::CreateCursor(team_id clientTeam, const uint8* cursorData)
108 if (!Lock())
109 return NULL;
111 ServerCursor* cursor = _FindCursor(clientTeam, cursorData);
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;
122 } else
123 cursor->AcquireReference();
125 Unlock();
127 return cursor;
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
135 int32
136 CursorManager::AddCursor(ServerCursor* cursor, int32 token)
138 if (!cursor)
139 return B_BAD_VALUE;
140 if (!Lock())
141 return B_ERROR;
143 if (!fCursorList.AddItem(cursor)) {
144 Unlock();
145 return B_NO_MEMORY;
148 if (token == -1)
149 token = fTokenSpace.NewToken(kCursorToken, cursor);
150 else
151 fTokenSpace.SetToken(token, kCursorToken, cursor);
153 cursor->fToken = token;
154 cursor->AttachedToManager(this);
156 Unlock();
158 return token;
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.
167 bool
168 CursorManager::RemoveCursor(ServerCursor* cursor)
170 if (!Lock())
171 return false;
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;
180 _RemoveCursor(cursor);
182 Unlock();
183 return true;
187 /*! \brief Removes and deletes all of an application's cursors
188 \param signature Signature to which the cursors belong
190 void
191 CursorManager::DeleteCursors(team_id team)
193 if (!Lock())
194 return;
196 for (int32 index = fCursorList.CountItems(); index-- > 0;) {
197 ServerCursor* cursor = (ServerCursor*)fCursorList.ItemAtFast(index);
198 if (cursor->OwningTeam() == team)
199 cursor->ReleaseReference();
202 Unlock();
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.
214 void
215 CursorManager::SetCursorSet(const char* path)
217 BAutolock locker (this);
219 CursorSet cursorSet(NULL);
221 if (!path || cursorSet.Load(path) != B_OK)
222 return;
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
269 ServerCursor*
270 CursorManager::GetCursor(BCursorID which)
272 BAutolock locker(this);
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;
334 default:
335 return NULL;
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
344 ServerCursor*
345 CursorManager::FindCursor(int32 token)
347 if (!Lock())
348 return NULL;
350 ServerCursor* cursor;
351 if (fTokenSpace.GetToken(token, kCursorToken, (void**)&cursor) != B_OK)
352 cursor = NULL;
354 Unlock();
356 return cursor;
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.
365 void
366 CursorManager::_InitCursor(ServerCursor*& cursorMember,
367 const uint8* cursorBits, BCursorID id, const BPoint& hotSpot)
369 if (cursorBits) {
370 cursorMember = new ServerCursor(cursorBits, kCursorWidth,
371 kCursorHeight, kCursorFormat);
372 } else
373 cursorMember = new ServerCursor(kCursorNoCursor, 1, 1, kCursorFormat);
375 cursorMember->SetHotSpot(hotSpot);
376 AddCursor(cursorMember, id);
380 void
381 CursorManager::_LoadCursor(ServerCursor*& cursorMember, const CursorSet& set,
382 BCursorID id)
384 ServerCursor* cursor;
385 if (set.FindCursor(id, &cursor) == B_OK) {
386 int32 index = fCursorList.IndexOf(cursorMember);
387 if (index >= 0) {
388 ServerCursor* items = reinterpret_cast<ServerCursor*>(
389 fCursorList.Items());
390 items[index] = cursor;
392 delete cursorMember;
393 cursorMember = cursor;
398 ServerCursor*
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) {
407 return cursor;
410 return NULL;
414 void
415 CursorManager::_RemoveCursor(ServerCursor* cursor)
417 fCursorList.RemoveItem(cursor);
418 fTokenSpace.RemoveToken(cursor->fToken);