xref: /haiku/src/servers/app/ServerApp.cpp (revision 746cac055adc6ac3308c7bc2d29040fb95689cc9)
1 /*
2  * Copyright 2001-2008, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		DarkWyrm <bpmagic@columbus.rr.com>
7  *		Adrian Oanca <adioanca@cotty.iren.ro>
8  *		Stephan Aßmus <superstippi@gmx.de>
9  *		Stefano Ceccherini (burton666@libero.it)
10  *		Axel Dörfler, axeld@pinc-software.de
11  *		Jérôme Duval, jerome.duval@free.fr
12  *		Andrej Spielmann, <andrej.spielmann@seh.ox.ac.uk>
13  */
14 
15 /*!
16 	\class ServerApp ServerApp.h
17 	\brief Counterpart to BApplication within the app_server
18 */
19 
20 #include "AppServer.h"
21 #include "BitmapManager.h"
22 #include "CursorManager.h"
23 #include "CursorSet.h"
24 #include "Desktop.h"
25 #include "DecorManager.h"
26 #include "DrawingEngine.h"
27 #include "EventStream.h"
28 #include "FontManager.h"
29 #include "HWInterface.h"
30 #include "InputManager.h"
31 #include "OffscreenServerWindow.h"
32 #include "Screen.h"
33 #include "ServerApp.h"
34 #include "ServerBitmap.h"
35 #include "ServerConfig.h"
36 #include "ServerCursor.h"
37 #include "ServerPicture.h"
38 #include "ServerTokenSpace.h"
39 #include "ServerWindow.h"
40 #include "SystemPalette.h"
41 #include "Window.h"
42 
43 #include <FontPrivate.h>
44 #include <MessengerPrivate.h>
45 #include <RosterPrivate.h>
46 #include <ServerProtocol.h>
47 #include <WindowPrivate.h>
48 
49 #include <AppDefs.h>
50 #include <Autolock.h>
51 #include <List.h>
52 #include <ScrollBar.h>
53 #include <Shape.h>
54 #include <String.h>
55 
56 #include <new>
57 #include <stdio.h>
58 #include <string.h>
59 #include <syslog.h>
60 
61 
62 //#define DEBUG_SERVERAPP
63 #ifdef DEBUG_SERVERAPP
64 #	define STRACE(x) debug_printf x
65 #else
66 #	define STRACE(x) ;
67 #endif
68 
69 //#define DEBUG_SERVERAPP_FONT
70 #ifdef DEBUG_SERVERAPP_FONT
71 #	define FTRACE(x) debug_printf x
72 #else
73 #	define FTRACE(x) ;
74 #endif
75 
76 using std::nothrow;
77 
78 static const uint32 kMsgUpdateShowAllDraggers = '_adg';
79 static const uint32 kMsgAppQuit = 'appQ';
80 
81 
82 ServerApp::ServerApp(Desktop* desktop, port_id clientReplyPort,
83 		port_id clientLooperPort, team_id clientTeam,
84 		int32 clientToken, const char* signature)
85 	: MessageLooper("application"),
86 
87 	fMessagePort(-1),
88 	fClientReplyPort(clientReplyPort),
89 	fDesktop(desktop),
90 	fSignature(signature),
91 	fClientTeam(clientTeam),
92 	fWindowListLock("window list"),
93 	fAppCursor(NULL),
94 	fViewCursor(NULL),
95 	fCursorHideLevel(0),
96 	fIsActive(false),
97 	fMemoryAllocator(this)
98 {
99 	if (fSignature == "")
100 		fSignature = "application/no-signature";
101 
102 	char name[B_OS_NAME_LENGTH];
103 	snprintf(name, sizeof(name), "a<%ld:%s", clientTeam, SignatureLeaf());
104 
105 	fMessagePort = create_port(DEFAULT_MONITOR_PORT_SIZE, name);
106 	if (fMessagePort < B_OK)
107 		return;
108 
109 	fLink.SetSenderPort(fClientReplyPort);
110 	fLink.SetReceiverPort(fMessagePort);
111 
112 	// we let the application own the port, so that we get aware when it's gone
113 	if (set_port_owner(fMessagePort, clientTeam) < B_OK) {
114 		delete_port(fMessagePort);
115 		fMessagePort = -1;
116 		return;
117 	}
118 
119 	BMessenger::Private(fHandlerMessenger).SetTo(fClientTeam,
120 		clientLooperPort, clientToken);
121 
122 	fInitialWorkspace = desktop->CurrentWorkspace();
123 		// TODO: this should probably be retrieved when the app is loaded!
124 
125 	STRACE(("ServerApp %s:\n", Signature()));
126 	STRACE(("\tBApp port: %ld\n", fClientReplyPort));
127 	STRACE(("\tReceiver port: %ld\n", fMessagePort));
128 }
129 
130 
131 ServerApp::~ServerApp()
132 {
133 	STRACE(("*ServerApp %s:~ServerApp()\n", Signature()));
134 	ASSERT(fQuitting);
135 
136 	// quit all server windows
137 
138 	fWindowListLock.Lock();
139 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
140 		ServerWindow* window = fWindowList.ItemAt(i);
141 		window->Quit();
142 	}
143 	fWindowListLock.Unlock();
144 
145 	// wait for the windows to quit
146 
147 	snooze(20000);
148 
149 	fWindowListLock.Lock();
150 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
151 		ServerWindow* window = fWindowList.ItemAt(i);
152 
153 		// a window could have been remove in the mean time (if those 20 millisecs
154 		// from above weren't enough)
155 		if (window == NULL)
156 			continue;
157 
158 		sem_id deathSemaphore = window->DeathSemaphore();
159 		fWindowListLock.Unlock();
160 
161 		// wait 3 seconds for our window to quit - that's quite a long
162 		// time, but killing it might have desastrous effects
163 		if (MessageLooper::WaitForQuit(deathSemaphore, 3000000) != B_OK) {
164 			// This really shouldn't happen, as it shows we're buggy
165 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
166 			syslog(LOG_ERR, "ServerApp %s: ServerWindow doesn't respond!\n",
167 				Signature());
168 #else
169 			debugger("ServerWindow doesn't respond!\n");
170 #endif
171 		}
172 		fWindowListLock.Lock();
173 	}
174 
175 	for (int32 i = fBitmapList.CountItems(); i-- > 0;) {
176 		gBitmapManager->DeleteBitmap(static_cast<ServerBitmap *>(fBitmapList.ItemAt(i)));
177 	}
178 
179 	for (int32 i = fPictureList.CountItems(); i-- > 0;) {
180 		delete (ServerPicture*)fPictureList.ItemAtFast(i);
181 	}
182 
183 	fDesktop->GetCursorManager().DeleteCursors(fClientTeam);
184 
185 	STRACE(("ServerApp %s::~ServerApp(): Exiting\n", Signature()));
186 }
187 
188 
189 /*!
190 	\brief Checks if the application was initialized correctly
191 */
192 status_t
193 ServerApp::InitCheck()
194 {
195 	if (fMessagePort < B_OK)
196 		return fMessagePort;
197 
198 	if (fClientReplyPort < B_OK)
199 		return fClientReplyPort;
200 
201 	if (fWindowListLock.Sem() < B_OK)
202 		return fWindowListLock.Sem();
203 
204 	return B_OK;
205 }
206 
207 
208 /*!
209 	\brief This quits the application and deletes it. You're not supposed
210 		to call its destructor directly.
211 
212 	At the point you're calling this method, the application should already
213 	be removed from the application list.
214 */
215 void
216 ServerApp::Quit(sem_id shutdownSemaphore)
217 {
218 	if (fThread < B_OK) {
219 		delete this;
220 		return;
221 	}
222 
223 	// execute application deletion in the message looper thread
224 
225 	fQuitting = true;
226 	PostMessage(kMsgAppQuit);
227 
228 	send_data(fThread, 'QUIT', &shutdownSemaphore, sizeof(sem_id));
229 }
230 
231 
232 /*!
233 	\brief Send a message to the ServerApp's BApplication
234 	\param msg The message to send
235 */
236 void
237 ServerApp::SendMessageToClient(BMessage *msg) const
238 {
239 	status_t status = fHandlerMessenger.SendMessage(msg, (BHandler*)NULL, 100000);
240 	if (status != B_OK)
241 		printf("app %s send to client failed: %s\n", Signature(), strerror(status));
242 }
243 
244 
245 bool
246 ServerApp::_HasWindowUnderMouse()
247 {
248 	BAutolock locker(fWindowListLock);
249 
250 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
251 		ServerWindow* serverWindow = fWindowList.ItemAt(i);
252 
253 		if (fDesktop->ViewUnderMouse(serverWindow->Window()) != B_NULL_TOKEN)
254 			return true;
255 	}
256 
257 	return false;
258 }
259 
260 
261 /*!
262 	\brief Sets the ServerApp's active status
263 	\param value The new status of the ServerApp.
264 
265 	This changes an internal flag and also sets the current cursor to the one
266 	specified by the application
267 */
268 void
269 ServerApp::Activate(bool value)
270 {
271 	if (fIsActive == value)
272 		return;
273 
274 	fIsActive = value;
275 
276 	if (fIsActive) {
277 		// notify registrar about the active app
278 		BRoster::Private roster;
279 		roster.UpdateActiveApp(ClientTeam());
280 
281 		if (_HasWindowUnderMouse()) {
282 			// Set the cursor to the application cursor, if any
283 			fDesktop->SetCursor(CurrentCursor());
284 		}
285 		fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0);
286 	}
287 }
288 
289 
290 void
291 ServerApp::SetCurrentCursor(ServerCursor* cursor)
292 {
293 	fViewCursor = cursor;
294 	fDesktop->SetCursor(CurrentCursor());
295 }
296 
297 
298 ServerCursor*
299 ServerApp::CurrentCursor() const
300 {
301 	if (fViewCursor != NULL)
302 		return fViewCursor;
303 
304 	return fAppCursor;
305 }
306 
307 
308 void
309 ServerApp::_GetLooperName(char* name, size_t length)
310 {
311 	snprintf(name, length, "a:%ld:%s", ClientTeam(), SignatureLeaf());
312 }
313 
314 
315 /*!
316 	\brief The thread function ServerApps use to monitor messages
317 */
318 void
319 ServerApp::_MessageLooper()
320 {
321 	// Message-dispatching loop for the ServerApp
322 
323 	// First let's tell the client how to talk with us.
324 	fLink.StartMessage(B_OK);
325 	fLink.Attach<port_id>(fMessagePort);
326 	fLink.Attach<area_id>(fDesktop->SharedReadOnlyArea());
327 	fLink.Flush();
328 
329 	BPrivate::LinkReceiver &receiver = fLink.Receiver();
330 
331 	int32 code;
332 	status_t err = B_OK;
333 
334 	while (!fQuitting) {
335 		STRACE(("info: ServerApp::_MessageLooper() listening on port %ld.\n", fMessagePort));
336 		err = receiver.GetNextMessage(code, B_INFINITE_TIMEOUT);
337 		if (err < B_OK || code == B_QUIT_REQUESTED) {
338 			STRACE(("ServerApp: application seems to be gone...\n"));
339 
340 			// Tell desktop to quit us
341 			BPrivate::LinkSender link(fDesktop->MessagePort());
342 			link.StartMessage(AS_DELETE_APP);
343 			link.Attach<thread_id>(Thread());
344 			link.Flush();
345 			break;
346 		}
347 
348 		switch (code) {
349 			case kMsgAppQuit:
350 				// we receive this from our destructor on quit
351 				fQuitting = true;
352 				break;
353 
354 			case AS_QUIT_APP:
355 			{
356 				// This message is received only when the app_server is asked to shut down in
357 				// test/debug mode. Of course, if we are testing while using AccelerantDriver, we do
358 				// NOT want to shut down client applications. The server can be quit o in this fashion
359 				// through the driver's interface, such as closing the ViewDriver's window.
360 
361 				STRACE(("ServerApp %s:Server shutdown notification received\n", Signature()));
362 
363 				// If we are using the real, accelerated version of the
364 				// DrawingEngine, we do NOT want the user to be able shut down
365 				// the server. The results would NOT be pretty
366 #if TEST_MODE
367 				BMessage pleaseQuit(B_QUIT_REQUESTED);
368 				SendMessageToClient(&pleaseQuit);
369 #endif
370 				break;
371 			}
372 
373 			default:
374 				STRACE(("ServerApp %s: Got a Message to dispatch\n", Signature()));
375 				_DispatchMessage(code, receiver);
376 				break;
377 		}
378 	}
379 
380 	// Quit() will send us a message; we're handling the exiting procedure
381 	thread_id sender;
382 	sem_id shutdownSemaphore;
383 	receive_data(&sender, &shutdownSemaphore, sizeof(sem_id));
384 
385 	delete this;
386 
387 	if (shutdownSemaphore >= B_OK)
388 		release_sem(shutdownSemaphore);
389 }
390 
391 
392 /*!
393 	\brief Handler function for BApplication API messages
394 	\param code Identifier code for the message. Equivalent to BMessage::what
395 	\param buffer Any attachments
396 
397 	Note that the buffer's exact format is determined by the particular message.
398 	All attachments are placed in the buffer via a PortLink, so it will be a
399 	matter of casting and incrementing an index variable to access them.
400 */
401 void
402 ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
403 {
404 	switch (code) {
405 		case AS_REGISTER_INPUT_SERVER:
406 		{
407 			EventStream* stream = new (nothrow) InputServerStream(fHandlerMessenger);
408 			if (stream != NULL
409 				&& (!stream->IsValid() || !gInputManager->AddStream(stream))) {
410 				delete stream;
411 				break;
412 			}
413 
414 			// TODO: this should be done using notifications (so that an abandoned
415 			//	stream will get noticed directly)
416 			if (fDesktop->EventDispatcher().InitCheck() != B_OK)
417 				fDesktop->EventDispatcher().SetTo(gInputManager->GetStream());
418 			break;
419 		}
420 
421 		case AS_APP_CRASHED:
422 			// Allow the debugger to show its window: if needed, remove any
423 			// kWindowScreenFeels from the windows of this application
424 			if (fWindowListLock.Lock()) {
425 				for (int32 i = fWindowList.CountItems(); i-- > 0;) {
426 					ServerWindow* serverWindow = fWindowList.ItemAt(i);
427 
428 					Window* window = serverWindow->Window();
429 					if (window == NULL || window->IsOffscreenWindow())
430 						continue;
431 
432 					if (window->Feel() == kWindowScreenFeel)
433 						fDesktop->SetWindowFeel(window, B_NORMAL_WINDOW_FEEL);
434 				}
435 
436 				fWindowListLock.Unlock();
437 			}
438 			break;
439 
440 		case AS_CREATE_WINDOW:
441 		case AS_CREATE_OFFSCREEN_WINDOW:
442 		{
443 			port_id clientReplyPort = -1;
444 			status_t status = _CreateWindow(code, link, clientReplyPort);
445 
446 			// if sucessful, ServerWindow::Run() will already have replied
447 			if (status < B_OK) {
448 				// window creation failed, we need to notify the client
449 				BPrivate::LinkSender reply(clientReplyPort);
450 				reply.StartMessage(status);
451 				reply.Flush();
452 			}
453 			break;
454 		}
455 
456 		case AS_GET_WINDOW_LIST:
457 		{
458 			team_id team;
459 			if (link.Read<team_id>(&team) == B_OK)
460 				fDesktop->WriteWindowList(team, fLink.Sender());
461 			break;
462 		}
463 
464 		case AS_GET_WINDOW_INFO:
465 		{
466 			int32 serverToken;
467 			if (link.Read<int32>(&serverToken) == B_OK)
468 				fDesktop->WriteWindowInfo(serverToken, fLink.Sender());
469 			break;
470 		}
471 
472 		case AS_GET_WINDOW_ORDER:
473 		{
474 			int32 workspace;
475 			if (link.Read<int32>(&workspace) == B_OK)
476 				fDesktop->WriteWindowOrder(workspace, fLink.Sender());
477 			break;
478 		}
479 
480 		case AS_GET_APPLICATION_ORDER:
481 		{
482 			int32 workspace;
483 			if (link.Read<int32>(&workspace) == B_OK)
484 				fDesktop->WriteApplicationOrder(workspace, fLink.Sender());
485 			break;
486 		}
487 
488 		case AS_MINIMIZE_TEAM:
489 		{
490 			team_id team;
491 			if (link.Read<team_id>(&team) == B_OK)
492 				fDesktop->MinimizeApplication(team);
493 			break;
494 		}
495 
496 		case AS_BRING_TEAM_TO_FRONT:
497 		{
498 			team_id team;
499 			if (link.Read<team_id>(&team) == B_OK)
500 				fDesktop->BringApplicationToFront(team);
501 			break;
502 		}
503 
504 		case AS_WINDOW_ACTION:
505 		{
506 			int32 token;
507 			int32 action;
508 
509 			link.Read<int32>(&token);
510 			if (link.Read<int32>(&action) != B_OK)
511 				break;
512 
513 			fDesktop->WindowAction(token, action);
514 			break;
515 		}
516 
517 		// Decorator commands
518 
519 		case AS_SET_DECORATOR:
520 		{
521 			// Received from an application when the user wants to set the window
522 			// decorator to a new one
523 
524 			// Attached Data:
525 			// int32 the index of the decorator to use
526 
527 			int32 index;
528 			link.Read<int32>(&index);
529 			if (gDecorManager.SetDecorator(index))
530 				fDesktop->BroadcastToAllApps(AS_UPDATE_DECORATOR);
531 			break;
532 		}
533 		case AS_COUNT_DECORATORS:
534 		{
535 			fLink.StartMessage(B_OK);
536 			fLink.Attach<int32>(gDecorManager.CountDecorators());
537 			fLink.Flush();
538 			break;
539 		}
540 		case AS_GET_DECORATOR:
541 		{
542 			fLink.StartMessage(B_OK);
543 			fLink.Attach<int32>(gDecorManager.GetDecorator());
544 			fLink.Flush();
545 			break;
546 		}
547 		case AS_GET_DECORATOR_NAME:
548 		{
549 			int32 index;
550 			link.Read<int32>(&index);
551 
552 			BString str(gDecorManager.GetDecoratorName(index));
553 			if (str.CountChars() > 0) {
554 				fLink.StartMessage(B_OK);
555 				fLink.AttachString(str.String());
556 			} else
557 				fLink.StartMessage(B_ERROR);
558 
559 			fLink.Flush();
560 			break;
561 		}
562 		case AS_R5_SET_DECORATOR:
563 		{
564 			// Sort of supports Tracker's nifty Easter Egg. It was easy to do and
565 			// it's kind of neat, so why not?
566 
567 			// Attached Data:
568 			// int32 value of the decorator to use
569 			// 0: BeOS
570 			// 1: Amiga
571 			// 2: Windows
572 			// 3: MacOS
573 
574 			int32 decindex = 0;
575 			link.Read<int32>(&decindex);
576 
577 			if (gDecorManager.SetR5Decorator(decindex))
578 				fDesktop->BroadcastToAllApps(AS_UPDATE_DECORATOR);
579 
580 			break;
581 		}
582 		case AS_CREATE_BITMAP:
583 		{
584 			STRACE(("ServerApp %s: Received BBitmap creation request\n", Signature()));
585 			// Allocate a bitmap for an application
586 
587 			// Attached Data:
588 			// 1) BRect bounds
589 			// 2) color_space space
590 			// 3) int32 bitmap_flags
591 			// 4) int32 bytes_per_row
592 			// 5) int32 screen_id::id
593 
594 			// Reply Data:
595 			//	1) int32 server token
596 			//	2) area_id id of the area in which the bitmap data resides
597 			//	3) int32 area pointer offset used to calculate fBasePtr
598 
599 			// First, let's attempt to allocate the bitmap
600 			ServerBitmap *bitmap = NULL;
601 			uint8 allocationFlags = kAllocator;
602 
603 			BRect frame;
604 			color_space colorSpace;
605 			uint32 flags;
606 			int32 bytesPerRow;
607 			screen_id screenID;
608 
609 			link.Read<BRect>(&frame);
610 			link.Read<color_space>(&colorSpace);
611 			link.Read<uint32>(&flags);
612 			link.Read<int32>(&bytesPerRow);
613 			if (link.Read<screen_id>(&screenID) == B_OK) {
614 				// TODO: choose the right HWInterface with regards to the screenID
615 				bitmap = gBitmapManager->CreateBitmap(&fMemoryAllocator,
616 					*fDesktop->HWInterface(), frame, colorSpace, flags, bytesPerRow,
617 					screenID, &allocationFlags);
618 			}
619 
620 			STRACE(("ServerApp %s: Create Bitmap (%.1fx%.1f)\n",
621 				Signature(), frame.Width() + 1, frame.Height() + 1));
622 
623 			if (bitmap != NULL && fBitmapList.AddItem(bitmap)) {
624 				bitmap->SetOwner(this);
625 
626 				fLink.StartMessage(B_OK);
627 				fLink.Attach<int32>(bitmap->Token());
628 				fLink.Attach<uint8>(allocationFlags);
629 
630 				fLink.Attach<area_id>(fMemoryAllocator.Area(bitmap->AllocationCookie()));
631 				fLink.Attach<int32>(fMemoryAllocator.AreaOffset(bitmap->AllocationCookie()));
632 
633 				if (allocationFlags & kFramebuffer)
634 					fLink.Attach<int32>(bitmap->BytesPerRow());
635 			} else {
636 				if (bitmap != NULL)
637 					gBitmapManager->DeleteBitmap(bitmap);
638 
639 				fLink.StartMessage(B_NO_MEMORY);
640 			}
641 
642 			fLink.Flush();
643 			break;
644 		}
645 		case AS_DELETE_BITMAP:
646 		{
647 			STRACE(("ServerApp %s: received BBitmap delete request\n", Signature()));
648 			// Delete a bitmap's allocated memory
649 
650 			// Attached Data:
651 			// 1) int32 token
652 			int32 token;
653 			link.Read<int32>(&token);
654 
655 			ServerBitmap *bitmap = FindBitmap(token);
656 			if (bitmap && fBitmapList.RemoveItem(bitmap)) {
657 				STRACE(("ServerApp %s: Deleting Bitmap %ld\n", Signature(), token));
658 
659 				gBitmapManager->DeleteBitmap(bitmap);
660 			}
661 			break;
662 		}
663 		case AS_GET_BITMAP_OVERLAY_RESTRICTIONS:
664 		{
665 			overlay_restrictions restrictions;
666 			status_t status = B_ERROR;
667 
668 			int32 token;
669 			if (link.Read<int32>(&token) != B_OK)
670 				break;
671 
672 			ServerBitmap *bitmap = FindBitmap(token);
673 			if (bitmap != NULL) {
674 				STRACE(("ServerApp %s: Get overlay restrictions for bitmap %ld\n",
675 					Signature(), token));
676 
677 				status = fDesktop->HWInterface()->GetOverlayRestrictions(
678 					bitmap->Overlay(), &restrictions);
679 			}
680 
681 			fLink.StartMessage(status);
682 			if (status == B_OK)
683 				fLink.Attach(&restrictions, sizeof(overlay_restrictions));
684 
685 			fLink.Flush();
686 			break;
687 		}
688 		case AS_GET_BITMAP_SUPPORT_FLAGS:
689 		{
690 			uint32 colorSpace;
691 			if (link.Read<uint32>(&colorSpace) != B_OK)
692 				break;
693 
694 			bool overlay = fDesktop->HWInterface()->CheckOverlayRestrictions(
695 				64, 64, (color_space)colorSpace);
696 			uint32 flags = overlay ? B_BITMAPS_SUPPORT_OVERLAY : 0;
697 
698 			fLink.StartMessage(B_OK);
699 			fLink.Attach<int32>(flags);
700 			fLink.Flush();
701 			break;
702 		}
703 
704 		case AS_CREATE_PICTURE:
705 		{
706 			// TODO: Maybe rename this to AS_UPLOAD_PICTURE ?
707 			STRACE(("ServerApp %s: Create Picture\n", Signature()));
708 			status_t status = B_ERROR;
709 			ServerPicture *picture = CreatePicture();
710 			if (picture != NULL) {
711 				int32 subPicturesCount = 0;
712 				link.Read<int32>(&subPicturesCount);
713 				for (int32 c = 0; c < subPicturesCount; c++) {
714 					int32 token = -1;
715 					link.Read<int32>(&token);
716 					if (ServerPicture *subPicture = FindPicture(token))
717 						picture->NestPicture(subPicture);
718 				}
719 				status = picture->ImportData(link);
720 			}
721 			if (status == B_OK) {
722 				fLink.StartMessage(B_OK);
723 				fLink.Attach<int32>(picture->Token());
724 			} else
725 				fLink.StartMessage(B_ERROR);
726 
727 			fLink.Flush();
728 			break;
729 		}
730 
731 		case AS_DELETE_PICTURE:
732 		{
733 			STRACE(("ServerApp %s: Delete Picture\n", Signature()));
734 			int32 token;
735 			if (link.Read<int32>(&token) == B_OK)
736 				DeletePicture(token);
737 
738 			break;
739 		}
740 
741 		case AS_CLONE_PICTURE:
742 		{
743 			STRACE(("ServerApp %s: Clone Picture\n", Signature()));
744 			int32 token;
745 			ServerPicture *original = NULL;
746 			if (link.Read<int32>(&token) == B_OK)
747 				original = FindPicture(token);
748 
749 			ServerPicture *cloned = NULL;
750 			if (original != NULL)
751 				cloned = CreatePicture(original);
752 
753 			if (cloned != NULL) {
754 				fLink.StartMessage(B_OK);
755 				fLink.Attach<int32>(cloned->Token());
756 			} else
757 				fLink.StartMessage(B_ERROR);
758 
759 			fLink.Flush();
760 			break;
761 		}
762 
763 		case AS_DOWNLOAD_PICTURE:
764 		{
765 			STRACE(("ServerApp %s: Download Picture\n", Signature()));
766 			int32 token;
767 			link.Read<int32>(&token);
768 			ServerPicture *picture = FindPicture(token);
769 			if (picture != NULL) {
770 				picture->ExportData(fLink);
771 					// ExportData() calls StartMessage() already
772 			} else
773 				fLink.StartMessage(B_ERROR);
774 
775 			fLink.Flush();
776 
777 			break;
778 		}
779 
780 		case AS_COUNT_WORKSPACES:
781 		{
782 			if (fDesktop->LockSingleWindow()) {
783 				DesktopSettings settings(fDesktop);
784 
785 				fLink.StartMessage(B_OK);
786 				fLink.Attach<int32>(settings.WorkspacesCount());
787 				fDesktop->UnlockSingleWindow();
788 			} else
789 				fLink.StartMessage(B_ERROR);
790 
791 			fLink.Flush();
792 			break;
793 		}
794 
795 		case AS_SET_WORKSPACE_COUNT:
796 		{
797 			int32 newCount;
798 			if (link.Read<int32>(&newCount) == B_OK)
799 				fDesktop->SetWorkspacesCount(newCount);
800 			break;
801 		}
802 
803 		case AS_CURRENT_WORKSPACE:
804 			STRACE(("ServerApp %s: get current workspace\n", Signature()));
805 
806 			if (fDesktop->LockSingleWindow()) {
807 				fLink.StartMessage(B_OK);
808 				fLink.Attach<int32>(fDesktop->CurrentWorkspace());
809 				fDesktop->UnlockSingleWindow();
810 			} else
811 				fLink.StartMessage(B_ERROR);
812 
813 			fLink.Flush();
814 			break;
815 
816 		case AS_ACTIVATE_WORKSPACE:
817 		{
818 			STRACE(("ServerApp %s: activate workspace\n", Signature()));
819 
820 			// TODO: See above
821 			int32 index;
822 			link.Read<int32>(&index);
823 
824 			fDesktop->SetWorkspace(index);
825 			break;
826 		}
827 
828 		case AS_IDLE_TIME:
829 			STRACE(("ServerApp %s: idle time\n", Signature()));
830 
831 			fLink.StartMessage(B_OK);
832 			fLink.Attach<bigtime_t>(fDesktop->EventDispatcher().IdleTime());
833 			fLink.Flush();
834 			break;
835 
836 		case AS_SHOW_CURSOR:
837 		{
838 			STRACE(("ServerApp %s: Show Cursor\n", Signature()));
839 			fCursorHideLevel--;
840 			if (fCursorHideLevel < 0)
841 				fCursorHideLevel = 0;
842 			fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0);
843 			break;
844 		}
845 		case AS_HIDE_CURSOR:
846 		{
847 			STRACE(("ServerApp %s: Hide Cursor\n", Signature()));
848 			fCursorHideLevel++;
849 			fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0);
850 			break;
851 		}
852 		case AS_OBSCURE_CURSOR:
853 		{
854 			STRACE(("ServerApp %s: Obscure Cursor\n", Signature()));
855 			fDesktop->HWInterface()->ObscureCursor();
856 			break;
857 		}
858 		case AS_QUERY_CURSOR_HIDDEN:
859 		{
860 			STRACE(("ServerApp %s: Received IsCursorHidden request\n", Signature()));
861 			fLink.StartMessage(fCursorHideLevel > 0 ? B_OK : B_ERROR);
862 			fLink.Flush();
863 			break;
864 		}
865 		case AS_SET_CURSOR:
866 		{
867 			STRACE(("ServerApp %s: SetCursor\n", Signature()));
868 
869 			// Attached data:
870 			// 1) bool flag to send a reply
871 			// 2) int32 token ID of the cursor to set
872 			// 3) port_id port to receive a reply. Only exists if the sync flag is true.
873 			bool sync;
874 			int32 token;
875 
876 			link.Read<bool>(&sync);
877 			if (link.Read<int32>(&token) != B_OK)
878 				break;
879 
880 			if (!fDesktop->GetCursorManager().Lock())
881 				break;
882 
883 			ServerCursor* oldCursor = fAppCursor;
884 			fAppCursor = fDesktop->GetCursorManager().FindCursor(token);
885 			if (fAppCursor != NULL)
886 				fAppCursor->Acquire();
887 
888 			if (_HasWindowUnderMouse())
889 				fDesktop->SetCursor(CurrentCursor());
890 
891 			if (oldCursor != NULL)
892 				oldCursor->Release();
893 
894 			fDesktop->GetCursorManager().Unlock();
895 
896 			if (sync) {
897 				// The application is expecting a reply
898 				fLink.StartMessage(B_OK);
899 				fLink.Flush();
900 			}
901 			break;
902 		}
903 		case AS_CREATE_CURSOR:
904 		{
905 			STRACE(("ServerApp %s: Create Cursor\n", Signature()));
906 			// Attached data:
907 			// 1) 68 bytes of fAppCursor data
908 			// 2) port_id reply port
909 
910 			status_t status = B_ERROR;
911 			uint8 cursorData[68];
912 			ServerCursor* cursor = NULL;
913 
914 //			if (link.Read(cursorData, sizeof(cursorData)) >= B_OK) {
915 //				cursor = new (nothrow) ServerCursor(cursorData);
916 //				if (cursor == NULL)
917 //					status = B_NO_MEMORY;
918 //			}
919 //
920 //			if (cursor != NULL) {
921 //				cursor->SetOwningTeam(fClientTeam);
922 //				fDesktop->GetCursorManager().AddCursor(cursor);
923 //
924 //				// Synchronous message - BApplication is waiting on the cursor's ID
925 //				fLink.StartMessage(B_OK);
926 //				fLink.Attach<int32>(cursor->Token());
927 //			} else
928 //				fLink.StartMessage(status);
929 
930 			if (link.Read(cursorData, sizeof(cursorData)) >= B_OK) {
931 				cursor = fDesktop->GetCursorManager().CreateCursor(fClientTeam,
932 																   cursorData);
933 				if (cursor == NULL)
934 					status = B_NO_MEMORY;
935 			}
936 
937 			if (cursor != NULL) {
938 				// Synchronous message - BApplication is waiting on the cursor's ID
939 				fLink.StartMessage(B_OK);
940 				fLink.Attach<int32>(cursor->Token());
941 			} else
942 				fLink.StartMessage(status);
943 
944 			fLink.Flush();
945 			break;
946 		}
947 		case AS_DELETE_CURSOR:
948 		{
949 			STRACE(("ServerApp %s: Delete BCursor\n", Signature()));
950 			// Attached data:
951 			// 1) int32 token ID of the cursor to delete
952 			int32 token;
953 			bool pendingViewCursor;
954 			link.Read<int32>(&token);
955 			if (link.Read<bool>(&pendingViewCursor) != B_OK)
956 				break;
957 
958 			if (!fDesktop->GetCursorManager().Lock())
959 				break;
960 
961 			ServerCursor* cursor = fDesktop->GetCursorManager().FindCursor(token);
962 			if (cursor) {
963 				if (pendingViewCursor)
964 					cursor->SetPendingViewCursor(true);
965 
966 				cursor->Release();
967 			}
968 			fDesktop->GetCursorManager().Unlock();
969 
970 			break;
971 		}
972 
973 		case AS_GET_SCROLLBAR_INFO:
974 		{
975 			STRACE(("ServerApp %s: Get ScrollBar info\n", Signature()));
976 
977 			if (fDesktop->LockSingleWindow()) {
978 				scroll_bar_info info;
979 				DesktopSettings settings(fDesktop);
980 				settings.GetScrollBarInfo(info);
981 
982 				fLink.StartMessage(B_OK);
983 				fLink.Attach<scroll_bar_info>(info);
984 				fDesktop->UnlockSingleWindow();
985 			} else
986 				fLink.StartMessage(B_ERROR);
987 
988 				fLink.Flush();
989 			break;
990 		}
991 		case AS_SET_SCROLLBAR_INFO:
992 		{
993 			STRACE(("ServerApp %s: Set ScrollBar info\n", Signature()));
994 			// Attached Data:
995 			// 1) scroll_bar_info scroll bar info structure
996 			scroll_bar_info info;
997 			if (link.Read<scroll_bar_info>(&info) == B_OK) {
998 				LockedDesktopSettings settings(fDesktop);
999 				settings.SetScrollBarInfo(info);
1000 			}
1001 
1002 			fLink.StartMessage(B_OK);
1003 			fLink.Flush();
1004 			break;
1005 		}
1006 
1007 		case AS_GET_MENU_INFO:
1008 		{
1009 			STRACE(("ServerApp %s: Get menu info\n", Signature()));
1010 			if (fDesktop->LockSingleWindow()) {
1011 				menu_info info;
1012 				DesktopSettings settings(fDesktop);
1013 				settings.GetMenuInfo(info);
1014 
1015 				fLink.StartMessage(B_OK);
1016 				fLink.Attach<menu_info>(info);
1017 
1018 				fDesktop->UnlockSingleWindow();
1019 			} else
1020 				fLink.StartMessage(B_ERROR);
1021 
1022 			fLink.Flush();
1023 			break;
1024 		}
1025 		case AS_SET_MENU_INFO:
1026 		{
1027 			STRACE(("ServerApp %s: Set menu info\n", Signature()));
1028 			menu_info info;
1029 			if (link.Read<menu_info>(&info) == B_OK) {
1030 				LockedDesktopSettings settings(fDesktop);
1031 				settings.SetMenuInfo(info);
1032 					// TODO: SetMenuInfo() should do some validity check, so
1033 					//	that the answer we're giving can actually be useful
1034 			}
1035 
1036 			fLink.StartMessage(B_OK);
1037 			fLink.Flush();
1038 			break;
1039 		}
1040 
1041 		case AS_SET_MOUSE_MODE:
1042 		{
1043 			STRACE(("ServerApp %s: Set Focus Follows Mouse mode\n", Signature()));
1044 			// Attached Data:
1045 			// 1) enum mode_mouse FFM mouse mode
1046 			mode_mouse mouseMode;
1047 			if (link.Read<mode_mouse>(&mouseMode) == B_OK) {
1048 				LockedDesktopSettings settings(fDesktop);
1049 				settings.SetMouseMode(mouseMode);
1050 			}
1051 			break;
1052 		}
1053 		case AS_GET_MOUSE_MODE:
1054 		{
1055 			STRACE(("ServerApp %s: Get Focus Follows Mouse mode\n", Signature()));
1056 
1057 			if (fDesktop->LockSingleWindow()) {
1058 				DesktopSettings settings(fDesktop);
1059 
1060 				fLink.StartMessage(B_OK);
1061 				fLink.Attach<mode_mouse>(settings.MouseMode());
1062 
1063 				fDesktop->UnlockSingleWindow();
1064 			} else
1065 				fLink.StartMessage(B_ERROR);
1066 
1067 			fLink.Flush();
1068 			break;
1069 		}
1070 
1071 		case AS_GET_SHOW_ALL_DRAGGERS:
1072 		{
1073 			STRACE(("ServerApp %s: Get Show All Draggers\n", Signature()));
1074 
1075 			if (fDesktop->LockSingleWindow()) {
1076 				DesktopSettings settings(fDesktop);
1077 
1078 				fLink.StartMessage(B_OK);
1079 				fLink.Attach<bool>(settings.ShowAllDraggers());
1080 
1081 				fDesktop->UnlockSingleWindow();
1082 			} else
1083 				fLink.StartMessage(B_ERROR);
1084 
1085 			fLink.Flush();
1086 			break;
1087 		}
1088 
1089 		case AS_SET_SHOW_ALL_DRAGGERS:
1090 		{
1091 			STRACE(("ServerApp %s: Set Show All Draggers\n", Signature()));
1092 
1093 			bool changed = false;
1094 			bool show;
1095 			if (link.Read<bool>(&show) == B_OK) {
1096 				LockedDesktopSettings settings(fDesktop);
1097 				if (show != settings.ShowAllDraggers()) {
1098 					settings.SetShowAllDraggers(show);
1099 					changed = true;
1100 				}
1101 			}
1102 
1103 			if (changed)
1104 				fDesktop->BroadcastToAllApps(kMsgUpdateShowAllDraggers);
1105 			break;
1106 		}
1107 
1108 		case kMsgUpdateShowAllDraggers:
1109 		{
1110 			bool show = false;
1111 			if (fDesktop->LockSingleWindow()) {
1112 				DesktopSettings settings(fDesktop);
1113 				show = settings.ShowAllDraggers();
1114 				fDesktop->UnlockSingleWindow();
1115 			}
1116 			BMessage update(_SHOW_DRAG_HANDLES_);
1117 			update.AddBool("show", show);
1118 
1119 			SendMessageToClient(&update);
1120 			break;
1121 		}
1122 
1123 		/* font messages */
1124 
1125 		case AS_SET_SYSTEM_FONT:
1126 		{
1127 			// gets:
1128 			//	1) string - font type ("plain", ...)
1129 			//	2) string - family
1130 			//	3) string - style
1131 			//	4) float - size
1132 
1133 			char type[B_OS_NAME_LENGTH];
1134 			font_family familyName;
1135 			font_style styleName;
1136 			float size;
1137 
1138 			if (link.ReadString(type, sizeof(type)) == B_OK
1139 				&& link.ReadString(familyName, sizeof(familyName)) == B_OK
1140 				&& link.ReadString(styleName, sizeof(styleName)) == B_OK
1141 				&& link.Read<float>(&size) == B_OK) {
1142 				gFontManager->Lock();
1143 
1144 				FontStyle* style = gFontManager->GetStyle(familyName, styleName);
1145 				if (style != NULL) {
1146 					ServerFont font(*style, size);
1147 					gFontManager->Unlock();
1148 						// We must not have locked the font manager when
1149 						// locking the desktop (through LockedDesktopSettings
1150 						// below)
1151 
1152 					LockedDesktopSettings settings(fDesktop);
1153 
1154 					if (!strcmp(type, "plain"))
1155 						settings.SetDefaultPlainFont(font);
1156 					else if (!strcmp(type, "bold"))
1157 						settings.SetDefaultBoldFont(font);
1158 					else if (!strcmp(type, "fixed"))
1159 						settings.SetDefaultFixedFont(font);
1160 				} else
1161 					gFontManager->Unlock();
1162 			}
1163 			break;
1164 		}
1165 		case AS_GET_SYSTEM_DEFAULT_FONT:
1166 		{
1167 			// input:
1168 			//	1) string - font type ("plain", ...)
1169 
1170 			ServerFont font;
1171 
1172 			char type[B_OS_NAME_LENGTH];
1173 			status_t status = link.ReadString(type, sizeof(type));
1174 			if (status == B_OK) {
1175 				if (!strcmp(type, "plain")) {
1176 					font = *gFontManager->DefaultPlainFont();
1177 				} else if (!strcmp(type, "bold")) {
1178 					font = *gFontManager->DefaultBoldFont();
1179 				} else if (!strcmp(type, "fixed")) {
1180 					font = *gFontManager->DefaultFixedFont();
1181 				} else
1182 					status = B_BAD_VALUE;
1183 			}
1184 
1185 			if (status == B_OK) {
1186 				// returns:
1187 				//	1) string - family
1188 				//	2) string - style
1189 				//	3) float - size
1190 
1191 				fLink.StartMessage(B_OK);
1192 				fLink.AttachString(font.Family());
1193 				fLink.AttachString(font.Style());
1194 				fLink.Attach<float>(font.Size());
1195 			} else
1196 				fLink.StartMessage(status);
1197 
1198 			fLink.Flush();
1199 			break;
1200 		}
1201 		case AS_GET_SYSTEM_FONTS:
1202 		{
1203 			FTRACE(("ServerApp %s: AS_GET_SYSTEM_FONTS\n", Signature()));
1204 			// Returns:
1205 			// 1) uint16 - family ID
1206 			// 2) uint16 - style ID
1207 			// 3) float - size in points
1208 			// 4) uint16 - face flags
1209 			// 5) uint32 - font flags
1210 
1211 			if (!fDesktop->LockSingleWindow()) {
1212 				fLink.StartMessage(B_OK);
1213 				fLink.Flush();
1214 				break;
1215 			}
1216 
1217 			DesktopSettings settings(fDesktop);
1218 			fLink.StartMessage(B_OK);
1219 
1220 			for (int32 i = 0; i < 3; i++) {
1221 				ServerFont font;
1222 				switch (i) {
1223 					case 0:
1224 						settings.GetDefaultPlainFont(font);
1225 						fLink.AttachString("plain");
1226 						break;
1227 					case 1:
1228 						settings.GetDefaultBoldFont(font);
1229 						fLink.AttachString("bold");
1230 						break;
1231 					case 2:
1232 						settings.GetDefaultFixedFont(font);
1233 						fLink.AttachString("fixed");
1234 						break;
1235 				}
1236 
1237 				fLink.Attach<uint16>(font.FamilyID());
1238 				fLink.Attach<uint16>(font.StyleID());
1239 				fLink.Attach<float>(font.Size());
1240 				fLink.Attach<uint16>(font.Face());
1241 				fLink.Attach<uint32>(font.Flags());
1242 			}
1243 
1244 			fDesktop->UnlockSingleWindow();
1245 			fLink.Flush();
1246 			break;
1247 		}
1248 		case AS_GET_FONT_LIST_REVISION:
1249 		{
1250 			STRACE(("ServerApp %s: AS_GET_FONT_LIST_REVISION\n", Signature()));
1251 
1252 			fLink.StartMessage(B_OK);
1253 			fLink.Attach<int32>(gFontManager->CheckRevision(fDesktop->UserID()));
1254 			fLink.Flush();
1255 			break;
1256 		}
1257 		case AS_GET_FAMILY_AND_STYLES:
1258 		{
1259 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLES\n", Signature()));
1260 			// Attached Data:
1261 			// 1) int32 the index of the font family to get
1262 
1263 			// Returns:
1264 			// 1) string - name of family
1265 			// 2) uint32 - flags of font family (B_IS_FIXED || B_HAS_TUNED_FONT)
1266 			// 3) count of styles in that family
1267 			// For each style:
1268 			//		1) string - name of style
1269 			//		2) uint16 - face of style
1270 			//		3) uint32 - flags of style
1271 
1272 			int32 index;
1273 			link.Read<int32>(&index);
1274 
1275 			gFontManager->Lock();
1276 
1277 			FontFamily* family = gFontManager->FamilyAt(index);
1278 			if (family) {
1279 				fLink.StartMessage(B_OK);
1280 				fLink.AttachString(family->Name());
1281 				fLink.Attach<uint32>(family->Flags());
1282 
1283 				int32 count = family->CountStyles();
1284 				fLink.Attach<int32>(count);
1285 
1286 				for (int32 i = 0; i < count; i++) {
1287 					FontStyle* style = family->StyleAt(i);
1288 
1289 					fLink.AttachString(style->Name());
1290 					fLink.Attach<uint16>(style->Face());
1291 					fLink.Attach<uint32>(style->Flags());
1292 				}
1293 			} else
1294 				fLink.StartMessage(B_BAD_VALUE);
1295 
1296 			gFontManager->Unlock();
1297 			fLink.Flush();
1298 			break;
1299 		}
1300 		case AS_GET_FAMILY_AND_STYLE:
1301 		{
1302 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE\n", Signature()));
1303 			// Attached Data:
1304 			// 1) uint16 - family ID
1305 			// 2) uint16 - style ID
1306 
1307 			// Returns:
1308 			// 1) font_family The name of the font family
1309 			// 2) font_style - name of the style
1310 			uint16 familyID, styleID;
1311 			link.Read<uint16>(&familyID);
1312 			link.Read<uint16>(&styleID);
1313 
1314 			gFontManager->Lock();
1315 
1316 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1317 			if (fontStyle != NULL) {
1318 				fLink.StartMessage(B_OK);
1319 				fLink.AttachString(fontStyle->Family()->Name());
1320 				fLink.AttachString(fontStyle->Name());
1321 			} else
1322 				fLink.StartMessage(B_BAD_VALUE);
1323 
1324 			fLink.Flush();
1325 			gFontManager->Unlock();
1326 			break;
1327 		}
1328 		case AS_GET_FAMILY_AND_STYLE_IDS:
1329 		{
1330 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE_IDS\n", Signature()));
1331 			// Attached Data:
1332 			// 1) font_family - name of font family to use
1333 			// 2) font_style - name of style in family
1334 			// 3) family ID - only used if 1) is empty
1335 			// 4) style ID - only used if 2) is empty
1336 			// 5) face - the font's current face
1337 
1338 			// Returns:
1339 			// 1) uint16 - family ID
1340 			// 2) uint16 - style ID
1341 			// 3) uint16 - face
1342 
1343 			font_family family;
1344 			font_style style;
1345 			uint16 familyID, styleID;
1346 			uint16 face;
1347 			if (link.ReadString(family, sizeof(font_family)) == B_OK
1348 				&& link.ReadString(style, sizeof(font_style)) == B_OK
1349 				&& link.Read<uint16>(&familyID) == B_OK
1350 				&& link.Read<uint16>(&styleID) == B_OK
1351 				&& link.Read<uint16>(&face) == B_OK) {
1352 				// get the font and return IDs and face
1353 				gFontManager->Lock();
1354 
1355 				FontStyle *fontStyle = gFontManager->GetStyle(family, style,
1356 					familyID, styleID, face);
1357 
1358 				if (fontStyle != NULL) {
1359 					fLink.StartMessage(B_OK);
1360 					fLink.Attach<uint16>(fontStyle->Family()->ID());
1361 					fLink.Attach<uint16>(fontStyle->ID());
1362 
1363 					// we try to keep the font face close to what we got
1364 					face = fontStyle->PreservedFace(face);
1365 
1366 					fLink.Attach<uint16>(face);
1367 				} else
1368 					fLink.StartMessage(B_NAME_NOT_FOUND);
1369 
1370 				gFontManager->Unlock();
1371 			} else
1372 				fLink.StartMessage(B_BAD_VALUE);
1373 
1374 			fLink.Flush();
1375 			break;
1376 		}
1377 		case AS_GET_FONT_FILE_FORMAT:
1378 		{
1379 			FTRACE(("ServerApp %s: AS_GET_FONT_FILE_FORMAT\n", Signature()));
1380 			// Attached Data:
1381 			// 1) uint16 - family ID
1382 			// 2) uint16 - style ID
1383 
1384 			// Returns:
1385 			// 1) uint16 font_file_format of font
1386 
1387 			int32 familyID, styleID;
1388 			link.Read<int32>(&familyID);
1389 			link.Read<int32>(&styleID);
1390 
1391 			gFontManager->Lock();
1392 
1393 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1394 			if (fontStyle) {
1395 				fLink.StartMessage(B_OK);
1396 				fLink.Attach<uint16>((uint16)fontStyle->FileFormat());
1397 			} else
1398 				fLink.StartMessage(B_BAD_VALUE);
1399 
1400 			gFontManager->Unlock();
1401 			fLink.Flush();
1402 			break;
1403 		}
1404 		case AS_GET_STRING_WIDTHS:
1405 		{
1406 			FTRACE(("ServerApp %s: AS_GET_STRING_WIDTHS\n", Signature()));
1407 			// Attached Data:
1408 			// 1) uint16 ID of family
1409 			// 2) uint16 ID of style
1410 			// 3) float point size of font
1411 			// 4) uint8 spacing to use
1412 			// 5) int32 numStrings
1413 			// 6) int32 string length to measure (numStrings times)
1414 			// 7) string String to measure (numStrings times)
1415 
1416 			// Returns:
1417 			// 1) float - width of the string in pixels (numStrings times)
1418 
1419 			uint16 family, style;
1420 			float size;
1421 			uint8 spacing;
1422 
1423 			link.Read<uint16>(&family);
1424 			link.Read<uint16>(&style);
1425 			link.Read<float>(&size);
1426 			link.Read<uint8>(&spacing);
1427 			int32 numStrings;
1428 			if (link.Read<int32>(&numStrings) != B_OK) {
1429 				// this results in a B_BAD_VALUE return
1430 				numStrings = 0;
1431 				size = 0.0f;
1432 			}
1433 
1434 			// TODO: don't use the stack for this - numStrings could be large
1435 			float widthArray[numStrings];
1436 			int32 lengthArray[numStrings];
1437 			char *stringArray[numStrings];
1438 			for (int32 i = 0; i < numStrings; i++) {
1439 				// This version of ReadString allocates the strings, we free
1440 				// them below
1441 				link.ReadString(&stringArray[i], (size_t *)&lengthArray[i]);
1442 			}
1443 
1444 			ServerFont font;
1445 
1446 			if (font.SetFamilyAndStyle(family, style) == B_OK && size > 0) {
1447 				font.SetSize(size);
1448 				font.SetSpacing(spacing);
1449 
1450 				for (int32 i = 0; i < numStrings; i++) {
1451 					if (!stringArray[i] || lengthArray[i] <= 0)
1452 						widthArray[i] = 0.0;
1453 					else {
1454 						widthArray[i] = font.StringWidth(stringArray[i],
1455 							lengthArray[i]);
1456 					}
1457 				}
1458 
1459 				fLink.StartMessage(B_OK);
1460 				fLink.Attach(widthArray, sizeof(widthArray));
1461 			} else
1462 				fLink.StartMessage(B_BAD_VALUE);
1463 
1464 			fLink.Flush();
1465 
1466 			for (int32 i = 0; i < numStrings; i++) {
1467 				free(stringArray[i]);
1468 			}
1469 			break;
1470 		}
1471 		case AS_GET_FONT_BOUNDING_BOX:
1472 		{
1473 			FTRACE(("ServerApp %s: AS_GET_BOUNDING_BOX unimplemented\n",
1474 				Signature()));
1475 			// Attached Data:
1476 			// 1) uint16 - family ID
1477 			// 2) uint16 - style ID
1478 
1479 			// Returns:
1480 			// 1) BRect - box holding entire font
1481 
1482 			// ToDo: implement me!
1483 			fLink.StartMessage(B_ERROR);
1484 			fLink.Flush();
1485 			break;
1486 		}
1487 		case AS_GET_TUNED_COUNT:
1488 		{
1489 			FTRACE(("ServerApp %s: AS_GET_TUNED_COUNT\n", Signature()));
1490 			// Attached Data:
1491 			// 1) uint16 - family ID
1492 			// 2) uint16 - style ID
1493 
1494 			// Returns:
1495 			// 1) int32 - number of font strikes available
1496 			uint16 familyID, styleID;
1497 			link.Read<uint16>(&familyID);
1498 			link.Read<uint16>(&styleID);
1499 
1500 			gFontManager->Lock();
1501 
1502 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1503 			if (fontStyle != NULL) {
1504 				fLink.StartMessage(B_OK);
1505 				fLink.Attach<int32>(fontStyle->TunedCount());
1506 			} else
1507 				fLink.StartMessage(B_BAD_VALUE);
1508 
1509 			gFontManager->Unlock();
1510 			fLink.Flush();
1511 			break;
1512 		}
1513 		case AS_GET_TUNED_INFO:
1514 		{
1515 			FTRACE(("ServerApp %s: AS_GET_TUNED_INFO unimplmemented\n",
1516 				Signature()));
1517 			// Attached Data:
1518 			// 1) uint16 - family ID
1519 			// 2) uint16 - style ID
1520 			// 3) uint32 - index of the particular font strike
1521 
1522 			// Returns:
1523 			// 1) tuned_font_info - info on the strike specified
1524 			// ToDo: implement me!
1525 			fLink.StartMessage(B_ERROR);
1526 			fLink.Flush();
1527 			break;
1528 		}
1529 		case AS_GET_EXTRA_FONT_FLAGS:
1530 		{
1531 			FTRACE(("ServerApp %s: AS_GET_EXTRA_FONT_FLAGS\n",
1532 				Signature()));
1533 			// Attached Data:
1534 			// 1) uint16 - family ID
1535 			// 2) uint16 - style ID
1536 
1537 			// Returns:
1538 			// 1) uint32 - extra font flags
1539 			uint16 familyID, styleID;
1540 			link.Read<uint16>(&familyID);
1541 			link.Read<uint16>(&styleID);
1542 
1543 			gFontManager->Lock();
1544 
1545 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1546 			if (fontStyle != NULL) {
1547 				fLink.StartMessage(B_OK);
1548 				fLink.Attach<uint32>(fontStyle->Flags());
1549 			} else
1550 				fLink.StartMessage(B_BAD_VALUE);
1551 
1552 			gFontManager->Unlock();
1553 			fLink.Flush();
1554 			break;
1555 		}
1556 		case AS_GET_FONT_HEIGHT:
1557 		{
1558 			FTRACE(("ServerApp %s: AS_GET_FONT_HEIGHT\n", Signature()));
1559 			// Attached Data:
1560 			// 1) uint16 family ID
1561 			// 2) uint16 style ID
1562 			// 3) float size
1563 			uint16 familyID, styleID;
1564 			float size;
1565 			link.Read<uint16>(&familyID);
1566 			link.Read<uint16>(&styleID);
1567 			link.Read<float>(&size);
1568 
1569 			gFontManager->Lock();
1570 
1571 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1572 			if (fontStyle != NULL) {
1573 				font_height height;
1574 				fontStyle->GetHeight(size, height);
1575 
1576 				fLink.StartMessage(B_OK);
1577 				fLink.Attach<font_height>(height);
1578 			} else
1579 				fLink.StartMessage(B_BAD_VALUE);
1580 
1581 			gFontManager->Unlock();
1582 			fLink.Flush();
1583 			break;
1584 		}
1585 		case AS_GET_GLYPH_SHAPES:
1586 		{
1587 			FTRACE(("ServerApp %s: AS_GET_GLYPH_SHAPES\n", Signature()));
1588 			// Attached Data:
1589 			// 1) uint16 - family ID
1590 			// 2) uint16 - style ID
1591 			// 3) float - point size
1592 			// 4) float - shear
1593 			// 5) float - rotation
1594 			// 6) float - false bold width
1595 			// 6) uint32 - flags
1596 			// 7) int32 - numChars
1597 			// 8) int32 - numBytes
1598 			// 8) char - chars (bytesInBuffer times)
1599 
1600 			// Returns:
1601 			// 1) BShape - glyph shape
1602 			// numChars times
1603 
1604 			uint16 familyID, styleID;
1605 			uint32 flags;
1606 			float size, shear, rotation, falseBoldWidth;
1607 
1608 			link.Read<uint16>(&familyID);
1609 			link.Read<uint16>(&styleID);
1610 			link.Read<float>(&size);
1611 			link.Read<float>(&shear);
1612 			link.Read<float>(&rotation);
1613 			link.Read<float>(&falseBoldWidth);
1614 			link.Read<uint32>(&flags);
1615 
1616 			int32 numChars, numBytes;
1617 			link.Read<int32>(&numChars);
1618 			link.Read<int32>(&numBytes);
1619 
1620 			// TODO: proper error checking
1621 			char* charArray = new (nothrow) char[numBytes];
1622 			link.Read(charArray, numBytes);
1623 
1624 			ServerFont font;
1625 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1626 			if (status == B_OK) {
1627 				font.SetSize(size);
1628 				font.SetShear(shear);
1629 				font.SetRotation(rotation);
1630 				font.SetFalseBoldWidth(falseBoldWidth);
1631 				font.SetFlags(flags);
1632 
1633 				// TODO: proper error checking
1634 				BShape** shapes = new (nothrow) BShape*[numChars];
1635 				status = font.GetGlyphShapes(charArray, numChars, shapes);
1636 				if (status == B_OK) {
1637 					fLink.StartMessage(B_OK);
1638 					for (int32 i = 0; i < numChars; i++) {
1639 						fLink.AttachShape(*shapes[i]);
1640 						delete shapes[i];
1641 					}
1642 				} else
1643 					fLink.StartMessage(status);
1644 
1645 				delete[] shapes;
1646 			} else
1647 				fLink.StartMessage(status);
1648 
1649 			delete[] charArray;
1650 			fLink.Flush();
1651 			break;
1652 		}
1653 		case AS_GET_HAS_GLYPHS:
1654 		{
1655 			FTRACE(("ServerApp %s: AS_GET_HAS_GLYPHS\n", Signature()));
1656 			// Attached Data:
1657 			// 1) uint16 - family ID
1658 			// 2) uint16 - style ID
1659 			// 3) int32 - numChars
1660 			// 4) int32 - numBytes
1661 			// 5) char - the char buffer with size numBytes
1662 
1663 			uint16 familyID, styleID;
1664 			link.Read<uint16>(&familyID);
1665 			link.Read<uint16>(&styleID);
1666 
1667 			int32 numChars, numBytes;
1668 			link.Read<int32>(&numChars);
1669 			link.Read<int32>(&numBytes);
1670 			// TODO: proper error checking
1671 			char* charArray = new (nothrow) char[numBytes];
1672 			link.Read(charArray, numBytes);
1673 
1674 			ServerFont font;
1675 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1676 			if (status == B_OK) {
1677 				bool hasArray[numChars];
1678 				status = font.GetHasGlyphs(charArray, numBytes, hasArray);
1679 				if (status == B_OK) {
1680 					fLink.StartMessage(B_OK);
1681 					fLink.Attach(hasArray, sizeof(hasArray));
1682 				} else
1683 					fLink.StartMessage(status);
1684 			} else
1685 				fLink.StartMessage(status);
1686 
1687 			delete[] charArray;
1688 			fLink.Flush();
1689 			break;
1690 		}
1691 		case AS_GET_EDGES:
1692 		{
1693 			FTRACE(("ServerApp %s: AS_GET_EDGES\n", Signature()));
1694 			// Attached Data:
1695 			// 1) uint16 - family ID
1696 			// 2) uint16 - style ID
1697 			// 3) int32 - numChars
1698 			// 4) int32 - numBytes
1699 			// 5) char - the char buffer with size numBytes
1700 
1701 			uint16 familyID, styleID;
1702 			link.Read<uint16>(&familyID);
1703 			link.Read<uint16>(&styleID);
1704 
1705 			int32 numChars;
1706 			link.Read<int32>(&numChars);
1707 
1708 			uint32 numBytes;
1709 			link.Read<uint32>(&numBytes);
1710 			// TODO: proper error checking
1711 			char* charArray = new (nothrow) char[numBytes];
1712 			link.Read(charArray, numBytes);
1713 
1714 			ServerFont font;
1715 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1716 			if (status == B_OK) {
1717 				edge_info edgeArray[numChars];
1718 				status = font.GetEdges(charArray, numBytes, edgeArray);
1719 				if (status == B_OK) {
1720 					fLink.StartMessage(B_OK);
1721 					fLink.Attach(edgeArray, sizeof(edgeArray));
1722 				} else
1723 					fLink.StartMessage(status);
1724 			} else
1725 				fLink.StartMessage(status);
1726 
1727 			delete[] charArray;
1728 			fLink.Flush();
1729 			break;
1730 		}
1731 		case AS_GET_ESCAPEMENTS:
1732 		{
1733 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS\n", Signature()));
1734 			// Attached Data:
1735 			// 1) uint16 - family ID
1736 			// 2) uint16 - style ID
1737 			// 3) float - point size
1738 			// 4) uint8 - spacing
1739 			// 5) float - rotation
1740 			// 6) uint32 - flags
1741 			// 7) int32 - numChars
1742 			// 8) char - char     -\       both
1743 			// 9) BPoint - offset -/ (numChars times)
1744 
1745 			// Returns:
1746 			// 1) BPoint - escapement
1747 			// numChars times
1748 
1749 			uint16 familyID, styleID;
1750 			uint32 flags;
1751 			float size, rotation;
1752 			uint8 spacing;
1753 
1754 			link.Read<uint16>(&familyID);
1755 			link.Read<uint16>(&styleID);
1756 			link.Read<float>(&size);
1757 			link.Read<uint8>(&spacing);
1758 			link.Read<float>(&rotation);
1759 			link.Read<uint32>(&flags);
1760 
1761 			escapement_delta delta;
1762 			link.Read<float>(&delta.nonspace);
1763 			link.Read<float>(&delta.space);
1764 
1765 			bool wantsOffsets;
1766 			link.Read<bool>(&wantsOffsets);
1767 
1768 			int32 numChars;
1769 			link.Read<int32>(&numChars);
1770 
1771 			uint32 numBytes;
1772 			link.Read<uint32>(&numBytes);
1773 
1774 			char *charArray = new (nothrow) char[numBytes];
1775 			BPoint *escapements = new (nothrow) BPoint[numChars];
1776 			BPoint *offsets = NULL;
1777 			if (wantsOffsets)
1778 				offsets = new (nothrow) BPoint[numChars];
1779 
1780 			if (charArray == NULL || escapements == NULL
1781 				|| (offsets == NULL && wantsOffsets)) {
1782 				delete[] charArray;
1783 				delete[] escapements;
1784 				delete[] offsets;
1785 
1786 				fLink.StartMessage(B_NO_MEMORY);
1787 				fLink.Flush();
1788 				break;
1789 			}
1790 
1791 			link.Read(charArray, numBytes);
1792 
1793 			ServerFont font;
1794 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1795 			if (status == B_OK) {
1796 				font.SetSize(size);
1797 				font.SetSpacing(spacing);
1798 				font.SetRotation(rotation);
1799 				font.SetFlags(flags);
1800 
1801 				status = font.GetEscapements(charArray, numBytes, numChars,
1802 					delta, escapements, offsets);
1803 
1804 				if (status == B_OK) {
1805 					fLink.StartMessage(B_OK);
1806 					for (int32 i = 0; i < numChars; i++)
1807 						fLink.Attach<BPoint>(escapements[i]);
1808 
1809 					if (offsets) {
1810 						for (int32 i = 0; i < numChars; i++)
1811 							fLink.Attach<BPoint>(offsets[i]);
1812 					}
1813 				} else
1814 					fLink.StartMessage(status);
1815 
1816 				delete[] escapements;
1817 				delete[] offsets;
1818 			} else
1819 				fLink.StartMessage(status);
1820 
1821 			delete[] charArray;
1822 			fLink.Flush();
1823 			break;
1824 		}
1825 		case AS_GET_ESCAPEMENTS_AS_FLOATS:
1826 		{
1827 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS_AS_FLOATS\n", Signature()));
1828 			// Attached Data:
1829 			// 1) uint16 - family ID
1830 			// 2) uint16 - style ID
1831 			// 3) float - point size
1832 			// 4) uint8 - spacing
1833 			// 5) float - rotation
1834 			// 6) uint32 - flags
1835 
1836 			// 7) float - additional "nonspace" delta
1837 			// 8) float - additional "space" delta
1838 
1839 			// 9) int32 - numChars
1840 			// 10) int32 - numBytes
1841 			// 11) char - the char buffer with size numBytes
1842 
1843 			// Returns:
1844 			// 1) float - escapement buffer with numChar entries
1845 
1846 			uint16 familyID, styleID;
1847 			uint32 flags;
1848 			float size, rotation;
1849 			uint8 spacing;
1850 
1851 			link.Read<uint16>(&familyID);
1852 			link.Read<uint16>(&styleID);
1853 			link.Read<float>(&size);
1854 			link.Read<uint8>(&spacing);
1855 			link.Read<float>(&rotation);
1856 			link.Read<uint32>(&flags);
1857 
1858 			escapement_delta delta;
1859 			link.Read<float>(&delta.nonspace);
1860 			link.Read<float>(&delta.space);
1861 
1862 			int32 numChars;
1863 			link.Read<int32>(&numChars);
1864 
1865 			uint32 numBytes;
1866 			link.Read<uint32>(&numBytes);
1867 
1868 			char* charArray = new (nothrow) char[numBytes];
1869 			float* escapements = new (nothrow) float[numChars];
1870 			if (charArray == NULL || escapements == NULL) {
1871 				delete[] charArray;
1872 				delete[] escapements;
1873 				fLink.StartMessage(B_NO_MEMORY);
1874 				fLink.Flush();
1875 				break;
1876 			}
1877 
1878 			link.Read(charArray, numBytes);
1879 
1880 			// figure out escapements
1881 
1882 			ServerFont font;
1883 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1884 			if (status == B_OK) {
1885 				font.SetSize(size);
1886 				font.SetSpacing(spacing);
1887 				font.SetRotation(rotation);
1888 				font.SetFlags(flags);
1889 
1890 				status = font.GetEscapements(charArray, numBytes, numChars,
1891 					delta, escapements);
1892 
1893 				if (status == B_OK) {
1894 					fLink.StartMessage(B_OK);
1895 					fLink.Attach(escapements, numChars * sizeof(float));
1896 				}
1897 			}
1898 
1899 			delete[] charArray;
1900 			delete[] escapements;
1901 
1902 			if (status != B_OK)
1903 				fLink.StartMessage(status);
1904 
1905 			fLink.Flush();
1906 			break;
1907 		}
1908 		case AS_GET_BOUNDINGBOXES_CHARS:
1909 		case AS_GET_BOUNDINGBOXES_STRING:
1910 		{
1911 			FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_CHARS\n", Signature()));
1912 			// Attached Data:
1913 			// 1) uint16 - family ID
1914 			// 2) uint16 - style ID
1915 			// 3) float - point size
1916 			// 4) float - rotation
1917 			// 5) float - shear
1918 			// 6) float - false bold width
1919 			// 7) uint8 - spacing
1920 			// 8) uint32 - flags
1921 
1922 			// 9) font_metric_mode - mode
1923 			// 10) bool - string escapement
1924 
1925 			// 11) escapement_delta - additional delta
1926 
1927 			// 12) int32 - numChars
1928 			// 13) int32 - numBytes
1929 			// 14) char - the char buffer with size numBytes
1930 
1931 			// Returns:
1932 			// 1) BRect - rects with numChar entries
1933 
1934 			uint16 famid, styid;
1935 			uint32 flags;
1936 			float ptsize, rotation, shear, falseBoldWidth;
1937 			uint8 spacing;
1938 			font_metric_mode mode;
1939 			bool string_escapement;
1940 
1941 			link.Read<uint16>(&famid);
1942 			link.Read<uint16>(&styid);
1943 			link.Read<float>(&ptsize);
1944 			link.Read<float>(&rotation);
1945 			link.Read<float>(&shear);
1946 			link.Read<float>(&falseBoldWidth);
1947 			link.Read<uint8>(&spacing);
1948 			link.Read<uint32>(&flags);
1949 			link.Read<font_metric_mode>(&mode);
1950 			link.Read<bool>(&string_escapement);
1951 
1952 			escapement_delta delta;
1953 			link.Read<escapement_delta>(&delta);
1954 
1955 			int32 numChars;
1956 			link.Read<int32>(&numChars);
1957 
1958 			uint32 numBytes;
1959 			link.Read<uint32>(&numBytes);
1960 
1961 			// TODO: proper error checking
1962 			char *charArray = new (nothrow) char[numBytes];
1963 			link.Read(charArray, numBytes);
1964 
1965 			BRect rectArray[numChars];
1966 			// figure out escapements
1967 
1968 			ServerFont font;
1969 			bool success = false;
1970 			if (font.SetFamilyAndStyle(famid, styid) == B_OK) {
1971 				font.SetSize(ptsize);
1972 				font.SetRotation(rotation);
1973 				font.SetShear(shear);
1974 				font.SetFalseBoldWidth(falseBoldWidth);
1975 				font.SetSpacing(spacing);
1976 				font.SetFlags(flags);
1977 
1978 				// TODO implement for real
1979 				if (font.GetBoundingBoxes(charArray, numBytes,
1980 					rectArray, string_escapement, mode, delta,
1981 					code == AS_GET_BOUNDINGBOXES_STRING) == B_OK) {
1982 					fLink.StartMessage(B_OK);
1983 					fLink.Attach(rectArray, sizeof(rectArray));
1984 					success = true;
1985 				}
1986 			}
1987 
1988 			if (!success)
1989 				fLink.StartMessage(B_ERROR);
1990 
1991 			delete[] charArray;
1992 			fLink.Flush();
1993 			break;
1994 		}
1995 		case AS_GET_BOUNDINGBOXES_STRINGS:
1996 		{
1997 			FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_STRINGS\n", Signature()));
1998 			// Attached Data:
1999 			// 1) uint16 - family ID
2000 			// 2) uint16 - style ID
2001 			// 3) float - point size
2002 			// 4) float - rotation
2003 			// 5) float - shear
2004 			// 6) float - false bold width
2005 			// 7) uint8 - spacing
2006 			// 8) uint32 - flags
2007 
2008 			// 9) font_metric_mode - mode
2009 			// 10) int32 numStrings
2010 
2011 			// 11) escapement_delta - additional delta (numStrings times)
2012 			// 12) int32 string length to measure (numStrings times)
2013 			// 13) string - string (numStrings times)
2014 
2015 			// Returns:
2016 			// 1) BRect - rects with numStrings entries
2017 
2018 			uint16 famid, styid;
2019 			uint32 flags;
2020 			float ptsize, rotation, shear, falseBoldWidth;
2021 			uint8 spacing;
2022 			font_metric_mode mode;
2023 
2024 			link.Read<uint16>(&famid);
2025 			link.Read<uint16>(&styid);
2026 			link.Read<float>(&ptsize);
2027 			link.Read<float>(&rotation);
2028 			link.Read<float>(&shear);
2029 			link.Read<float>(&falseBoldWidth);
2030 			link.Read<uint8>(&spacing);
2031 			link.Read<uint32>(&flags);
2032 			link.Read<font_metric_mode>(&mode);
2033 
2034 			int32 numStrings;
2035 			link.Read<int32>(&numStrings);
2036 
2037 			escapement_delta deltaArray[numStrings];
2038 			char *stringArray[numStrings];
2039 			int32 lengthArray[numStrings];
2040 			for(int32 i=0; i<numStrings; i++) {
2041 				// This version of ReadString allocates the strings, we free them below
2042 				link.ReadString(&stringArray[i], (size_t *)&lengthArray[i]);
2043 				link.Read<escapement_delta>(&deltaArray[i]);
2044 			}
2045 
2046 			BRect rectArray[numStrings];
2047 
2048 			ServerFont font;
2049 			bool success = false;
2050 			if (font.SetFamilyAndStyle(famid, styid) == B_OK) {
2051 				font.SetSize(ptsize);
2052 				font.SetRotation(rotation);
2053 				font.SetShear(shear);
2054 				font.SetFalseBoldWidth(falseBoldWidth);
2055 				font.SetSpacing(spacing);
2056 				font.SetFlags(flags);
2057 
2058 				if (font.GetBoundingBoxesForStrings(stringArray, lengthArray,
2059 					numStrings, rectArray, mode, deltaArray) == B_OK) {
2060 					fLink.StartMessage(B_OK);
2061 					fLink.Attach(rectArray, sizeof(rectArray));
2062 					success = true;
2063 				}
2064 			}
2065 
2066 			for (int32 i = 0; i < numStrings; i++)
2067 				free(stringArray[i]);
2068 
2069 			if (!success)
2070 				fLink.StartMessage(B_ERROR);
2071 
2072 			fLink.Flush();
2073 			break;
2074 		}
2075 
2076 		/* screen commands */
2077 
2078 		case AS_VALID_SCREEN_ID:
2079 		{
2080 			// Attached data
2081 			// 1) screen_id screen
2082 			screen_id id;
2083 			if (link.Read<screen_id>(&id) == B_OK
2084 				&& id.id == B_MAIN_SCREEN_ID.id)
2085 				fLink.StartMessage(B_OK);
2086 			else
2087 				fLink.StartMessage(B_ERROR);
2088 
2089 			fLink.Flush();
2090 			break;
2091 		}
2092 
2093 		case AS_GET_NEXT_SCREEN_ID:
2094 		{
2095 			// Attached data
2096 			// 1) screen_id screen
2097 			screen_id id;
2098 			link.Read<screen_id>(&id);
2099 
2100 			// TODO: for now, just say we're the last one
2101 			fLink.StartMessage(B_ENTRY_NOT_FOUND);
2102 			fLink.Flush();
2103 			break;
2104 		}
2105 
2106 		case AS_GET_SCREEN_ID_FROM_WINDOW:
2107 		{
2108 			status_t status = B_ENTRY_NOT_FOUND;
2109 
2110 			// Attached data
2111 			// 1) int32 - window client token
2112 			int32 clientToken;
2113 			if (link.Read<int32>(&clientToken) != B_OK)
2114 				status = B_BAD_DATA;
2115 			else {
2116 				BAutolock locker(fWindowListLock);
2117 
2118 				for (int32 i = fWindowList.CountItems(); i-- > 0;) {
2119 					ServerWindow* window = fWindowList.ItemAt(i);
2120 
2121 					if (window->ClientToken() == clientToken) {
2122 						// got it!
2123 						fLink.StartMessage(B_OK);
2124 						fLink.Attach<screen_id>(B_MAIN_SCREEN_ID);
2125 							// TODO: for now...
2126 						status = B_OK;
2127 					}
2128 				}
2129 			}
2130 
2131 			if (status != B_OK)
2132 				fLink.StartMessage(status);
2133 			fLink.Flush();
2134 			break;
2135 		}
2136 
2137 		case AS_SCREEN_GET_MODE:
2138 		{
2139 			STRACE(("ServerApp %s: AS_SCREEN_GET_MODE\n", Signature()));
2140 			// Attached data
2141 			// 1) screen_id screen
2142 			// 2) uint32 workspace index
2143 			screen_id id;
2144 			link.Read<screen_id>(&id);
2145 			uint32 workspace;
2146 			link.Read<uint32>(&workspace);
2147 
2148 			// TODO: the display_mode can be different between
2149 			// the various screens.
2150 			// We have the screen_id and the workspace number, with these
2151 			// we need to find the corresponding "driver", and call getmode on it
2152 			display_mode mode;
2153 			fDesktop->ScreenAt(0)->GetMode(&mode);
2154 			// actually this isn't still enough as different workspaces can
2155 			// have different display_modes
2156 
2157 			fLink.StartMessage(B_OK);
2158 			fLink.Attach<display_mode>(mode);
2159 			fLink.Flush();
2160 			break;
2161 		}
2162 		case AS_SCREEN_SET_MODE:
2163 		{
2164 			STRACE(("ServerApp %s: AS_SCREEN_SET_MODE\n", Signature()));
2165 			// Attached data
2166 			// 1) screen_id
2167 			// 2) workspace index
2168 			// 3) display_mode to set
2169 			// 4) 'makeDefault' boolean
2170 			// TODO: See above: workspaces support, etc.
2171 
2172 			screen_id id;
2173 			link.Read<screen_id>(&id);
2174 
2175 			uint32 workspace;
2176 			link.Read<uint32>(&workspace);
2177 
2178 			display_mode mode;
2179 			link.Read<display_mode>(&mode);
2180 
2181 			bool makeDefault = false;
2182 			status_t status = link.Read<bool>(&makeDefault);
2183 
2184 			if (status == B_OK && fDesktop->LockAllWindows()) {
2185 				display_mode oldMode;
2186 				fDesktop->ScreenAt(0)->GetMode(&oldMode);
2187 				if (memcmp(&oldMode, &mode, sizeof(display_mode))) {
2188 					status = fDesktop->ScreenAt(0)->SetMode(mode, makeDefault);
2189 					if (status == B_OK) {
2190 						gInputManager->UpdateScreenBounds(fDesktop->ScreenAt(0)->Frame());
2191 						fDesktop->ScreenChanged(fDesktop->ScreenAt(0), makeDefault);
2192 					}
2193 				} else
2194 					status = B_OK;
2195 				fDesktop->UnlockAllWindows();
2196 			} else
2197 				status = B_ERROR;
2198 
2199 			fLink.StartMessage(status);
2200 			fLink.Flush();
2201 			break;
2202 		}
2203 
2204 		case AS_PROPOSE_MODE:
2205 		{
2206 			STRACE(("ServerApp %s: AS_PROPOSE_MODE\n", Signature()));
2207 			screen_id id;
2208 			link.Read<screen_id>(&id);
2209 
2210 			display_mode target, low, high;
2211 			link.Read<display_mode>(&target);
2212 			link.Read<display_mode>(&low);
2213 			link.Read<display_mode>(&high);
2214 			status_t status = fDesktop->HWInterface()->ProposeMode(&target, &low, &high);
2215 
2216 			// ProposeMode() returns B_BAD_VALUE to hint that the candidate is
2217 			// not within the given limits (but is supported)
2218 			if (status == B_OK || status == B_BAD_VALUE) {
2219 				fLink.StartMessage(B_OK);
2220 				fLink.Attach<display_mode>(target);
2221 				fLink.Attach<bool>(status == B_OK);
2222 			} else
2223 				fLink.StartMessage(status);
2224 
2225 			fLink.Flush();
2226 			break;
2227 		}
2228 
2229 		case AS_GET_MODE_LIST:
2230 		{
2231 			screen_id id;
2232 			link.Read<screen_id>(&id);
2233 			// TODO: use this screen id
2234 
2235 			display_mode* modeList;
2236 			uint32 count;
2237 			status_t status = fDesktop->HWInterface()->GetModeList(&modeList, &count);
2238 			if (status == B_OK) {
2239 				fLink.StartMessage(B_OK);
2240 				fLink.Attach<uint32>(count);
2241 				fLink.Attach(modeList, sizeof(display_mode) * count);
2242 
2243 				delete[] modeList;
2244 			} else
2245 				fLink.StartMessage(status);
2246 
2247 			fLink.Flush();
2248 			break;
2249 		}
2250 
2251 		case AS_SCREEN_GET_COLORMAP:
2252 		{
2253 			STRACE(("ServerApp %s: AS_SCREEN_GET_COLORMAP\n", Signature()));
2254 
2255 			screen_id id;
2256 			link.Read<screen_id>(&id);
2257 
2258 			const color_map *colorMap = SystemColorMap();
2259 			if (colorMap != NULL) {
2260 				fLink.StartMessage(B_OK);
2261 				fLink.Attach<color_map>(*colorMap);
2262 			} else
2263 				fLink.StartMessage(B_ERROR);
2264 
2265 			fLink.Flush();
2266 			break;
2267 		}
2268 
2269 		case AS_GET_DESKTOP_COLOR:
2270 		{
2271 			STRACE(("ServerApp %s: get desktop color\n", Signature()));
2272 
2273 			uint32 index;
2274 			link.Read<uint32>(&index);
2275 
2276 			fLink.StartMessage(B_OK);
2277 			fDesktop->Lock();
2278 
2279 			// we're nice to our children (and also take the default case
2280 			// into account which asks for the current workspace)
2281 			if (index >= (uint32)kMaxWorkspaces)
2282 				index = fDesktop->CurrentWorkspace();
2283 
2284 			Workspace workspace(*fDesktop, index);
2285 			fLink.Attach<rgb_color>(workspace.Color());
2286 
2287 			fDesktop->Unlock();
2288 			fLink.Flush();
2289 			break;
2290 		}
2291 
2292 		case AS_SET_DESKTOP_COLOR:
2293 		{
2294 			STRACE(("ServerApp %s: set desktop color\n", Signature()));
2295 
2296 			rgb_color color;
2297 			uint32 index;
2298 			bool makeDefault;
2299 
2300 			link.Read<rgb_color>(&color);
2301 			link.Read<uint32>(&index);
2302 			if (link.Read<bool>(&makeDefault) != B_OK)
2303 				break;
2304 
2305 			fDesktop->Lock();
2306 
2307 			// we're nice to our children (and also take the default case
2308 			// into account which asks for the current workspace)
2309 			if (index >= (uint32)kMaxWorkspaces)
2310 				index = fDesktop->CurrentWorkspace();
2311 
2312 			Workspace workspace(*fDesktop, index);
2313 			workspace.SetColor(color, makeDefault);
2314 
2315 			fDesktop->Unlock();
2316 			break;
2317 		}
2318 
2319 		case AS_SET_UI_COLOR:
2320 		{
2321 			STRACE(("ServerApp %s: Set UI Color\n", Signature()));
2322 			// Attached Data:
2323 			// 1) color_which which
2324 			// 2) rgb_color color
2325 			color_which which;
2326 			rgb_color color;
2327 
2328 			link.Read<color_which>(&which);
2329 			if (link.Read<rgb_color>(&color) == B_OK) {
2330 				LockedDesktopSettings settings(fDesktop);
2331 				settings.SetUIColor(which, color);
2332 			}
2333 			break;
2334 		}
2335 
2336 		case AS_GET_ACCELERANT_INFO:
2337 		{
2338 			STRACE(("ServerApp %s: get accelerant info\n", Signature()));
2339 
2340 			// We aren't using the screen_id for now...
2341 			screen_id id;
2342 			link.Read<screen_id>(&id);
2343 
2344 			accelerant_device_info accelerantInfo;
2345 			// TODO: I wonder if there should be a "desktop" lock...
2346 			status_t status = fDesktop->HWInterface()->GetDeviceInfo(&accelerantInfo);
2347 			if (status == B_OK) {
2348 				fLink.StartMessage(B_OK);
2349 				fLink.Attach<accelerant_device_info>(accelerantInfo);
2350 			} else
2351 				fLink.StartMessage(status);
2352 
2353 			fLink.Flush();
2354 			break;
2355 		}
2356 
2357 		case AS_GET_MONITOR_INFO:
2358 		{
2359 			STRACE(("ServerApp %s: get monitor info\n", Signature()));
2360 
2361 			// We aren't using the screen_id for now...
2362 			screen_id id;
2363 			link.Read<screen_id>(&id);
2364 
2365 			monitor_info info;
2366 			// TODO: I wonder if there should be a "desktop" lock...
2367 			status_t status = fDesktop->HWInterface()->GetMonitorInfo(&info);
2368 			if (status == B_OK) {
2369 				fLink.StartMessage(B_OK);
2370 				fLink.Attach<monitor_info>(info);
2371 			} else
2372 				fLink.StartMessage(status);
2373 
2374 			fLink.Flush();
2375 			break;
2376 		}
2377 
2378 		case AS_GET_FRAME_BUFFER_CONFIG:
2379 		{
2380 			STRACE(("ServerApp %s: get frame buffer config\n", Signature()));
2381 
2382 			// We aren't using the screen_id for now...
2383 			screen_id id;
2384 			link.Read<screen_id>(&id);
2385 
2386 			frame_buffer_config config;
2387 			// TODO: I wonder if there should be a "desktop" lock...
2388 			status_t status = fDesktop->HWInterface()->GetFrameBufferConfig(config);
2389 			if (status == B_OK) {
2390 				fLink.StartMessage(B_OK);
2391 				fLink.Attach<frame_buffer_config>(config);
2392 			} else
2393 				fLink.StartMessage(status);
2394 
2395 			fLink.Flush();
2396 			break;
2397 		}
2398 
2399 		case AS_GET_RETRACE_SEMAPHORE:
2400 		{
2401 			STRACE(("ServerApp %s: get retrace semaphore\n", Signature()));
2402 
2403 			// We aren't using the screen_id for now...
2404 			screen_id id;
2405 			link.Read<screen_id>(&id);
2406 
2407 			fLink.StartMessage(B_OK);
2408 			fLink.Attach<sem_id>(fDesktop->HWInterface()->RetraceSemaphore());
2409 			fLink.Flush();
2410 			break;
2411 		}
2412 
2413 		case AS_GET_TIMING_CONSTRAINTS:
2414 		{
2415 			STRACE(("ServerApp %s: get timing constraints\n", Signature()));
2416 			// We aren't using the screen_id for now...
2417 			screen_id id;
2418 			link.Read<screen_id>(&id);
2419 
2420 			display_timing_constraints constraints;
2421 			status_t status = fDesktop->HWInterface()->GetTimingConstraints(
2422 				&constraints);
2423 			if (status == B_OK) {
2424 				fLink.StartMessage(B_OK);
2425 				fLink.Attach<display_timing_constraints>(constraints);
2426 			} else
2427 				fLink.StartMessage(status);
2428 
2429 			fLink.Flush();
2430 			break;
2431 		}
2432 
2433 		case AS_GET_PIXEL_CLOCK_LIMITS:
2434 		{
2435 			STRACE(("ServerApp %s: get pixel clock limits\n", Signature()));
2436 			// We aren't using the screen_id for now...
2437 			screen_id id;
2438 			link.Read<screen_id>(&id);
2439 			display_mode mode;
2440 			link.Read<display_mode>(&mode);
2441 
2442 			uint32 low, high;
2443 			status_t status = fDesktop->HWInterface()->GetPixelClockLimits(&mode,
2444 				&low, &high);
2445 			if (status == B_OK) {
2446 				fLink.StartMessage(B_OK);
2447 				fLink.Attach<uint32>(low);
2448 				fLink.Attach<uint32>(high);
2449 			} else
2450 				fLink.StartMessage(status);
2451 
2452 			fLink.Flush();
2453 			break;
2454 		}
2455 
2456 		case AS_SET_DPMS:
2457 		{
2458 			STRACE(("ServerApp %s: AS_SET_DPMS\n", Signature()));
2459 			screen_id id;
2460 			link.Read<screen_id>(&id);
2461 
2462 			uint32 mode;
2463 			link.Read<uint32>(&mode);
2464 
2465 			status_t status = fDesktop->HWInterface()->SetDPMSMode(mode);
2466 			fLink.StartMessage(status);
2467 
2468 			fLink.Flush();
2469 			break;
2470 		}
2471 
2472 		case AS_GET_DPMS_STATE:
2473 		{
2474 			STRACE(("ServerApp %s: AS_GET_DPMS_STATE\n", Signature()));
2475 
2476 			screen_id id;
2477 			link.Read<screen_id>(&id);
2478 
2479 			uint32 state = fDesktop->HWInterface()->DPMSMode();
2480 			fLink.StartMessage(B_OK);
2481 			fLink.Attach<uint32>(state);
2482 			fLink.Flush();
2483 			break;
2484 		}
2485 
2486 		case AS_GET_DPMS_CAPABILITIES:
2487 		{
2488 			STRACE(("ServerApp %s: AS_GET_DPMS_CAPABILITIES\n", Signature()));
2489 			screen_id id;
2490 			link.Read<screen_id>(&id);
2491 
2492 			uint32 capabilities = fDesktop->HWInterface()->DPMSCapabilities();
2493 			fLink.StartMessage(B_OK);
2494 			fLink.Attach<uint32>(capabilities);
2495 			fLink.Flush();
2496 			break;
2497 		}
2498 
2499 		case AS_READ_BITMAP:
2500 		{
2501 			STRACE(("ServerApp %s: AS_READ_BITMAP\n", Signature()));
2502 			int32 bitmapToken;
2503 			link.Read<int32>(&bitmapToken);
2504 
2505 			bool drawCursor = true;
2506 			link.Read<bool>(&drawCursor);
2507 
2508 			BRect bounds;
2509 			link.Read<BRect>(&bounds);
2510 
2511 			ServerBitmap *bitmap = FindBitmap(bitmapToken);
2512 			if (bitmap != NULL) {
2513 				if (fDesktop->GetDrawingEngine()->ReadBitmap(bitmap,
2514 					drawCursor, bounds) == B_OK) {
2515 					fLink.StartMessage(B_OK);
2516 				} else
2517 					fLink.StartMessage(B_BAD_VALUE);
2518 			} else
2519 				fLink.StartMessage(B_BAD_VALUE);
2520 
2521 			fLink.Flush();
2522 			break;
2523 		}
2524 
2525 		case AS_GET_ACCELERANT_PATH:
2526 		{
2527 			int32 index;
2528 			fLink.Read<int32>(&index);
2529 
2530 			BString path;
2531 			status_t status = fDesktop->HWInterface()->GetAccelerantPath(path);
2532 			fLink.StartMessage(status);
2533 			if (status == B_OK)
2534 				fLink.AttachString(path.String());
2535 
2536 			fLink.Flush();
2537 			break;
2538 		}
2539 
2540 		case AS_GET_DRIVER_PATH:
2541 		{
2542 			int32 index;
2543 			fLink.Read<int32>(&index);
2544 
2545 			BString path;
2546 			status_t status = fDesktop->HWInterface()->GetDriverPath(path);
2547 			fLink.StartMessage(status);
2548 			if (status == B_OK)
2549 				fLink.AttachString(path.String());
2550 
2551 			fLink.Flush();
2552 			break;
2553 		}
2554 
2555 		case AS_SET_SUBPIXEL_ANTIALIASING:
2556 		{
2557 			bool subpix;
2558 			if (link.Read<bool>(&subpix) == B_OK) {
2559 				LockedDesktopSettings settings(fDesktop);
2560 				settings.SetSubpixelAntialiasing(subpix);
2561 			}
2562 			fDesktop->Redraw();
2563 			break;
2564 		}
2565 
2566 		case AS_GET_SUBPIXEL_ANTIALIASING:
2567 		{
2568 			DesktopSettings settings(fDesktop);
2569 			fLink.StartMessage(B_OK);
2570 			fLink.Attach<bool>(settings.SubpixelAntialiasing());
2571 			fLink.Flush();
2572 			break;
2573 		}
2574 
2575 		case AS_SET_HINTING:
2576 		{
2577 			bool hinting;
2578 			if (link.Read<bool>(&hinting) == B_OK) {
2579 				LockedDesktopSettings settings(fDesktop);
2580 				settings.SetHinting(hinting);
2581 			}
2582 			fDesktop->Redraw();
2583 			break;
2584 		}
2585 
2586 		case AS_GET_HINTING:
2587 		{
2588 			DesktopSettings settings(fDesktop);
2589 			fLink.StartMessage(B_OK);
2590 			fLink.Attach<bool>(settings.Hinting());
2591 			fLink.Flush();
2592 			break;
2593 		}
2594 
2595 		case AS_SET_SUBPIXEL_AVERAGE_WEIGHT:
2596 		{
2597 			uint8 averageWeight;
2598 			if (link.Read<uint8>(&averageWeight) == B_OK) {
2599 				LockedDesktopSettings settings(fDesktop);
2600 				settings.SetSubpixelAverageWeight(averageWeight);
2601 			}
2602 			fDesktop->Redraw();
2603 			break;
2604 		}
2605 
2606 		case AS_GET_SUBPIXEL_AVERAGE_WEIGHT:
2607 		{
2608 			DesktopSettings settings(fDesktop);
2609 			fLink.StartMessage(B_OK);
2610 			fLink.Attach<uint8>(settings.SubpixelAverageWeight());
2611 			fLink.Flush();
2612 			break;
2613 		}
2614 
2615 		case AS_SET_SUBPIXEL_ORDERING:
2616 		{
2617 			bool subpixelOrdering;
2618 			if (link.Read<bool>(&subpixelOrdering) == B_OK) {
2619 				LockedDesktopSettings settings(fDesktop);
2620 				settings.SetSubpixelOrderingRegular(subpixelOrdering);
2621 			}
2622 			fDesktop->Redraw();
2623 			break;
2624 		}
2625 
2626 		case AS_GET_SUBPIXEL_ORDERING:
2627 		{
2628 			DesktopSettings settings(fDesktop);
2629 			fLink.StartMessage(B_OK);
2630 			fLink.Attach<bool>(settings.IsSubpixelOrderingRegular());
2631 			fLink.Flush();
2632 			break;
2633 		}
2634 
2635 		default:
2636 			printf("ServerApp %s received unhandled message code %ld\n",
2637 				Signature(), code);
2638 
2639 			if (link.NeedsReply()) {
2640 				// the client is now blocking and waiting for a reply!
2641 				fLink.StartMessage(B_ERROR);
2642 				fLink.Flush();
2643 			} else
2644 				puts("message doesn't need a reply!");
2645 			break;
2646 	}
2647 }
2648 
2649 
2650 status_t
2651 ServerApp::_CreateWindow(int32 code, BPrivate::LinkReceiver& link,
2652 	port_id& clientReplyPort)
2653 {
2654 	// Attached data:
2655 	// 1) int32 bitmap token (only for AS_CREATE_OFFSCREEN_WINDOW)
2656 	// 2) BRect window frame
2657 	// 3) uint32 window look
2658 	// 4) uint32 window feel
2659 	// 5) uint32 window flags
2660 	// 6) uint32 workspace index
2661 	// 7) int32 BHandler token of the window
2662 	// 8) port_id window's reply port
2663 	// 9) port_id window's looper port
2664 	// 10) const char * title
2665 
2666 	BRect frame;
2667 	int32 bitmapToken;
2668 	uint32 look;
2669 	uint32 feel;
2670 	uint32 flags;
2671 	uint32 workspaces;
2672 	int32 token;
2673 	port_id looperPort;
2674 	char* title;
2675 
2676 	if (code == AS_CREATE_OFFSCREEN_WINDOW)
2677 		link.Read<int32>(&bitmapToken);
2678 
2679 	link.Read<BRect>(&frame);
2680 	link.Read<uint32>(&look);
2681 	link.Read<uint32>(&feel);
2682 	link.Read<uint32>(&flags);
2683 	link.Read<uint32>(&workspaces);
2684 	link.Read<int32>(&token);
2685 	link.Read<port_id>(&clientReplyPort);
2686 	link.Read<port_id>(&looperPort);
2687 	if (link.ReadString(&title) != B_OK)
2688 		return B_ERROR;
2689 
2690 	if (!frame.IsValid()) {
2691 		// make sure we pass a valid rectangle to ServerWindow
2692 		frame.right = frame.left + 1;
2693 		frame.bottom = frame.top + 1;
2694 	}
2695 
2696 	status_t status = B_NO_MEMORY;
2697 	ServerWindow *window = NULL;
2698 
2699 	if (code == AS_CREATE_OFFSCREEN_WINDOW) {
2700 		ServerBitmap* bitmap = FindBitmap(bitmapToken);
2701 
2702 		if (bitmap != NULL) {
2703 			window = new (nothrow) OffscreenServerWindow(title, this, clientReplyPort,
2704 				looperPort, token, bitmap);
2705 		} else
2706 			status = B_ERROR;
2707 	} else {
2708 		window = new (nothrow) ServerWindow(title, this, clientReplyPort, looperPort, token);
2709 		STRACE(("\nServerApp %s: New Window %s (%g:%g, %g:%g)\n",
2710 			Signature(), title, frame.left, frame.top,
2711 			frame.right, frame.bottom));
2712 	}
2713 
2714 	free(title);
2715 
2716 	// NOTE: the reply to the client is handled in ServerWindow::Run()
2717 	if (window != NULL) {
2718 		status = window->Init(frame, (window_look)look, (window_feel)feel,
2719 			flags, workspaces);
2720 		if (status == B_OK && !window->Run()) {
2721 			fprintf(stderr, "ServerApp::_CreateWindow() - failed to run the window thread\n");
2722 			status = B_ERROR;
2723 		}
2724 
2725 		if (status < B_OK)
2726 			delete window;
2727 	}
2728 
2729 	return status;
2730 }
2731 
2732 
2733 bool
2734 ServerApp::AddWindow(ServerWindow* window)
2735 {
2736 	BAutolock locker(fWindowListLock);
2737 
2738 	return fWindowList.AddItem(window);
2739 }
2740 
2741 
2742 void
2743 ServerApp::RemoveWindow(ServerWindow* window)
2744 {
2745 	BAutolock locker(fWindowListLock);
2746 
2747 	fWindowList.RemoveItem(window);
2748 }
2749 
2750 
2751 bool
2752 ServerApp::InWorkspace(int32 index) const
2753 {
2754 	BAutolock locker(fWindowListLock);
2755 
2756 	// we could cache this, but then we'd have to recompute the cached
2757 	// value everytime a window has closed or changed workspaces
2758 
2759 	// TODO: support initial application workspace!
2760 
2761 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
2762 		ServerWindow* serverWindow = fWindowList.ItemAt(i);
2763 
2764 		const Window* window = serverWindow->Window();
2765 		if (window == NULL || window->IsOffscreenWindow())
2766 			continue;
2767 
2768 		// only normal and unhidden windows count
2769 
2770 		if (window->IsNormal() && !window->IsHidden() && window->InWorkspace(index))
2771 			return true;
2772 	}
2773 
2774 	return false;
2775 }
2776 
2777 
2778 uint32
2779 ServerApp::Workspaces() const
2780 {
2781 	uint32 workspaces = 0;
2782 
2783 	BAutolock locker(fWindowListLock);
2784 
2785 	// we could cache this, but then we'd have to recompute the cached
2786 	// value everytime a window has closed or changed workspaces
2787 
2788 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
2789 		ServerWindow* serverWindow = fWindowList.ItemAt(i);
2790 
2791 		const Window* window = serverWindow->Window();
2792 		if (window == NULL || window->IsOffscreenWindow())
2793 			continue;
2794 
2795 		// only normal and unhidden windows count
2796 
2797 		if (window->IsNormal() && !window->IsHidden())
2798 			workspaces |= window->Workspaces();
2799 	}
2800 
2801 	// TODO: add initial application workspace!
2802 	return workspaces;
2803 }
2804 
2805 
2806 int32
2807 ServerApp::CountBitmaps() const
2808 {
2809 	return fBitmapList.CountItems();
2810 }
2811 
2812 
2813 /*!
2814 	\brief Looks up a ServerApp's ServerBitmap in its list
2815 	\param token ID token of the bitmap to find
2816 	\return The bitmap having that ID or NULL if not found
2817 */
2818 ServerBitmap*
2819 ServerApp::FindBitmap(int32 token) const
2820 {
2821 	// TODO: we need to make sure the bitmap is ours?!
2822 	ServerBitmap* bitmap;
2823 	if (gTokenSpace.GetToken(token, kBitmapToken, (void**)&bitmap) == B_OK)
2824 		return bitmap;
2825 
2826 	return NULL;
2827 }
2828 
2829 
2830 int32
2831 ServerApp::CountPictures() const
2832 {
2833 	return fPictureList.CountItems();
2834 }
2835 
2836 
2837 ServerPicture *
2838 ServerApp::CreatePicture(const ServerPicture *original)
2839 {
2840 	ServerPicture *picture;
2841 	if (original != NULL)
2842 		picture = new (nothrow) ServerPicture(*original);
2843 	else
2844 		picture = new (nothrow) ServerPicture();
2845 
2846 	if (picture != NULL)
2847 		fPictureList.AddItem(picture);
2848 
2849 	return picture;
2850 }
2851 
2852 
2853 ServerPicture *
2854 ServerApp::FindPicture(const int32 &token) const
2855 {
2856 	// TODO: we need to make sure the picture is ours?!
2857 	ServerPicture* picture;
2858 	if (gTokenSpace.GetToken(token, kPictureToken, (void**)&picture) == B_OK)
2859 		return picture;
2860 
2861 	return NULL;
2862 }
2863 
2864 
2865 bool
2866 ServerApp::DeletePicture(const int32 &token)
2867 {
2868 	ServerPicture *picture = FindPicture(token);
2869 	if (picture == NULL)
2870 		return false;
2871 
2872 	if (!fPictureList.RemoveItem(picture))
2873 		return false;
2874 
2875 	delete picture;
2876 
2877 	return true;
2878 }
2879 
2880 
2881 team_id
2882 ServerApp::ClientTeam() const
2883 {
2884 	return fClientTeam;
2885 }
2886 
2887