xref: /haiku/src/servers/app/CursorManager.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
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