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