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