xref: /haiku/src/servers/app/CursorManager.cpp (revision 2213782534a8b17fdea5d7fc603360f4c9ac317e)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2001-2005, Haiku, Inc.
3 //
4 //	Permission is hereby granted, free of charge, to any person obtaining a
5 //	copy of this software and associated documentation files (the "Software"),
6 //	to deal in the Software without restriction, including without limitation
7 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 //	and/or sell copies of the Software, and to permit persons to whom the
9 //	Software is furnished to do so, subject to the following conditions:
10 //
11 //	The above copyright notice and this permission notice shall be included in
12 //	all copies or substantial portions of the Software.
13 //
14 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 //	DEALINGS IN THE SOFTWARE.
21 //
22 //	File Name:		CursorManager.cpp
23 //	Author:			DarkWyrm <bpmagic@columbus.rr.com>
24 //	Description:	Handles the system's cursor infrastructure
25 //
26 //------------------------------------------------------------------------------
27 #include <Directory.h>
28 #include <String.h>
29 #include "CursorData.h"
30 #include "CursorManager.h"
31 #include "ServerCursor.h"
32 #include "ServerConfig.h"
33 #include "HaikuSystemCursor.h"
34 
35 //! Initializes the CursorManager
36 CursorManager::CursorManager()
37 {
38 	// Error code for AddCursor
39 	fTokenizer.ExcludeValue(B_ERROR);
40 
41 	// Set system cursors to "unassigned"
42 	// ToDo: decide about default cursor
43 #if 1
44 	fDefaultCursor = new ServerCursor(kHaikuCursorBits, kHaikuCursorWidth,
45 		kHaikuCursorHeight, kHaikuCursorFormat);
46 	// we just happen to know where the hotspot is
47 	fDefaultCursor->SetHotSpot(BPoint(1, 0));
48 #else
49 	fDefaultCursor = new ServerCursor(default_cursor_data);
50 	AddCursor(fDefaultCursor);
51 #endif
52 
53 	fTextCursor = new ServerCursor(default_text_data);
54 	AddCursor(fTextCursor);
55 
56 	fMoveCursor = new ServerCursor(default_move_data);
57 	AddCursor(fMoveCursor);
58 
59 	fDragCursor = new ServerCursor(default_drag_data);
60 	AddCursor(fDragCursor);
61 
62 	fResizeCursor = new ServerCursor(default_resize_data);
63 	AddCursor(fResizeCursor);
64 
65 	fNWSECursor = new ServerCursor(default_resize_nwse_data);
66 	AddCursor(fNWSECursor);
67 
68 	fNESWCursor = new ServerCursor(default_resize_nesw_data);
69 	AddCursor(fNESWCursor);
70 
71 	fNSCursor = new ServerCursor(default_resize_ns_data);
72 	AddCursor(fNSCursor);
73 
74 	fEWCursor = new ServerCursor(default_resize_ew_data);
75 	AddCursor(fEWCursor);
76 }
77 
78 
79 //! Does all the teardown
80 CursorManager::~CursorManager()
81 {
82 	for (int32 i = 0; i < fCursorList.CountItems(); i++) {
83 		ServerCursor *cursor = (ServerCursor *)fCursorList.ItemAt(i);
84 		if (cursor)
85 			delete cursor;
86 	}
87 
88 	// Note that it is not necessary to remove and delete the system
89 	// cursors. These cursors are kept in the list with a empty application
90 	// signature so they cannot be removed very easily except via
91 	// SetCursor(cursor_which). At shutdown, they are removed with the
92 	// above loop.
93 }
94 
95 
96 /*!
97 	\brief Registers a cursor with the manager.
98 	\param sc ServerCursor object to register
99 	\return The token assigned to the cursor or B_ERROR if sc is NULL
100 */
101 int32
102 CursorManager::AddCursor(ServerCursor *cursor)
103 {
104 	if (!cursor)
105 		return B_ERROR;
106 
107 	Lock();
108 
109 	fCursorList.AddItem(cursor);
110 	int32 token = fTokenizer.GetToken();
111 	cursor->fToken = token;
112 
113 	Unlock();
114 	return token;
115 }
116 
117 
118 /*!
119 	\brief Removes a cursor from the internal list and deletes it
120 	\param token ID value of the cursor to be deleted
121 
122 	If the cursor is not found, this call does nothing
123 */
124 void
125 CursorManager::DeleteCursor(int32 token)
126 {
127 	Lock();
128 
129 	for (int32 i = 0; i < fCursorList.CountItems(); i++) {
130 		ServerCursor *cursor = (ServerCursor *)fCursorList.ItemAt(i);
131 
132 		if (cursor && cursor->fToken == token) {
133 			fCursorList.RemoveItem(i);
134 			delete cursor;
135 			break;
136 		}
137 	}
138 
139 	Unlock();
140 }
141 
142 
143 /*!
144 	\brief Removes and deletes all of an application's cursors
145 	\param signature Signature to which the cursors belong
146 */
147 void
148 CursorManager::RemoveAppCursors(team_id team)
149 {
150 	Lock();
151 
152 	int32 index = 0;
153 	while (index < fCursorList.CountItems()) {
154 		ServerCursor *cursor = (ServerCursor *)fCursorList.ItemAt(index);
155 		if (!cursor)
156 			break;
157 
158 		if (cursor->OwningTeam() == team) {
159 			fCursorList.RemoveItem(index);
160 			delete cursor;
161 		} else
162 			index++;
163 	}
164 
165 	Unlock();
166 }
167 
168 
169 /*!
170 	\brief Sets all the cursors from a specified CursorSet
171 	\param path Path to the cursor set
172 
173 	All cursors in the set will be assigned. If the set does not specify a
174 	cursor for a particular cursor specifier, it will remain unchanged.
175 	This function will fail if passed a NULL path, an invalid path, or the
176 	path to a non-CursorSet file.
177 */
178 void
179 CursorManager::SetCursorSet(const char *path)
180 {
181 	Lock();
182 	CursorSet cursorSet(NULL);
183 
184 	if (!path || cursorSet.Load(path) != B_OK)
185 		return;
186 
187 	ServerCursor *cursor = NULL;
188 
189 	if (cursorSet.FindCursor(B_CURSOR_DEFAULT, &cursor) == B_OK) {
190 		if (fDefaultCursor)
191 			delete fDefaultCursor;
192 		fDefaultCursor = cursor;
193 	}
194 
195 	if (cursorSet.FindCursor(B_CURSOR_TEXT, &cursor) == B_OK) {
196 		if (fTextCursor)
197 			delete fTextCursor;
198 		fTextCursor = cursor;
199 	}
200 
201 	if (cursorSet.FindCursor(B_CURSOR_MOVE, &cursor) == B_OK) {
202 		if (fMoveCursor)
203 			delete fMoveCursor;
204 		fMoveCursor = cursor;
205 	}
206 
207 	if (cursorSet.FindCursor(B_CURSOR_DRAG, &cursor) == B_OK) {
208 		if (fDragCursor)
209 			delete fDragCursor;
210 		fDragCursor = cursor;
211 	}
212 
213 	if (cursorSet.FindCursor(B_CURSOR_RESIZE, &cursor) == B_OK) {
214 		if (fResizeCursor)
215 			delete fResizeCursor;
216 		fResizeCursor = cursor;
217 	}
218 
219 	if (cursorSet.FindCursor(B_CURSOR_RESIZE_NWSE, &cursor) == B_OK) {
220 		if (fNWSECursor)
221 			delete fNWSECursor;
222 		fNWSECursor = cursor;
223 	}
224 
225 	if (cursorSet.FindCursor(B_CURSOR_RESIZE_NESW, &cursor) == B_OK) {
226 		if (fNESWCursor)
227 			delete fNESWCursor;
228 		fNESWCursor = cursor;
229 	}
230 
231 	if (cursorSet.FindCursor(B_CURSOR_RESIZE_NS, &cursor) == B_OK) {
232 		if (fNSCursor)
233 			delete fNSCursor;
234 		fNSCursor = cursor;
235 	}
236 
237 	if (cursorSet.FindCursor(B_CURSOR_RESIZE_EW, &cursor) == B_OK) {
238 		if (fEWCursor)
239 			delete fEWCursor;
240 		fEWCursor = cursor;
241 	}
242 
243 	Unlock();
244 }
245 
246 
247 /*!
248 	\brief Acquire the cursor which is used for a particular system cursor
249 	\param which Which system cursor to get
250 	\return Pointer to the particular cursor used or NULL if which is
251 	invalid or the cursor has not been assigned
252 */
253 ServerCursor *
254 CursorManager::GetCursor(cursor_which which)
255 {
256 	ServerCursor *cursor = NULL;
257 	Lock();
258 
259 	switch (which) {
260 		case B_CURSOR_DEFAULT:
261 			cursor = fDefaultCursor;
262 			break;
263 
264 		case B_CURSOR_TEXT:
265 			cursor = fTextCursor;
266 			break;
267 
268 		case B_CURSOR_MOVE:
269 			cursor = fMoveCursor;
270 			break;
271 
272 		case B_CURSOR_DRAG:
273 			cursor = fDragCursor;
274 			break;
275 
276 		case B_CURSOR_RESIZE:
277 			cursor = fResizeCursor;
278 			break;
279 
280 		case B_CURSOR_RESIZE_NWSE:
281 			cursor = fNWSECursor;
282 			break;
283 
284 		case B_CURSOR_RESIZE_NESW:
285 			cursor = fNESWCursor;
286 			break;
287 
288 		case B_CURSOR_RESIZE_NS:
289 			cursor = fNSCursor;
290 			break;
291 
292 		case B_CURSOR_RESIZE_EW:
293 			cursor = fEWCursor;
294 			break;
295 
296 		default:
297 			break;
298 	}
299 
300 	Unlock();
301 	return cursor;
302 }
303 
304 
305 /*!
306 	\brief Gets the current system cursor value
307 	\return The current cursor value or CURSOR_OTHER if some non-system cursor
308 */
309 cursor_which
310 CursorManager::GetCursorWhich()
311 {
312 	Lock();
313 
314 	// ToDo: Where is fCurrentWhich set?
315 	cursor_which which;
316 	which = fCurrentWhich;
317 
318 	Unlock();
319 	return which;
320 }
321 
322 
323 /*!
324 	\brief Sets the specified system cursor to the a particular cursor
325 	\param which Which system cursor to change
326 	\param token The ID of the cursor to become the new one
327 
328 	A word of warning: once a cursor has been assigned to the system, the
329 	system will take ownership of the cursor and deleting the cursor
330 	will have no effect on the system.
331 */
332 void
333 CursorManager::ChangeCursor(cursor_which which, int32 token)
334 {
335 	Lock();
336 
337 	// Find the cursor, based on the token
338 	ServerCursor *cursor = FindCursor(token);
339 
340 	// Did we find a cursor with this token?
341 	if (!cursor) {
342 		Unlock();
343 		return;
344 	}
345 
346 	// Do the assignment
347 	switch (which) {
348 		case B_CURSOR_DEFAULT:
349 		{
350 			if (fDefaultCursor)
351 				delete fDefaultCursor;
352 
353 			fDefaultCursor = cursor;
354 			break;
355 		}
356 		case B_CURSOR_TEXT:
357 		{
358 			if(fTextCursor)
359 				delete fTextCursor;
360 
361 			fTextCursor = cursor;
362 			break;
363 		}
364 		case B_CURSOR_MOVE:
365 		{
366 			if(fMoveCursor)
367 				delete fMoveCursor;
368 
369 			fMoveCursor = cursor;
370 			break;
371 		}
372 		case B_CURSOR_DRAG:
373 		{
374 			if(fDragCursor)
375 				delete fDragCursor;
376 
377 			fDragCursor = cursor;
378 			break;
379 		}
380 		case B_CURSOR_RESIZE:
381 		{
382 			if(fResizeCursor)
383 				delete fResizeCursor;
384 
385 			fResizeCursor = cursor;
386 			break;
387 		}
388 		case B_CURSOR_RESIZE_NWSE:
389 		{
390 			if(fNWSECursor)
391 				delete fNWSECursor;
392 
393 			fNWSECursor = cursor;
394 			break;
395 		}
396 		case B_CURSOR_RESIZE_NESW:
397 		{
398 			if(fNESWCursor)
399 				delete fNESWCursor;
400 
401 			fNESWCursor = cursor;
402 			break;
403 		}
404 		case B_CURSOR_RESIZE_NS:
405 		{
406 			if(fNSCursor)
407 				delete fNSCursor;
408 
409 			fNSCursor = cursor;
410 			break;
411 		}
412 		case B_CURSOR_RESIZE_EW:
413 		{
414 			if(fEWCursor)
415 				delete fEWCursor;
416 
417 			fEWCursor = cursor;
418 			break;
419 		}
420 		default:
421 			Unlock();
422 			return;
423 	}
424 
425 	if (cursor->GetAppSignature())
426 		cursor->SetAppSignature("");
427 
428 	fCursorList.RemoveItem(cursor);
429 	Unlock();
430 }
431 
432 
433 /*!
434 	\brief Internal function which finds the cursor with a particular ID
435 	\param token ID of the cursor to find
436 	\return The cursor or NULL if not found
437 */
438 ServerCursor *
439 CursorManager::FindCursor(int32 token)
440 {
441 	for (int32 i = 0; i < fCursorList.CountItems(); i++) {
442 		ServerCursor *cursor = (ServerCursor *)fCursorList.ItemAt(i);
443 		if (cursor && cursor->fToken == token)
444 			return cursor;
445 	}
446 
447 	return NULL;
448 }
449 
450 
451 //! Sets the cursors to the defaults and saves them to CURSOR_SETTINGS_DIR/"d
452 void
453 CursorManager::SetDefaults()
454 {
455 	Lock();
456 	CursorSet cursorSet("Default");
457 	cursorSet.AddCursor(B_CURSOR_DEFAULT, default_cursor_data);
458 	cursorSet.AddCursor(B_CURSOR_TEXT, default_text_data);
459 	cursorSet.AddCursor(B_CURSOR_MOVE, default_move_data);
460 	cursorSet.AddCursor(B_CURSOR_DRAG, default_drag_data);
461 	cursorSet.AddCursor(B_CURSOR_RESIZE, default_resize_data);
462 	cursorSet.AddCursor(B_CURSOR_RESIZE_NWSE, default_resize_nwse_data);
463 	cursorSet.AddCursor(B_CURSOR_RESIZE_NESW, default_resize_nesw_data);
464 	cursorSet.AddCursor(B_CURSOR_RESIZE_NS, default_resize_ns_data);
465 	cursorSet.AddCursor(B_CURSOR_RESIZE_EW, default_resize_ew_data);
466 
467 	BDirectory dir;
468 	if (dir.SetTo(CURSOR_SET_DIR) == B_ENTRY_NOT_FOUND)
469 		create_directory(CURSOR_SET_DIR, 0777);
470 
471 	BString string(CURSOR_SET_DIR);
472 	string += "Default";
473 	cursorSet.Save(string.String(), B_CREATE_FILE | B_FAIL_IF_EXISTS);
474 
475 	SetCursorSet(string.String());
476 	Unlock();
477 }
478