xref: /haiku/src/servers/app/ServerApp.cpp (revision dd2a1e350b303b855a50fd64e6cb55618be1ae6a)
1 /*
2  * Copyright 2001-2016, 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  *		Philippe Saint-Pierre, stpere@gmail.com
14  *		Wim van der Meer, <WPJvanderMeer@gmail.com>
15  *		Joseph Groover <looncraz@looncraz.net>
16  */
17 
18 
19 /*!	\class ServerApp ServerApp.h
20 	\brief Counterpart to BApplication within the app_server
21 */
22 
23 
24 #include "ServerApp.h"
25 
26 #include <new>
27 #include <stdio.h>
28 #include <string.h>
29 #include <syslog.h>
30 
31 #include <AppDefs.h>
32 #include <Autolock.h>
33 #include <AutoLocker.h>
34 #include <Debug.h>
35 #include <List.h>
36 #include <ScrollBar.h>
37 #include <Shape.h>
38 #include <String.h>
39 #include <StackOrHeapArray.h>
40 
41 #include <FontPrivate.h>
42 #include <MessengerPrivate.h>
43 #include <PrivateScreen.h>
44 #include <RosterPrivate.h>
45 #include <ServerProtocol.h>
46 #include <WindowPrivate.h>
47 
48 #include "AppFontManager.h"
49 #include "AppServer.h"
50 #include "BitmapManager.h"
51 #include "CursorManager.h"
52 #include "CursorSet.h"
53 #include "Desktop.h"
54 #include "DecorManager.h"
55 #include "DrawingEngine.h"
56 #include "EventStream.h"
57 #include "GlobalFontManager.h"
58 #include "HWInterface.h"
59 #include "InputManager.h"
60 #include "OffscreenServerWindow.h"
61 #include "Screen.h"
62 #include "ServerBitmap.h"
63 #include "ServerConfig.h"
64 #include "ServerCursor.h"
65 #include "ServerPicture.h"
66 #include "ServerTokenSpace.h"
67 #include "ServerWindow.h"
68 #include "SystemPalette.h"
69 #include "Window.h"
70 
71 
72 //#define DEBUG_SERVERAPP
73 #ifdef DEBUG_SERVERAPP
74 #	define STRACE(x) debug_printf x
75 #else
76 #	define STRACE(x) ;
77 #endif
78 
79 //#define DEBUG_SERVERAPP_FONT
80 #ifdef DEBUG_SERVERAPP_FONT
81 #	define FTRACE(x) debug_printf x
82 #else
83 #	define FTRACE(x) ;
84 #endif
85 
86 using std::nothrow;
87 
88 static const uint32 kMsgUpdateShowAllDraggers = '_adg';
89 static const uint32 kMsgAppQuit = 'appQ';
90 
91 
92 ServerApp::ServerApp(Desktop* desktop, port_id clientReplyPort,
93 		port_id clientLooperPort, team_id clientTeam,
94 		int32 clientToken, const char* signature)
95 	:
96 	MessageLooper("application"),
97 
98 	fMessagePort(-1),
99 	fClientReplyPort(clientReplyPort),
100 	fDesktop(desktop),
101 	fSignature(signature),
102 	fClientTeam(clientTeam),
103 	fWindowListLock("window list"),
104 	fInitialWorkspace(desktop->CurrentWorkspace()),
105 		// TODO: this should probably be retrieved when the app is loaded!
106 	fTemporaryDisplayModeChange(0),
107 	fMapLocker("server app maps"),
108 	fAppCursor(NULL),
109 	fViewCursor(NULL),
110 	fCursorHideLevel(0),
111 	fIsActive(false),
112 	fMemoryAllocator(new (std::nothrow) ClientMemoryAllocator(this), true),
113 	fAppFontManager(NULL)
114 {
115 	if (fSignature.IsEmpty())
116 		fSignature = "application/no-signature";
117 
118 	char name[B_OS_NAME_LENGTH];
119 	snprintf(name, sizeof(name), "a<%" B_PRId32 ":%s", fClientTeam,
120 		SignatureLeaf());
121 
122 	fMessagePort = create_port(DEFAULT_MONITOR_PORT_SIZE, name);
123 	if (fMessagePort < B_OK)
124 		return;
125 
126 	fLink.SetSenderPort(fClientReplyPort);
127 	fLink.SetReceiverPort(fMessagePort);
128 	fLink.SetTargetTeam(fClientTeam);
129 
130 	// we let the application own the port, so that we get aware when it's gone
131 	if (set_port_owner(fMessagePort, fClientTeam) < B_OK) {
132 		delete_port(fMessagePort);
133 		fMessagePort = -1;
134 		return;
135 	}
136 
137 	BMessenger::Private(fHandlerMessenger).SetTo(fClientTeam,
138 		clientLooperPort, clientToken);
139 
140 	// record the current system wide fonts..
141 	desktop->LockSingleWindow();
142 	DesktopSettings settings(desktop);
143 	settings.GetDefaultPlainFont(fPlainFont);
144 	settings.GetDefaultBoldFont(fBoldFont);
145 	settings.GetDefaultFixedFont(fFixedFont);
146 	desktop->UnlockSingleWindow();
147 
148 	fAppFontManager = new AppFontManager();
149 
150 	STRACE(("ServerApp %s:\n", Signature()));
151 	STRACE(("\tBApp port: %" B_PRId32 "\n", fClientReplyPort));
152 	STRACE(("\tReceiver port: %" B_PRId32 "\n", fMessagePort));
153 }
154 
155 
156 ServerApp::~ServerApp()
157 {
158 	STRACE(("*ServerApp %s:~ServerApp()\n", Signature()));
159 	ASSERT(fQuitting);
160 
161 	// quit all server windows
162 
163 	fWindowListLock.Lock();
164 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
165 		ServerWindow* window = fWindowList.ItemAt(i);
166 		window->Quit();
167 	}
168 	fWindowListLock.Unlock();
169 
170 	// wait for the windows to quit
171 	snooze(20000);
172 
173 	fDesktop->RevertScreenModes(fTemporaryDisplayModeChange);
174 
175 	fWindowListLock.Lock();
176 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
177 		ServerWindow* window = fWindowList.ItemAt(i);
178 
179 		// A window could have been removed in the mean time
180 		// (if those 20 milli seconds from above weren't enough)
181 		if (window == NULL)
182 			continue;
183 
184 		sem_id deathSemaphore = window->DeathSemaphore();
185 		fWindowListLock.Unlock();
186 
187 		// wait 3 seconds for our window to quit - that's quite a long
188 		// time, but killing it might have desastrous effects
189 		if (MessageLooper::WaitForQuit(deathSemaphore, 3000000) != B_OK) {
190 			// This really shouldn't happen, as it shows we're buggy
191 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
192 			syslog(LOG_ERR, "ServerApp %s: ServerWindow doesn't respond!\n",
193 				Signature());
194 #else
195 			debugger("ServerWindow doesn't respond!\n");
196 #endif
197 		}
198 		fWindowListLock.Lock();
199 	}
200 
201 	if (fMemoryAllocator != NULL)
202 		fMemoryAllocator->Detach();
203 	fMapLocker.Lock();
204 
205 	while (!fBitmapMap.empty())
206 		_DeleteBitmap(fBitmapMap.begin()->second);
207 
208 	while (!fPictureMap.empty())
209 		fPictureMap.begin()->second->SetOwner(NULL);
210 
211 	fDesktop->GetCursorManager().DeleteCursors(fClientTeam);
212 
213 	delete fAppFontManager;
214 
215 	STRACE(("ServerApp %s::~ServerApp(): Exiting\n", Signature()));
216 }
217 
218 
219 /*!	\brief Checks if the application was initialized correctly
220 */
221 status_t
222 ServerApp::InitCheck()
223 {
224 	if (fMessagePort < B_OK)
225 		return fMessagePort;
226 
227 	if (fClientReplyPort < B_OK)
228 		return fClientReplyPort;
229 
230 	if (fWindowListLock.InitCheck() < B_OK)
231 		return fWindowListLock.InitCheck();
232 
233 	if (fMemoryAllocator == NULL)
234 		return B_NO_MEMORY;
235 
236 	return B_OK;
237 }
238 
239 
240 void
241 ServerApp::Quit()
242 {
243 	Quit(-1);
244 }
245 
246 
247 /*!	\brief This quits the application and deletes it. You're not supposed
248 		to call its destructor directly.
249 
250 	At the point you're calling this method, the application should already
251 	be removed from the application list.
252 */
253 void
254 ServerApp::Quit(sem_id shutdownSemaphore)
255 {
256 	if (fThread < B_OK) {
257 		delete this;
258 		return;
259 	}
260 
261 	// execute application deletion in the message looper thread
262 
263 	fQuitting = true;
264 	PostMessage(kMsgAppQuit);
265 
266 	send_data(fThread, 'QUIT', &shutdownSemaphore, sizeof(sem_id));
267 }
268 
269 
270 /*!	\brief Sets the ServerApp's active status
271 	\param value The new status of the ServerApp.
272 
273 	This changes an internal flag and also sets the current cursor to the one
274 	specified by the application
275 */
276 void
277 ServerApp::Activate(bool value)
278 {
279 	if (fIsActive == value)
280 		return;
281 
282 	fIsActive = value;
283 
284 	if (fIsActive) {
285 		// notify registrar about the active app
286 		BRoster::Private roster;
287 		roster.UpdateActiveApp(ClientTeam());
288 
289 		if (_HasWindowUnderMouse()) {
290 			// Set the cursor to the application cursor, if any
291 			fDesktop->SetCursor(CurrentCursor());
292 		}
293 		fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0);
294 	}
295 }
296 
297 
298 void
299 ServerApp::SetCurrentCursor(ServerCursor* cursor)
300 {
301 	fViewCursor.SetTo(cursor, false);
302 
303 	fDesktop->SetCursor(CurrentCursor());
304 }
305 
306 
307 ServerCursor*
308 ServerApp::CurrentCursor() const
309 {
310 	if (fViewCursor != NULL)
311 		return fViewCursor;
312 
313 	return fAppCursor;
314 }
315 
316 
317 bool
318 ServerApp::AddWindow(ServerWindow* window)
319 {
320 	BAutolock locker(fWindowListLock);
321 
322 	return fWindowList.AddItem(window);
323 }
324 
325 
326 void
327 ServerApp::RemoveWindow(ServerWindow* window)
328 {
329 	BAutolock locker(fWindowListLock);
330 
331 	fWindowList.RemoveItem(window);
332 }
333 
334 
335 bool
336 ServerApp::InWorkspace(int32 index) const
337 {
338 	BAutolock locker(fWindowListLock);
339 
340 	// we could cache this, but then we'd have to recompute the cached
341 	// value everytime a window has closed or changed workspaces
342 
343 	// TODO: support initial application workspace!
344 
345 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
346 		ServerWindow* serverWindow = fWindowList.ItemAt(i);
347 
348 		const Window* window = serverWindow->Window();
349 		if (window == NULL || window->IsOffscreenWindow())
350 			continue;
351 
352 		// only normal and unhidden windows count
353 
354 		if (window->IsNormal() && !window->IsHidden()
355 			&& window->InWorkspace(index))
356 			return true;
357 	}
358 
359 	return false;
360 }
361 
362 
363 uint32
364 ServerApp::Workspaces() const
365 {
366 	uint32 workspaces = 0;
367 
368 	BAutolock locker(fWindowListLock);
369 
370 	// we could cache this, but then we'd have to recompute the cached
371 	// value everytime a window has closed or changed workspaces
372 
373 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
374 		ServerWindow* serverWindow = fWindowList.ItemAt(i);
375 
376 		const Window* window = serverWindow->Window();
377 		if (window == NULL || window->IsOffscreenWindow())
378 			continue;
379 
380 		// only normal and unhidden windows count
381 
382 		if (window->IsNormal() && !window->IsHidden())
383 			workspaces |= window->Workspaces();
384 	}
385 
386 	// TODO: add initial application workspace!
387 	return workspaces;
388 }
389 
390 
391 /*!	\brief Acquires a reference of the desired bitmap, if available.
392 	\param token ID token of the bitmap to find
393 	\return The bitmap having that ID or NULL if not found
394 */
395 ServerBitmap*
396 ServerApp::GetBitmap(int32 token) const
397 {
398 	if (token < 1)
399 		return NULL;
400 
401 	BAutolock _(fMapLocker);
402 
403 	ServerBitmap* bitmap = _FindBitmap(token);
404 	if (bitmap == NULL)
405 		return NULL;
406 
407 	bitmap->AcquireReference();
408 
409 	return bitmap;
410 }
411 
412 
413 ServerPicture*
414 ServerApp::CreatePicture(const ServerPicture* original)
415 {
416 	BReference<ServerPicture> picture;
417 	if (original != NULL)
418 		picture.SetTo(new(std::nothrow) ServerPicture(*original), true);
419 	else
420 		picture.SetTo(new(std::nothrow) ServerPicture(), true);
421 
422 	if (picture != NULL && !picture->SetOwner(this))
423 		return NULL;
424 
425 	return picture.Detach();
426 }
427 
428 
429 ServerPicture*
430 ServerApp::GetPicture(int32 token) const
431 {
432 	if (token < 1)
433 		return NULL;
434 
435 	BAutolock _(fMapLocker);
436 
437 	ServerPicture* picture = _FindPicture(token);
438 	if (picture == NULL)
439 		return NULL;
440 
441 	picture->AcquireReference();
442 
443 	return picture;
444 }
445 
446 
447 /*! To be called only by ServerPicture itself.*/
448 bool
449 ServerApp::AddPicture(ServerPicture* picture)
450 {
451 	BAutolock _(fMapLocker);
452 
453 	ASSERT(picture->Owner() == NULL);
454 
455 	try {
456 		fPictureMap.insert(std::make_pair(picture->Token(), BReference<ServerPicture>(picture, false)));
457 	} catch (std::bad_alloc& exception) {
458 		return false;
459 	}
460 
461 	return true;
462 }
463 
464 
465 /*! To be called only by ServerPicture itself.*/
466 void
467 ServerApp::RemovePicture(ServerPicture* picture)
468 {
469 	BAutolock _(fMapLocker);
470 
471 	ASSERT(picture->Owner() == this);
472 
473 	fPictureMap.erase(picture->Token());
474 }
475 
476 
477 /*!	Called from the ClientMemoryAllocator whenever a server area could be
478 	deleted.
479 	A message is then sent to the client telling it that it can delete its
480 	client area, too.
481 */
482 void
483 ServerApp::NotifyDeleteClientArea(area_id serverArea)
484 {
485 	BMessage notify(kMsgDeleteServerMemoryArea);
486 	notify.AddInt32("server area", serverArea);
487 
488 	SendMessageToClient(&notify);
489 }
490 
491 
492 /*!	\brief Send a message to the ServerApp's BApplication
493 	\param message The message to send
494 */
495 void
496 ServerApp::SendMessageToClient(BMessage* message) const
497 {
498 	status_t status = fHandlerMessenger.SendMessage(message, (BHandler*)NULL,
499 		100000);
500 	if (status != B_OK) {
501 		syslog(LOG_ERR, "app %s send to client failed: %s\n", Signature(),
502 			strerror(status));
503 	}
504 }
505 
506 
507 // #pragma mark - private methods
508 
509 
510 void
511 ServerApp::_GetLooperName(char* name, size_t length)
512 {
513 	snprintf(name, length, "a:%" B_PRId32 ":%s", ClientTeam(), SignatureLeaf());
514 }
515 
516 
517 /*!	\brief Handler function for BApplication API messages
518 	\param code Identifier code for the message. Equivalent to BMessage::what
519 	\param buffer Any attachments
520 
521 	Note that the buffer's exact format is determined by the particular message.
522 	All attachments are placed in the buffer via a PortLink, so it will be a
523 	matter of casting and incrementing an index variable to access them.
524 */
525 void
526 ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
527 {
528 	switch (code) {
529 		case AS_REGISTER_INPUT_SERVER:
530 		{
531 			EventStream* stream
532 				= new(std::nothrow) InputServerStream(fHandlerMessenger);
533 			if (stream != NULL
534 				&& (!stream->IsValid() || !gInputManager->AddStream(stream))) {
535 				delete stream;
536 				break;
537 			}
538 
539 			// TODO: this should be done using notifications (so that an
540 			// abandoned stream will get noticed directly)
541 			if (fDesktop->EventDispatcher().InitCheck() != B_OK)
542 				fDesktop->EventDispatcher().SetTo(gInputManager->GetStream());
543 			break;
544 		}
545 
546 		case AS_APP_CRASHED:
547 			// Allow the debugger to show its window: if needed, remove any
548 			// kWindowScreenFeels from the windows of this application
549 			if (fDesktop->LockAllWindows()) {
550 				if (fWindowListLock.Lock()) {
551 					for (int32 i = fWindowList.CountItems(); i-- > 0;) {
552 						ServerWindow* serverWindow = fWindowList.ItemAt(i);
553 
554 						Window* window = serverWindow->Window();
555 						if (window == NULL || window->IsOffscreenWindow())
556 							continue;
557 
558 						if (window->Feel() == kWindowScreenFeel)
559 							fDesktop->SetWindowFeel(window, B_NORMAL_WINDOW_FEEL);
560 					}
561 
562 					fWindowListLock.Unlock();
563 				}
564 				fDesktop->UnlockAllWindows();
565 			}
566 			break;
567 
568 		case AS_DUMP_ALLOCATOR:
569 			fMemoryAllocator->Dump();
570 			break;
571 		case AS_DUMP_BITMAPS:
572 		{
573 			fMapLocker.Lock();
574 
575 			debug_printf("Application %" B_PRId32 ", %s: %d bitmaps:\n",
576 				ClientTeam(), Signature(), (int)fBitmapMap.size());
577 
578 			BitmapMap::const_iterator iterator = fBitmapMap.begin();
579 			for (; iterator != fBitmapMap.end(); iterator++) {
580 				ServerBitmap* bitmap = iterator->second;
581 				debug_printf("  [%" B_PRId32 "] %" B_PRId32 "x%" B_PRId32 ", "
582 					"area %" B_PRId32 ", size %" B_PRId32 "\n",
583 					bitmap->Token(), bitmap->Width(), bitmap->Height(),
584 					bitmap->Area(), bitmap->BitsLength());
585 			}
586 			fMapLocker.Unlock();
587 			break;
588 		}
589 
590 		case AS_CREATE_WINDOW:
591 		case AS_CREATE_OFFSCREEN_WINDOW:
592 		{
593 			port_id clientReplyPort = -1;
594 			status_t status = _CreateWindow(code, link, clientReplyPort);
595 
596 			// if sucessful, ServerWindow::Run() will already have replied
597 			if (status < B_OK) {
598 				// window creation failed, we need to notify the client
599 				BPrivate::LinkSender reply(clientReplyPort);
600 				reply.StartMessage(status);
601 				reply.Flush();
602 			}
603 			break;
604 		}
605 
606 		case AS_GET_WINDOW_LIST:
607 		{
608 			team_id team;
609 			if (link.Read<team_id>(&team) == B_OK)
610 				fDesktop->WriteWindowList(team, fLink.Sender());
611 			break;
612 		}
613 
614 		case AS_GET_WINDOW_INFO:
615 		{
616 			int32 serverToken;
617 			if (link.Read<int32>(&serverToken) == B_OK)
618 				fDesktop->WriteWindowInfo(serverToken, fLink.Sender());
619 			break;
620 		}
621 
622 		case AS_GET_WINDOW_ORDER:
623 		{
624 			int32 workspace;
625 			if (link.Read<int32>(&workspace) == B_OK)
626 				fDesktop->WriteWindowOrder(workspace, fLink.Sender());
627 			break;
628 		}
629 
630 		case AS_GET_APPLICATION_ORDER:
631 		{
632 			int32 workspace;
633 			if (link.Read<int32>(&workspace) == B_OK)
634 				fDesktop->WriteApplicationOrder(workspace, fLink.Sender());
635 			break;
636 		}
637 
638 		case AS_MINIMIZE_TEAM:
639 		{
640 			team_id team;
641 			if (link.Read<team_id>(&team) == B_OK)
642 				fDesktop->MinimizeApplication(team);
643 			break;
644 		}
645 
646 		case AS_BRING_TEAM_TO_FRONT:
647 		{
648 			team_id team;
649 			if (link.Read<team_id>(&team) == B_OK)
650 				fDesktop->BringApplicationToFront(team);
651 			break;
652 		}
653 
654 		case AS_WINDOW_ACTION:
655 		{
656 			int32 token;
657 			int32 action;
658 
659 			link.Read<int32>(&token);
660 			if (link.Read<int32>(&action) != B_OK)
661 				break;
662 
663 			fDesktop->WindowAction(token, action);
664 			break;
665 		}
666 
667 		// Decorator commands
668 
669 		case AS_SET_DECORATOR:
670 		{
671 			// Attached Data:
672 			// path to decorator add-on
673 
674 			BString path;
675 			link.ReadString(path);
676 
677 			status_t error = gDecorManager.SetDecorator(path, fDesktop);
678 
679 			fLink.Attach<status_t>(error);
680 			fLink.Flush();
681 
682 			if (error == B_OK)
683 				fDesktop->BroadcastToAllApps(AS_UPDATE_DECORATOR);
684 			break;
685 		}
686 
687 		case AS_GET_DECORATOR:
688 		{
689 			fLink.StartMessage(B_OK);
690 			fLink.AttachString(gDecorManager.GetCurrentDecorator().String());
691 			fLink.Flush();
692 			break;
693 		}
694 
695 		case AS_SET_CONTROL_LOOK:
696 		{
697 			STRACE(("ServerApp %s: Set ControlLook\n", Signature()));
698 
699 			BString path;
700 			status_t error = B_ERROR;
701 			if (link.ReadString(path) == B_OK) {
702 				LockedDesktopSettings settings(fDesktop);
703 				error = settings.SetControlLook(path.String());
704 			}
705 
706 			fLink.StartMessage(error);
707 			fLink.Flush();
708 			break;
709 		}
710 
711 		case AS_GET_CONTROL_LOOK:
712 		{
713 			STRACE(("ServerApp %s: Get ControlLook\n", Signature()));
714 
715 			if (fDesktop->LockSingleWindow()) {
716 				DesktopSettings settings(fDesktop);
717 
718 				fLink.StartMessage(B_OK);
719 				fLink.AttachString(settings.ControlLook().String());
720 				fDesktop->UnlockSingleWindow();
721 			} else
722 				fLink.StartMessage(B_ERROR);
723 
724 			fLink.Flush();
725 			break;
726 		}
727 
728 		case AS_CREATE_BITMAP:
729 		{
730 			STRACE(("ServerApp %s: Received BBitmap creation request\n",
731 				Signature()));
732 
733 			// Allocate a bitmap for an application
734 
735 			// Attached Data:
736 			// 1) BRect bounds
737 			// 2) color_space space
738 			// 3) int32 bitmap_flags
739 			// 4) int32 bytes_per_row
740 			// 5) int32 screen_id
741 
742 			// Reply Data:
743 			//	1) int32 server token
744 			//	2) area_id id of the area in which the bitmap data resides
745 			//	3) int32 area pointer offset used to calculate fBasePtr
746 
747 			// First, let's attempt to allocate the bitmap
748 			BReference<ServerBitmap> bitmap;
749 			uint8 allocationFlags = kAllocator;
750 
751 			BRect frame;
752 			color_space colorSpace;
753 			uint32 flags;
754 			int32 bytesPerRow;
755 			int32 screenID;
756 
757 			link.Read<BRect>(&frame);
758 			link.Read<color_space>(&colorSpace);
759 			link.Read<uint32>(&flags);
760 			link.Read<int32>(&bytesPerRow);
761 			if (link.Read<int32>(&screenID) == B_OK) {
762 				// TODO: choose the right HWInterface with regards to the
763 				// screenID
764 				bitmap.SetTo(gBitmapManager->CreateBitmap(fMemoryAllocator,
765 					*fDesktop->HWInterface(), frame, colorSpace, flags,
766 					bytesPerRow, screenID, &allocationFlags), true);
767 			}
768 
769 			STRACE(("ServerApp %s: Create Bitmap (%.1fx%.1f)\n",
770 				Signature(), frame.Width() + 1, frame.Height() + 1));
771 
772 			if (bitmap != NULL && _AddBitmap(bitmap)) {
773 				fLink.StartMessage(B_OK);
774 				fLink.Attach<int32>(bitmap->Token());
775 				fLink.Attach<uint8>(allocationFlags);
776 
777 				fLink.Attach<area_id>(bitmap->Area());
778 				fLink.Attach<int32>(bitmap->AreaOffset());
779 
780 				if ((allocationFlags & kFramebuffer) != 0)
781 					fLink.Attach<int32>(bitmap->BytesPerRow());
782 			} else {
783 				fLink.StartMessage(B_NO_MEMORY);
784 			}
785 
786 			fLink.Flush();
787 			break;
788 		}
789 
790 		case AS_DELETE_BITMAP:
791 		{
792 			STRACE(("ServerApp %s: received BBitmap delete request\n",
793 				Signature()));
794 
795 			// Attached Data:
796 			// 1) int32 token
797 			int32 token;
798 			link.Read<int32>(&token);
799 
800 			fMapLocker.Lock();
801 
802 			ServerBitmap* bitmap = _FindBitmap(token);
803 			if (bitmap != NULL) {
804 				STRACE(("ServerApp %s: Deleting Bitmap %" B_PRId32 "\n",
805 					Signature(), token));
806 
807 				_DeleteBitmap(bitmap);
808 			}
809 
810 			fMapLocker.Unlock();
811 			break;
812 		}
813 
814 		case AS_GET_BITMAP_OVERLAY_RESTRICTIONS:
815 		{
816 			overlay_restrictions restrictions;
817 			status_t status = B_ERROR;
818 
819 			int32 token;
820 			if (link.Read<int32>(&token) != B_OK)
821 				break;
822 
823 			BReference<ServerBitmap> bitmap(GetBitmap(token), true);
824 			if (bitmap != NULL) {
825 				STRACE(("ServerApp %s: Get overlay restrictions for bitmap "
826 					"%" B_PRId32 "\n", Signature(), token));
827 
828 				status = fDesktop->HWInterface()->GetOverlayRestrictions(
829 					bitmap->Overlay(), &restrictions);
830 			}
831 
832 			fLink.StartMessage(status);
833 			if (status == B_OK)
834 				fLink.Attach(&restrictions, sizeof(overlay_restrictions));
835 
836 			fLink.Flush();
837 			break;
838 		}
839 
840 		case AS_GET_BITMAP_SUPPORT_FLAGS:
841 		{
842 			uint32 colorSpace;
843 			if (link.Read<uint32>(&colorSpace) != B_OK)
844 				break;
845 
846 			bool overlay = fDesktop->HWInterface()->CheckOverlayRestrictions(
847 				64, 64, (color_space)colorSpace);
848 			uint32 flags = overlay ? B_BITMAPS_SUPPORT_OVERLAY : 0;
849 
850 			fLink.StartMessage(B_OK);
851 			fLink.Attach<int32>(flags);
852 			fLink.Flush();
853 			break;
854 		}
855 
856 		case AS_RECONNECT_BITMAP:
857 		{
858 			// First, let's attempt to allocate the bitmap
859 			BReference<ServerBitmap> bitmap;
860 
861 			BRect frame;
862 			color_space colorSpace;
863 			uint32 flags;
864 			int32 bytesPerRow;
865 			int32 screenID;
866 			area_id clientArea;
867 			int32 areaOffset;
868 
869 			link.Read<BRect>(&frame);
870 			link.Read<color_space>(&colorSpace);
871 			link.Read<uint32>(&flags);
872 			link.Read<int32>(&bytesPerRow);
873 			link.Read<int32>(&screenID);
874 			link.Read<int32>(&clientArea);
875 			if (link.Read<int32>(&areaOffset) == B_OK) {
876 				// TODO: choose the right HWInterface with regards to the
877 				// screenID
878 				bitmap.SetTo(gBitmapManager->CloneFromClient(clientArea, areaOffset,
879 					frame, colorSpace, flags, bytesPerRow), true);
880 			}
881 
882 			if (bitmap != NULL && _AddBitmap(bitmap)) {
883 				fLink.StartMessage(B_OK);
884 				fLink.Attach<int32>(bitmap->Token());
885 
886 				fLink.Attach<area_id>(bitmap->Area());
887 
888 			} else {
889 				fLink.StartMessage(B_NO_MEMORY);
890 			}
891 
892 			fLink.Flush();
893 			break;
894 		}
895 
896 		// Picture ops
897 
898 		case AS_CREATE_PICTURE:
899 		{
900 			// TODO: Maybe rename this to AS_UPLOAD_PICTURE ?
901 			STRACE(("ServerApp %s: Create Picture\n", Signature()));
902 			status_t status = B_NO_MEMORY;
903 
904 			BReference<ServerPicture> picture(CreatePicture());
905 			if (picture != NULL) {
906 				int32 subPicturesCount = 0;
907 				link.Read<int32>(&subPicturesCount);
908 				for (int32 i = 0; i < subPicturesCount; i++) {
909 					int32 token = -1;
910 					link.Read<int32>(&token);
911 
912 					BAutolock _(fMapLocker);
913 					if (ServerPicture* subPicture = _FindPicture(token))
914 						picture->NestPicture(subPicture);
915 				}
916 				status = picture->ImportData(link);
917 			}
918 			if (status == B_OK) {
919 				fLink.StartMessage(B_OK);
920 				fLink.Attach<int32>(picture->Token());
921 			} else
922 				fLink.StartMessage(status);
923 
924 			fLink.Flush();
925 			break;
926 		}
927 
928 		case AS_DELETE_PICTURE:
929 		{
930 			STRACE(("ServerApp %s: Delete Picture\n", Signature()));
931 			int32 token;
932 			if (link.Read<int32>(&token) == B_OK) {
933 				BAutolock _(fMapLocker);
934 
935 				ServerPicture* picture = _FindPicture(token);
936 				if (picture != NULL)
937 					picture->SetOwner(NULL);
938 			}
939 			break;
940 		}
941 
942 		case AS_CLONE_PICTURE:
943 		{
944 			STRACE(("ServerApp %s: Clone Picture\n", Signature()));
945 			int32 token;
946 			BReference<ServerPicture> original;
947 			if (link.Read<int32>(&token) == B_OK)
948 				original.SetTo(GetPicture(token), true);
949 
950 			if (original != NULL) {
951 				BReference<ServerPicture> cloned(CreatePicture(original), true);
952 				if (cloned != NULL) {
953 					fLink.StartMessage(B_OK);
954 					fLink.Attach<int32>(cloned->Token());
955 				} else
956 					fLink.StartMessage(B_NO_MEMORY);
957 			} else
958 				fLink.StartMessage(B_BAD_VALUE);
959 
960 			fLink.Flush();
961 			break;
962 		}
963 
964 		case AS_DOWNLOAD_PICTURE:
965 		{
966 			STRACE(("ServerApp %s: Download Picture\n", Signature()));
967 			int32 token;
968 			link.Read<int32>(&token);
969 			BReference<ServerPicture> picture(GetPicture(token), true);
970 			if (picture != NULL) {
971 				picture->ExportData(fLink);
972 					// ExportData() calls StartMessage() already
973 			} else
974 				fLink.StartMessage(B_ERROR);
975 
976 			fLink.Flush();
977 			break;
978 		}
979 
980 		case AS_CURRENT_WORKSPACE:
981 			STRACE(("ServerApp %s: get current workspace\n", Signature()));
982 
983 			if (fDesktop->LockSingleWindow()) {
984 				fLink.StartMessage(B_OK);
985 				fLink.Attach<int32>(fDesktop->CurrentWorkspace());
986 				fDesktop->UnlockSingleWindow();
987 			} else
988 				fLink.StartMessage(B_ERROR);
989 
990 			fLink.Flush();
991 			break;
992 
993 		case AS_ACTIVATE_WORKSPACE:
994 		{
995 			STRACE(("ServerApp %s: activate workspace\n", Signature()));
996 
997 			// TODO: See above
998 			int32 index;
999 			link.Read<int32>(&index);
1000 
1001 			bool takeFocusWindowThere;
1002 			link.Read<bool>(&takeFocusWindowThere);
1003 
1004 			fDesktop->SetWorkspace(index, takeFocusWindowThere);
1005 			break;
1006 		}
1007 
1008 		case AS_SET_WORKSPACE_LAYOUT:
1009 		{
1010 			int32 newColumns;
1011 			int32 newRows;
1012 			if (link.Read<int32>(&newColumns) == B_OK
1013 				&& link.Read<int32>(&newRows) == B_OK)
1014 				fDesktop->SetWorkspacesLayout(newColumns, newRows);
1015 			break;
1016 		}
1017 
1018 		case AS_GET_WORKSPACE_LAYOUT:
1019 		{
1020 			if (fDesktop->LockSingleWindow()) {
1021 				DesktopSettings settings(fDesktop);
1022 
1023 				fLink.StartMessage(B_OK);
1024 				fLink.Attach<int32>(settings.WorkspacesColumns());
1025 				fLink.Attach<int32>(settings.WorkspacesRows());
1026 
1027 				fDesktop->UnlockSingleWindow();
1028 			} else
1029 				fLink.StartMessage(B_ERROR);
1030 
1031 			fLink.Flush();
1032 			break;
1033 		}
1034 
1035 		case AS_IDLE_TIME:
1036 			STRACE(("ServerApp %s: idle time\n", Signature()));
1037 
1038 			fLink.StartMessage(B_OK);
1039 			fLink.Attach<bigtime_t>(fDesktop->EventDispatcher().IdleTime());
1040 			fLink.Flush();
1041 			break;
1042 
1043 		case AS_SHOW_CURSOR:
1044 		{
1045 			STRACE(("ServerApp %s: Show Cursor\n", Signature()));
1046 			fCursorHideLevel--;
1047 			if (fCursorHideLevel < 0)
1048 				fCursorHideLevel = 0;
1049 			fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0);
1050 			break;
1051 		}
1052 
1053 		case AS_HIDE_CURSOR:
1054 		{
1055 			STRACE(("ServerApp %s: Hide Cursor\n", Signature()));
1056 			fCursorHideLevel++;
1057 			fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0);
1058 			break;
1059 		}
1060 
1061 		case AS_OBSCURE_CURSOR:
1062 		{
1063 			STRACE(("ServerApp %s: Obscure Cursor\n", Signature()));
1064 			fDesktop->HWInterface()->ObscureCursor();
1065 			break;
1066 		}
1067 
1068 		case AS_QUERY_CURSOR_HIDDEN:
1069 		{
1070 			STRACE(("ServerApp %s: Received IsCursorHidden request\n",
1071 				Signature()));
1072 
1073 			fLink.StartMessage(fCursorHideLevel > 0 ? B_OK : B_ERROR);
1074 			fLink.Flush();
1075 			break;
1076 		}
1077 
1078 		case AS_SET_CURSOR:
1079 		{
1080 			STRACE(("ServerApp %s: SetCursor\n", Signature()));
1081 
1082 			// Attached data:
1083 			// 1) bool flag to send a reply
1084 			// 2) int32 token ID of the cursor to set
1085 			// 3) port_id port to receive a reply. Only exists if the sync flag
1086 			//    is true.
1087 			bool sync;
1088 			int32 token;
1089 
1090 			link.Read<bool>(&sync);
1091 			if (link.Read<int32>(&token) != B_OK)
1092 				break;
1093 
1094 			if (!fDesktop->GetCursorManager().Lock())
1095 				break;
1096 
1097 			fAppCursor.SetTo(fDesktop->GetCursorManager().FindCursor(token), false);
1098 
1099 			if (_HasWindowUnderMouse())
1100 				fDesktop->SetCursor(CurrentCursor());
1101 
1102 			fDesktop->GetCursorManager().Unlock();
1103 
1104 			if (sync) {
1105 				// The application is expecting a reply
1106 				fLink.StartMessage(B_OK);
1107 				fLink.Flush();
1108 			}
1109 			break;
1110 		}
1111 
1112 		case AS_SET_VIEW_CURSOR:
1113 		{
1114 			STRACE(("ServerApp %s: AS_SET_VIEW_CURSOR:\n", Signature()));
1115 
1116 			ViewSetViewCursorInfo info;
1117 			if (link.Read<ViewSetViewCursorInfo>(&info) != B_OK)
1118 				break;
1119 
1120 			if (fDesktop->GetCursorManager().Lock()) {
1121 				BReference<ServerCursor> cursor(fDesktop->GetCursorManager().FindCursor(
1122 					info.cursorToken), false);
1123 
1124 				fDesktop->GetCursorManager().Unlock();
1125 
1126 				// We need to acquire the write lock here, since we cannot
1127 				// afford that the window thread to which the view belongs
1128 				// is running and messing with that same view.
1129 				fDesktop->LockAllWindows();
1130 
1131 				// Find the corresponding view by the given token. It's ok
1132 				// if this view does not exist anymore, since it may have
1133 				// already be deleted in the window thread before this
1134 				// message got here.
1135 				View* view;
1136 				if (fViewTokens.GetToken(info.viewToken, B_HANDLER_TOKEN,
1137 					(void**)&view) == B_OK) {
1138 					// Set the cursor on the view.
1139 					view->SetCursor(cursor);
1140 
1141 					// The cursor might need to be updated now.
1142 					Window* window = view->Window();
1143 					if (window != NULL && window->IsFocus()) {
1144 						if (fDesktop->ViewUnderMouse(window) == view->Token())
1145 							SetCurrentCursor(cursor);
1146 					}
1147 				}
1148 
1149 				fDesktop->UnlockAllWindows();
1150 			}
1151 
1152 			if (info.sync) {
1153 				// sync the client (it can now delete the cursor)
1154 				fLink.StartMessage(B_OK);
1155 				fLink.Flush();
1156 			}
1157 			break;
1158 		}
1159 
1160 		case AS_CREATE_CURSOR:
1161 		{
1162 			STRACE(("ServerApp %s: Create Cursor\n", Signature()));
1163 
1164 			// Attached data:
1165 			// 1) 68 bytes of fAppCursor data
1166 			// 2) port_id reply port
1167 
1168 			status_t status = B_ERROR;
1169 			uint8 cursorData[68];
1170 			ServerCursor* cursor = NULL;
1171 
1172 //			if (link.Read(cursorData, sizeof(cursorData)) >= B_OK) {
1173 //				cursor = new (nothrow) ServerCursor(cursorData);
1174 //				if (cursor == NULL)
1175 //					status = B_NO_MEMORY;
1176 //			}
1177 //
1178 //			if (cursor != NULL) {
1179 //				cursor->SetOwningTeam(fClientTeam);
1180 //				fDesktop->GetCursorManager().AddCursor(cursor);
1181 //
1182 //				// Synchronous message - BApplication is waiting on the cursor's ID
1183 //				fLink.StartMessage(B_OK);
1184 //				fLink.Attach<int32>(cursor->Token());
1185 //			} else
1186 //				fLink.StartMessage(status);
1187 
1188 			if (link.Read(cursorData, sizeof(cursorData)) >= B_OK) {
1189 				cursor = fDesktop->GetCursorManager().CreateCursor(fClientTeam,
1190 					cursorData);
1191 				if (cursor == NULL)
1192 					status = B_NO_MEMORY;
1193 			}
1194 
1195 			if (cursor != NULL) {
1196 				// Synchronous message - BApplication is waiting on the
1197 				// cursor's ID
1198 				fLink.StartMessage(B_OK);
1199 				fLink.Attach<int32>(cursor->Token());
1200 			} else
1201 				fLink.StartMessage(status);
1202 
1203 			fLink.Flush();
1204 			break;
1205 		}
1206 
1207 		case AS_CREATE_CURSOR_BITMAP:
1208 		{
1209 			STRACE(("ServerApp %s: Create Cursor bitmap\n", Signature()));
1210 
1211 			status_t status = B_ERROR;
1212 
1213 			int32 size = 0, bytesPerRow = 0;
1214 			BRect cursorRect;
1215 			color_space colorspace = B_RGBA32;
1216 			BPoint hotspot;
1217 			ServerCursor* cursor = NULL;
1218 
1219 			if (link.Read<BRect>(&cursorRect) == B_OK
1220 				&& link.Read<BPoint>(&hotspot) == B_OK
1221 				&& link.Read<color_space>(&colorspace) == B_OK
1222 				&& link.Read<int32>(&bytesPerRow) == B_OK
1223 				&& link.Read<int32>(&size) == B_OK
1224 				&& size > 0) {
1225 
1226 				BStackOrHeapArray<uint8, 256> byteArray(size);
1227 				if (!byteArray.IsValid()) {
1228 					status = B_NO_MEMORY;
1229 				} else if (link.Read(byteArray, size) == B_OK) {
1230 					cursor = fDesktop->GetCursorManager().CreateCursor(
1231 						fClientTeam, cursorRect, colorspace, 0, hotspot);
1232 					if (cursor == NULL)
1233 						status = B_NO_MEMORY;
1234 					else
1235 						cursor->ImportBits(byteArray, size, bytesPerRow, colorspace);
1236 				}
1237 			}
1238 
1239 			if (cursor != NULL) {
1240 				// Synchronous message - BApplication is waiting on the
1241 				// cursor's ID
1242 				fLink.StartMessage(B_OK);
1243 				fLink.Attach<int32>(cursor->Token());
1244 			} else
1245 				fLink.StartMessage(status);
1246 
1247 			fLink.Flush();
1248 			break;
1249 		}
1250 
1251 		case AS_REFERENCE_CURSOR:
1252 		{
1253 			STRACE(("ServerApp %s: Reference BCursor\n", Signature()));
1254 
1255 			// Attached data:
1256 			// 1) int32 token ID of the cursor to reference
1257 
1258 			int32 token;
1259 			if (link.Read<int32>(&token) != B_OK)
1260 				break;
1261 
1262 			if (!fDesktop->GetCursorManager().Lock())
1263 				break;
1264 
1265 			ServerCursor* cursor
1266 				= fDesktop->GetCursorManager().FindCursor(token);
1267 			if (cursor != NULL)
1268 				cursor->AcquireReference();
1269 
1270 			fDesktop->GetCursorManager().Unlock();
1271 
1272 			break;
1273 		}
1274 
1275 		case AS_DELETE_CURSOR:
1276 		{
1277 			STRACE(("ServerApp %s: Delete BCursor\n", Signature()));
1278 
1279 			// Attached data:
1280 			// 1) int32 token ID of the cursor to delete
1281 
1282 			int32 token;
1283 			if (link.Read<int32>(&token) != B_OK)
1284 				break;
1285 
1286 			if (!fDesktop->GetCursorManager().Lock())
1287 				break;
1288 
1289 			ServerCursor* cursor
1290 				= fDesktop->GetCursorManager().FindCursor(token);
1291 			if (cursor != NULL)
1292 				cursor->ReleaseReference();
1293 
1294 			fDesktop->GetCursorManager().Unlock();
1295 
1296 			break;
1297 		}
1298 
1299 		case AS_GET_CURSOR_POSITION:
1300 		{
1301 			STRACE(("ServerApp %s: Get Cursor position\n", Signature()));
1302 
1303 			// Returns
1304 			// 1) BPoint mouse location
1305 			// 2) int32 button state
1306 
1307 			BPoint where;
1308 			int32 buttons;
1309 			fDesktop->GetLastMouseState(&where, &buttons);
1310 			fLink.StartMessage(B_OK);
1311 			fLink.Attach<BPoint>(where);
1312 			fLink.Attach<int32>(buttons);
1313 			fLink.Flush();
1314 			break;
1315 		}
1316 
1317 		case AS_GET_CURSOR_BITMAP:
1318 		{
1319 			STRACE(("ServerApp %s: Get Cursor bitmap\n", Signature()));
1320 
1321 			// Returns
1322 			// 1) uint32 number of data bytes of the bitmap
1323 			// 2) uint32 cursor width in number of pixels
1324 			// 3) uint32 cursor height in number of pixels
1325 			// 4) BPoint cursor hot spot
1326 			// 5) cursor bitmap data
1327 
1328 			ServerCursorReference cursorRef = fDesktop->Cursor();
1329 			ServerCursor* cursor = cursorRef.Get();
1330 			if (cursor != NULL) {
1331 				uint32 size = cursor->BitsLength();
1332 				fLink.StartMessage(B_OK);
1333 				fLink.Attach<uint32>(size);
1334 				fLink.Attach<uint32>(cursor->Width());
1335 				fLink.Attach<uint32>(cursor->Height());
1336 				fLink.Attach<color_space>(cursor->ColorSpace());
1337 				fLink.Attach<BPoint>(cursor->GetHotSpot());
1338 				fLink.Attach(cursor->Bits(), size);
1339 			} else
1340 				fLink.StartMessage(B_ERROR);
1341 
1342 			fLink.Flush();
1343 
1344 			break;
1345 		}
1346 
1347 		case AS_GET_SCROLLBAR_INFO:
1348 		{
1349 			STRACE(("ServerApp %s: Get ScrollBar info\n", Signature()));
1350 
1351 			if (fDesktop->LockSingleWindow()) {
1352 				scroll_bar_info info;
1353 				DesktopSettings settings(fDesktop);
1354 				settings.GetScrollBarInfo(info);
1355 
1356 				fLink.StartMessage(B_OK);
1357 				fLink.Attach<scroll_bar_info>(info);
1358 				fDesktop->UnlockSingleWindow();
1359 			} else
1360 				fLink.StartMessage(B_ERROR);
1361 
1362 			fLink.Flush();
1363 			break;
1364 		}
1365 
1366 		case AS_SET_SCROLLBAR_INFO:
1367 		{
1368 			STRACE(("ServerApp %s: Set ScrollBar info\n", Signature()));
1369 
1370 			// Attached Data:
1371 			// 1) scroll_bar_info scroll bar info structure
1372 
1373 			scroll_bar_info info;
1374 			if (link.Read<scroll_bar_info>(&info) == B_OK) {
1375 				LockedDesktopSettings settings(fDesktop);
1376 				settings.SetScrollBarInfo(info);
1377 			}
1378 
1379 			fLink.StartMessage(B_OK);
1380 			fLink.Flush();
1381 			break;
1382 		}
1383 
1384 		case AS_GET_MENU_INFO:
1385 		{
1386 			STRACE(("ServerApp %s: Get menu info\n", Signature()));
1387 			if (fDesktop->LockSingleWindow()) {
1388 				menu_info info;
1389 				DesktopSettings settings(fDesktop);
1390 				settings.GetMenuInfo(info);
1391 
1392 				fLink.StartMessage(B_OK);
1393 				fLink.Attach<menu_info>(info);
1394 
1395 				fDesktop->UnlockSingleWindow();
1396 			} else
1397 				fLink.StartMessage(B_ERROR);
1398 
1399 			fLink.Flush();
1400 			break;
1401 		}
1402 
1403 		case AS_SET_MENU_INFO:
1404 		{
1405 			STRACE(("ServerApp %s: Set menu info\n", Signature()));
1406 			menu_info info;
1407 			if (link.Read<menu_info>(&info) == B_OK) {
1408 				LockedDesktopSettings settings(fDesktop);
1409 				settings.SetMenuInfo(info);
1410 					// TODO: SetMenuInfo() should do some validity check, so
1411 					//	that the answer we're giving can actually be useful
1412 			}
1413 
1414 			fLink.StartMessage(B_OK);
1415 			fLink.Flush();
1416 			break;
1417 		}
1418 
1419 		case AS_SET_MOUSE_MODE:
1420 		{
1421 			STRACE(("ServerApp %s: Set Mouse Focus mode\n",
1422 				Signature()));
1423 
1424 			// Attached Data:
1425 			// 1) enum mode_mouse mouse focus mode
1426 
1427 			mode_mouse mouseMode;
1428 			if (link.Read<mode_mouse>(&mouseMode) == B_OK) {
1429 				LockedDesktopSettings settings(fDesktop);
1430 				settings.SetMouseMode(mouseMode);
1431 			}
1432 			break;
1433 		}
1434 
1435 		case AS_GET_MOUSE_MODE:
1436 		{
1437 			STRACE(("ServerApp %s: Get Mouse Focus mode\n",
1438 				Signature()));
1439 
1440 			if (fDesktop->LockSingleWindow()) {
1441 				DesktopSettings settings(fDesktop);
1442 
1443 				fLink.StartMessage(B_OK);
1444 				fLink.Attach<mode_mouse>(settings.MouseMode());
1445 
1446 				fDesktop->UnlockSingleWindow();
1447 			} else
1448 				fLink.StartMessage(B_ERROR);
1449 
1450 			fLink.Flush();
1451 			break;
1452 		}
1453 
1454 		case AS_SET_FOCUS_FOLLOWS_MOUSE_MODE:
1455 		{
1456 			STRACE(("ServerApp %s: Set Focus Follows Mouse mode\n", Signature()));
1457 
1458 			// Attached Data:
1459 			// 1) enum mode_focus_follows_mouse FFM mouse mode
1460 
1461 			mode_focus_follows_mouse focusFollowsMousMode;
1462 			if (link.Read<mode_focus_follows_mouse>(&focusFollowsMousMode) == B_OK) {
1463 				LockedDesktopSettings settings(fDesktop);
1464 				settings.SetFocusFollowsMouseMode(focusFollowsMousMode);
1465 			}
1466 			break;
1467 		}
1468 
1469 		case AS_GET_FOCUS_FOLLOWS_MOUSE_MODE:
1470 		{
1471 			STRACE(("ServerApp %s: Get Focus Follows Mouse mode\n", Signature()));
1472 
1473 			if (fDesktop->LockSingleWindow()) {
1474 				DesktopSettings settings(fDesktop);
1475 
1476 				fLink.StartMessage(B_OK);
1477 				fLink.Attach<mode_focus_follows_mouse>(
1478 					settings.FocusFollowsMouseMode());
1479 
1480 				fDesktop->UnlockSingleWindow();
1481 			} else
1482 				fLink.StartMessage(B_ERROR);
1483 
1484 			fLink.Flush();
1485 			break;
1486 		}
1487 
1488 		case AS_SET_ACCEPT_FIRST_CLICK:
1489 		{
1490 			STRACE(("ServerApp %s: Set Accept First Click\n", Signature()));
1491 
1492 			// Attached Data:
1493 			// 1) bool accept_first_click
1494 
1495 			bool acceptFirstClick;
1496 			if (link.Read<bool>(&acceptFirstClick) == B_OK) {
1497 				LockedDesktopSettings settings(fDesktop);
1498 				settings.SetAcceptFirstClick(acceptFirstClick);
1499 			}
1500 			break;
1501 		}
1502 
1503 		case AS_GET_ACCEPT_FIRST_CLICK:
1504 		{
1505 			STRACE(("ServerApp %s: Get Accept First Click\n", Signature()));
1506 
1507 			if (fDesktop->LockSingleWindow()) {
1508 				DesktopSettings settings(fDesktop);
1509 
1510 				fLink.StartMessage(B_OK);
1511 				fLink.Attach<bool>(settings.AcceptFirstClick());
1512 
1513 				fDesktop->UnlockSingleWindow();
1514 			} else
1515 				fLink.StartMessage(B_ERROR);
1516 
1517 			fLink.Flush();
1518 			break;
1519 		}
1520 
1521 		case AS_GET_SHOW_ALL_DRAGGERS:
1522 		{
1523 			STRACE(("ServerApp %s: Get Show All Draggers\n", Signature()));
1524 
1525 			if (fDesktop->LockSingleWindow()) {
1526 				DesktopSettings settings(fDesktop);
1527 
1528 				fLink.StartMessage(B_OK);
1529 				fLink.Attach<bool>(settings.ShowAllDraggers());
1530 
1531 				fDesktop->UnlockSingleWindow();
1532 			} else
1533 				fLink.StartMessage(B_ERROR);
1534 
1535 			fLink.Flush();
1536 			break;
1537 		}
1538 
1539 		case AS_SET_SHOW_ALL_DRAGGERS:
1540 		{
1541 			STRACE(("ServerApp %s: Set Show All Draggers\n", Signature()));
1542 
1543 			bool changed = false;
1544 			bool show;
1545 			if (link.Read<bool>(&show) == B_OK) {
1546 				LockedDesktopSettings settings(fDesktop);
1547 				if (show != settings.ShowAllDraggers()) {
1548 					settings.SetShowAllDraggers(show);
1549 					changed = true;
1550 				}
1551 			}
1552 
1553 			if (changed)
1554 				fDesktop->BroadcastToAllApps(kMsgUpdateShowAllDraggers);
1555 			break;
1556 		}
1557 
1558 		case kMsgUpdateShowAllDraggers:
1559 		{
1560 			bool show = false;
1561 			if (fDesktop->LockSingleWindow()) {
1562 				DesktopSettings settings(fDesktop);
1563 				show = settings.ShowAllDraggers();
1564 				fDesktop->UnlockSingleWindow();
1565 			}
1566 			BMessage update(_SHOW_DRAG_HANDLES_);
1567 			update.AddBool("show", show);
1568 
1569 			SendMessageToClient(&update);
1570 			break;
1571 		}
1572 
1573 		/* font messages */
1574 
1575 		case AS_ADD_FONT_FILE:
1576 		{
1577 			FTRACE(("ServerApp %s: Received BFont creation request\n",
1578 				Signature()));
1579 
1580 			// Add a font for an application from a file
1581 
1582 			// Attached Data:
1583 			// 1) char* - path to font on disk
1584 			// 2) uint16 - index in font file
1585 			// 3) uint16 - instance
1586 
1587 			// Returns:
1588 			// 1) uint16 - family ID of added font
1589 			// 2) uint16 - style ID of added font
1590 			// 3) uint16 - face of added font
1591 
1592 			AutoLocker< ::FontManager> fontLock(fAppFontManager);
1593 
1594 			if (fAppFontManager->CountFamilies() > MAX_USER_FONTS) {
1595 				fLink.StartMessage(B_NOT_ALLOWED);
1596 				fLink.Flush();
1597 				break;
1598 			}
1599 
1600 			uint16 familyID, styleID;
1601 			char* fontPath;
1602 			uint16 index, instance;
1603 			link.ReadString(&fontPath);
1604 			link.Read<uint16>(&index);
1605 			link.Read<uint16>(&instance);
1606 
1607 			status_t status = fAppFontManager->AddUserFontFromFile(fontPath, index, instance,
1608 				familyID, styleID);
1609 
1610 			if (status != B_OK) {
1611 				fLink.StartMessage(status);
1612 			} else {
1613 				ServerFont font;
1614 				status = font.SetFamilyAndStyle(familyID, styleID,
1615 					fAppFontManager);
1616 
1617 				fLink.StartMessage(status);
1618 				if (status == B_OK) {
1619 					fLink.Attach<uint16>(font.FamilyID());
1620 					fLink.Attach<uint16>(font.StyleID());
1621 					fLink.Attach<uint16>(font.Face());
1622 				}
1623 			}
1624 
1625 			fLink.Flush();
1626 			break;
1627 		}
1628 
1629 		case AS_ADD_FONT_MEMORY:
1630 		{
1631 			FTRACE(("ServerApp %s: Received BFont memory creation request\n",
1632 				Signature()));
1633 
1634 			// Add a font for an application from a memory area
1635 
1636 			// Attached Data:
1637 			// 1) area_id - id of memory area where font resides
1638 			// 2) size_t - size of memory area for font
1639 			// 3) size_t - offset to start of font memory
1640 			// 4) uint16 - index in font buffer
1641 			// 5) uint16 - instance
1642 
1643 			// Returns:
1644 			// 1) uint16 - family ID of added font
1645 			// 2) uint16 - style ID of added font
1646 			// 3) uint16 - face of added font
1647 
1648 			AutoLocker< ::FontManager> fontLock(fAppFontManager);
1649 
1650 			if (fAppFontManager->CountFamilies() > MAX_USER_FONTS) {
1651 				fLink.StartMessage(B_NOT_ALLOWED);
1652 				fLink.Flush();
1653 				break;
1654 			}
1655 
1656 			area_id fontAreaID, fontAreaCloneID;
1657 			area_info fontAreaInfo;
1658 			char* area_addr;
1659 			size_t size, offset;
1660 			uint16 index, instance;
1661 
1662 			link.Read<int32>(&fontAreaID);
1663 			link.Read<size_t>(&size);
1664 			link.Read<size_t>(&offset);
1665 			link.Read<uint16>(&index);
1666 			link.Read<uint16>(&instance);
1667 			fontAreaCloneID = clone_area("user font",
1668 				(void **)&area_addr,
1669 				B_ANY_ADDRESS,
1670 				B_READ_AREA,
1671 				fontAreaID);
1672 
1673 			if (fontAreaCloneID < B_OK) {
1674 				fLink.StartMessage(fontAreaCloneID);
1675 				fLink.Flush();
1676 				break;
1677 			}
1678 
1679 			status_t status = get_area_info(fontAreaCloneID, &fontAreaInfo);
1680 			if (status != B_OK) {
1681 				fLink.StartMessage(status);
1682 				fLink.Flush();
1683 				delete_area(fontAreaCloneID);
1684 				break;
1685 			}
1686 
1687 			size_t fontMemorySize = fontAreaInfo.size - offset;
1688 
1689 			if (size == 0)
1690 				size = fontMemorySize;
1691 
1692 			// Check size of font area and reject if it's too large
1693 			if (size > MAX_FONT_DATA_SIZE_BYTES
1694 				|| size > fontMemorySize) {
1695 				fLink.StartMessage(B_BAD_DATA);
1696 				fLink.Flush();
1697 				delete_area(fontAreaCloneID);
1698 				break;
1699 			}
1700 
1701 			FT_Byte* fontData = (FT_Byte*)(malloc (sizeof(FT_Byte) * size));
1702 			if (fontData == NULL) {
1703 				delete_area(fontAreaCloneID);
1704 				fLink.StartMessage(B_BAD_DATA);
1705 				fLink.Flush();
1706 				break;
1707 			}
1708 
1709 			memcpy(fontData, (FT_Byte*)fontAreaInfo.address + offset, size);
1710 
1711 			delete_area(fontAreaCloneID);
1712 
1713 			uint16 familyID, styleID;
1714 
1715 			status = fAppFontManager->AddUserFontFromMemory(fontData, size, index, instance,
1716 				familyID, styleID);
1717 
1718 			if (status != B_OK) {
1719 				fLink.StartMessage(status);
1720 				free(fontData);
1721 			} else {
1722 				ServerFont font;
1723 				status = font.SetFamilyAndStyle(familyID, styleID,
1724 					fAppFontManager);
1725 
1726 				if (status == B_OK) {
1727 					font.SetFontData(fontData, size);
1728 					fLink.StartMessage(B_OK);
1729 					fLink.Attach<uint16>(font.FamilyID());
1730 					fLink.Attach<uint16>(font.StyleID());
1731 					fLink.Attach<uint16>(font.Face());
1732 				} else {
1733 					fLink.StartMessage(status);
1734 					free(fontData);
1735 				}
1736 			}
1737 
1738 			fLink.Flush();
1739 			break;
1740 		}
1741 
1742 		case AS_REMOVE_FONT:
1743 		{
1744 			STRACE(("ServerApp %s: Received BFont removal request\n",
1745 				Signature()));
1746 
1747 			// Remove an application-added font
1748 
1749 			// Attached Data:
1750 			// 1) uint16 - familyID of font to remove
1751 			// 2) uint16 - styleID of font to remove
1752 
1753 			uint16 familyID, styleID;
1754 			link.Read<uint16>(&familyID);
1755 			link.Read<uint16>(&styleID);
1756 
1757 			status_t status = B_OK;
1758 
1759 			AutoLocker< ::FontManager> fontLock(fAppFontManager);
1760 			status = fAppFontManager->RemoveUserFont(familyID, styleID);
1761 
1762 			fLink.StartMessage(status);
1763 			fLink.Flush();
1764 			break;
1765 		}
1766 
1767 		case AS_SET_SYSTEM_FONT:
1768 		{
1769 			FTRACE(("ServerApp %s: AS_SET_SYSTEM_FONT\n", Signature()));
1770 			// gets:
1771 			//	1) string - font type ("plain", ...)
1772 			//	2) string - family
1773 			//	3) string - style
1774 			//	4) float - size
1775 
1776 			char type[B_OS_NAME_LENGTH];
1777 			font_family familyName;
1778 			font_style styleName;
1779 			float size;
1780 
1781 			if (link.ReadString(type, sizeof(type)) == B_OK
1782 				&& link.ReadString(familyName, sizeof(familyName)) == B_OK
1783 				&& link.ReadString(styleName, sizeof(styleName)) == B_OK
1784 				&& link.Read<float>(&size) == B_OK) {
1785 				gFontManager->Lock();
1786 
1787 				FontStyle* style
1788 					= gFontManager->GetStyle(familyName, styleName);
1789 				if (style != NULL) {
1790 					ServerFont font(*style, size);
1791 					gFontManager->Unlock();
1792 						// We must not have locked the font manager when
1793 						// locking the desktop (through LockedDesktopSettings
1794 						// below)
1795 
1796 					LockedDesktopSettings settings(fDesktop);
1797 
1798 					// TODO: Should we also update our internal copies now?
1799 					if (strcmp(type, "plain") == 0)
1800 						settings.SetDefaultPlainFont(font);
1801 					else if (strcmp(type, "bold") == 0)
1802 						settings.SetDefaultBoldFont(font);
1803 					else if (strcmp(type, "fixed") == 0)
1804 						settings.SetDefaultFixedFont(font);
1805 				} else
1806 					gFontManager->Unlock();
1807 			}
1808 			break;
1809 		}
1810 
1811 		case AS_GET_SYSTEM_DEFAULT_FONT:
1812 		{
1813 			// input:
1814 			//	1) string - font type ("plain", ...)
1815 
1816 			ServerFont font;
1817 
1818 			char type[B_OS_NAME_LENGTH];
1819 			status_t status = link.ReadString(type, sizeof(type));
1820 			if (status == B_OK) {
1821 				if (strcmp(type, "plain") == 0)
1822 					font = *gFontManager->DefaultPlainFont();
1823 				else if (strcmp(type, "bold") == 0)
1824 					font = *gFontManager->DefaultBoldFont();
1825 				else if (strcmp(type, "fixed") == 0)
1826 					font = *gFontManager->DefaultFixedFont();
1827 				else
1828 					status = B_BAD_VALUE;
1829 			}
1830 
1831 			if (status == B_OK) {
1832 				// returns:
1833 				//	1) string - family
1834 				//	2) string - style
1835 				//	3) float - size
1836 
1837 				fLink.StartMessage(B_OK);
1838 				fLink.AttachString(font.Family());
1839 				fLink.AttachString(font.Style());
1840 				fLink.Attach<float>(font.Size());
1841 			} else
1842 				fLink.StartMessage(status);
1843 
1844 			fLink.Flush();
1845 			break;
1846 		}
1847 
1848 		case AS_GET_SYSTEM_FONTS:
1849 		{
1850 			FTRACE(("ServerApp %s: AS_GET_SYSTEM_FONTS\n", Signature()));
1851 			// Returns:
1852 			// 1) uint16 - family ID
1853 			// 2) uint16 - style ID
1854 			// 3) float - size in points
1855 			// 4) uint16 - face flags
1856 			// 5) uint32 - font flags
1857 
1858 			if (!fDesktop->LockSingleWindow()) {
1859 				fLink.StartMessage(B_OK);
1860 				fLink.Flush();
1861 				break;
1862 			}
1863 
1864 			// The client is requesting the system fonts, this
1865 			// could have happened either at application start up,
1866 			// or because the client is resyncing with the global
1867 			// fonts. So we record the current system wide fonts
1868 			// into our own copies at this point.
1869 			DesktopSettings settings(fDesktop);
1870 
1871 			settings.GetDefaultPlainFont(fPlainFont);
1872 			settings.GetDefaultBoldFont(fBoldFont);
1873 			settings.GetDefaultFixedFont(fFixedFont);
1874 
1875 			fLink.StartMessage(B_OK);
1876 
1877 			for (int32 i = 0; i < 3; i++) {
1878 				ServerFont* font = NULL;
1879 				switch (i) {
1880 					case 0:
1881 						font = &fPlainFont;
1882 						fLink.AttachString("plain");
1883 						break;
1884 
1885 					case 1:
1886 						font = &fBoldFont;
1887 						fLink.AttachString("bold");
1888 						break;
1889 
1890 					case 2:
1891 						font = &fFixedFont;
1892 						fLink.AttachString("fixed");
1893 						break;
1894 				}
1895 
1896 				fLink.Attach<uint16>(font->FamilyID());
1897 				fLink.Attach<uint16>(font->StyleID());
1898 				fLink.Attach<float>(font->Size());
1899 				fLink.Attach<uint16>(font->Face());
1900 				fLink.Attach<uint32>(font->Flags());
1901 			}
1902 
1903 			fDesktop->UnlockSingleWindow();
1904 			fLink.Flush();
1905 			break;
1906 		}
1907 
1908 		case AS_GET_FONT_LIST_REVISION:
1909 		{
1910 			FTRACE(("ServerApp %s: AS_GET_FONT_LIST_REVISION\n", Signature()));
1911 
1912 			fLink.StartMessage(B_OK);
1913 			fLink.Attach<int32>(
1914 				gFontManager->CheckRevision(fDesktop->UserID()));
1915 			fLink.Flush();
1916 			break;
1917 		}
1918 
1919 		case AS_GET_FAMILY_AND_STYLES:
1920 		{
1921 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLES\n", Signature()));
1922 
1923 			// Attached Data:
1924 			// 1) int32 the index of the font family to get
1925 
1926 			// Returns:
1927 			// 1) string - name of family
1928 			// 2) uint32 - flags of font family (B_IS_FIXED || B_HAS_TUNED_FONT)
1929 			// 3) count of styles in that family
1930 			// For each style:
1931 			//		1) string - name of style
1932 			//		2) uint16 - face of style
1933 			//		3) uint32 - flags of style
1934 
1935 			int32 index;
1936 			link.Read<int32>(&index);
1937 
1938 			AutoLocker< ::FontManager> fontLock(gFontManager);
1939 
1940 			FontFamily* family = gFontManager->FamilyAt(index);
1941 			if (family == NULL) {
1942 				fontLock.SetTo(fAppFontManager, false);
1943 
1944 				family = fAppFontManager->FamilyAt(index);
1945 			}
1946 
1947 			if (family) {
1948 				fLink.StartMessage(B_OK);
1949 				fLink.AttachString(family->Name());
1950 				fLink.Attach<uint32>(family->Flags());
1951 
1952 				int32 count = family->CountStyles();
1953 
1954 				fLink.Attach<int32>(count);
1955 
1956 				for (int32 i = 0; i < count; i++) {
1957 					FontStyle* style = family->StyleAt(i);
1958 
1959 					fLink.AttachString(style->Name());
1960 					fLink.Attach<uint16>(style->Face());
1961 					fLink.Attach<uint32>(style->Flags());
1962 				}
1963 			} else
1964 				fLink.StartMessage(B_BAD_VALUE);
1965 
1966 
1967 			fLink.Flush();
1968 			break;
1969 		}
1970 
1971 		case AS_GET_FAMILY_AND_STYLE:
1972 		{
1973 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE\n", Signature()));
1974 
1975 			// Attached Data:
1976 			// 1) uint16 - family ID
1977 			// 2) uint16 - style ID
1978 
1979 			// Returns:
1980 			// 1) font_family The name of the font family
1981 			// 2) font_style - name of the style
1982 
1983 			uint16 familyID, styleID;
1984 			link.Read<uint16>(&familyID);
1985 			link.Read<uint16>(&styleID);
1986 
1987 			AutoLocker< ::FontManager> fontLock(gFontManager);
1988 
1989 			FontStyle* fontStyle = gFontManager->GetStyle(familyID, styleID);
1990 			if (fontStyle == NULL) {
1991 				fontLock.SetTo(fAppFontManager, false);
1992 
1993 				fontStyle = fAppFontManager->GetStyle(familyID, styleID);
1994 			}
1995 
1996 			if (fontStyle != NULL) {
1997 				fLink.StartMessage(B_OK);
1998 				fLink.AttachString(fontStyle->Family()->Name());
1999 				fLink.AttachString(fontStyle->Name());
2000 			} else
2001 				fLink.StartMessage(B_BAD_VALUE);
2002 
2003 			fLink.Flush();
2004 
2005 			break;
2006 		}
2007 
2008 		case AS_GET_FAMILY_AND_STYLE_IDS:
2009 		{
2010 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE_IDS\n",
2011 				Signature()));
2012 
2013 			// Attached Data:
2014 			// 1) font_family - name of font family to use
2015 			// 2) font_style - name of style in family
2016 			// 3) family ID - only used if 1) is empty
2017 			// 4) style ID - only used if 2) is empty
2018 			// 5) face - the font's current face
2019 
2020 			// Returns:
2021 			// 1) uint16 - family ID
2022 			// 2) uint16 - style ID
2023 			// 3) uint16 - face
2024 
2025 			font_family family;
2026 			font_style style;
2027 			uint16 familyID, styleID;
2028 			uint16 face;
2029 			if (link.ReadString(family, sizeof(font_family)) == B_OK
2030 				&& link.ReadString(style, sizeof(font_style)) == B_OK
2031 				&& link.Read<uint16>(&familyID) == B_OK
2032 				&& link.Read<uint16>(&styleID) == B_OK
2033 				&& link.Read<uint16>(&face) == B_OK) {
2034 				// get the font and return IDs and face
2035 				AutoLocker< ::FontManager> fontLock(gFontManager);
2036 
2037 				FontStyle* fontStyle = gFontManager->GetStyle(family, style,
2038 					familyID, styleID, face);
2039 				if (fontStyle == NULL) {
2040 					fontLock.SetTo(fAppFontManager, false);
2041 
2042 					fontStyle = fAppFontManager->GetStyle(family, style,
2043 						familyID, styleID, face);
2044 				}
2045 
2046 				if (fontStyle != NULL) {
2047 					fLink.StartMessage(B_OK);
2048 					fLink.Attach<uint16>(fontStyle->Family()->ID());
2049 					fLink.Attach<uint16>(fontStyle->ID());
2050 
2051 					// we try to keep the font face close to what we got
2052 					face = fontStyle->PreservedFace(face);
2053 
2054 					fLink.Attach<uint16>(face);
2055 				} else
2056 					fLink.StartMessage(B_NAME_NOT_FOUND);
2057 			} else
2058 				fLink.StartMessage(B_BAD_VALUE);
2059 
2060 			fLink.Flush();
2061 			break;
2062 		}
2063 
2064 		case AS_GET_FONT_FILE_FORMAT:
2065 		{
2066 			FTRACE(("ServerApp %s: AS_GET_FONT_FILE_FORMAT\n", Signature()));
2067 
2068 			// Attached Data:
2069 			// 1) uint16 - family ID
2070 			// 2) uint16 - style ID
2071 
2072 			// Returns:
2073 			// 1) uint16 font_file_format of font
2074 
2075 			int32 familyID, styleID;
2076 			link.Read<int32>(&familyID);
2077 			link.Read<int32>(&styleID);
2078 
2079 			AutoLocker< ::FontManager> fontLock(gFontManager);
2080 
2081 			FontStyle* fontStyle = gFontManager->GetStyle(familyID, styleID);
2082 			if (fontStyle == NULL) {
2083 				fontLock.SetTo(fAppFontManager, false);
2084 
2085 				fontStyle = fAppFontManager->GetStyle(familyID, styleID);
2086 			}
2087 
2088 			if (fontStyle != NULL) {
2089 				fLink.StartMessage(B_OK);
2090 				fLink.Attach<uint16>((uint16)fontStyle->FileFormat());
2091 			} else
2092 				fLink.StartMessage(B_BAD_VALUE);
2093 
2094 			fLink.Flush();
2095 			break;
2096 		}
2097 
2098 		case AS_GET_STRING_WIDTHS:
2099 		{
2100 			FTRACE(("ServerApp %s: AS_GET_STRING_WIDTHS\n", Signature()));
2101 
2102 			// Attached Data:
2103 			// 1) uint16 ID of family
2104 			// 2) uint16 ID of style
2105 			// 3) float point size of font
2106 			// 4) uint8 spacing to use
2107 			// 5) int32 numStrings
2108 			// 6) int32 string length to measure (numStrings times)
2109 			// 7) string String to measure (numStrings times)
2110 
2111 			// Returns:
2112 			// 1) float - width of the string in pixels (numStrings times)
2113 
2114 			uint16 familyID, styleID;
2115 			float size;
2116 			uint8 spacing;
2117 
2118 			link.Read<uint16>(&familyID);
2119 			link.Read<uint16>(&styleID);
2120 			link.Read<float>(&size);
2121 			link.Read<uint8>(&spacing);
2122 			int32 numStrings;
2123 			if (link.Read<int32>(&numStrings) != B_OK) {
2124 				// this results in a B_BAD_VALUE return
2125 				numStrings = 0;
2126 				size = 0.0f;
2127 			}
2128 
2129 			BStackOrHeapArray<float, 64> widthArray(numStrings);
2130 			BStackOrHeapArray<int32, 64> lengthArray(numStrings);
2131 			BStackOrHeapArray<char*, 64> stringArray(numStrings);
2132 			if (!widthArray.IsValid() || !lengthArray.IsValid()
2133 				|| !stringArray.IsValid()) {
2134 				fLink.StartMessage(B_NO_MEMORY);
2135 				fLink.Flush();
2136 				break;
2137 			}
2138 
2139 			for (int32 i = 0; i < numStrings; i++) {
2140 				// This version of ReadString allocates the strings, we free
2141 				// them below
2142 				link.ReadString(&stringArray[i], (size_t *)&lengthArray[i]);
2143 			}
2144 
2145 			ServerFont font;
2146 
2147 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2148 				fAppFontManager);
2149 
2150 			if (status == B_OK && size > 0) {
2151 				font.SetSize(size);
2152 				font.SetSpacing(spacing);
2153 
2154 				for (int32 i = 0; i < numStrings; i++) {
2155 					if (!stringArray[i] || lengthArray[i] <= 0)
2156 						widthArray[i] = 0.0;
2157 					else {
2158 						widthArray[i] = font.StringWidth(stringArray[i],
2159 							lengthArray[i]);
2160 					}
2161 				}
2162 
2163 				fLink.StartMessage(B_OK);
2164 				fLink.Attach(widthArray, numStrings * sizeof(float));
2165 			} else
2166 				fLink.StartMessage(B_BAD_VALUE);
2167 
2168 			fLink.Flush();
2169 
2170 			for (int32 i = 0; i < numStrings; i++)
2171 				free(stringArray[i]);
2172 			break;
2173 		}
2174 
2175 		case AS_GET_FONT_BOUNDING_BOX:
2176 		{
2177 			FTRACE(("ServerApp %s: AS_GET_BOUNDING_BOX\n",
2178 				Signature()));
2179 
2180 			// Attached Data:
2181 			// 1) uint16 - family ID
2182 			// 2) uint16 - style ID
2183 			// 3) float - font size
2184 
2185 			// Returns:
2186 			// 1) BRect - box holding entire font
2187 
2188 			uint16 familyID, styleID;
2189 			float size;
2190 
2191 			link.Read<uint16>(&familyID);
2192 			link.Read<uint16>(&styleID);
2193 			link.Read<float>(&size);
2194 
2195 			ServerFont font;
2196 
2197 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2198 				fAppFontManager);
2199 
2200 			if (status == B_OK && size > 0) {
2201 				font.SetSize(size);
2202 
2203 				fLink.StartMessage(B_OK);
2204 				fLink.Attach<BRect>(font.BoundingBox());
2205 			} else
2206 				fLink.StartMessage(B_BAD_VALUE);
2207 
2208 			fLink.Flush();
2209 			break;
2210 		}
2211 
2212 		case AS_GET_TUNED_COUNT:
2213 		{
2214 			FTRACE(("ServerApp %s: AS_GET_TUNED_COUNT\n", Signature()));
2215 
2216 			// Attached Data:
2217 			// 1) uint16 - family ID
2218 			// 2) uint16 - style ID
2219 
2220 			// Returns:
2221 			// 1) int32 - number of font strikes available
2222 
2223 			uint16 familyID, styleID;
2224 			link.Read<uint16>(&familyID);
2225 			link.Read<uint16>(&styleID);
2226 
2227 			AutoLocker< ::FontManager> fontLock(gFontManager);
2228 
2229 			FontStyle* fontStyle = gFontManager->GetStyle(familyID, styleID);
2230 			if (fontStyle == NULL) {
2231 				fontLock.SetTo(fAppFontManager, false);
2232 
2233 				fontStyle = fAppFontManager->GetStyle(familyID, styleID);
2234 			}
2235 
2236 			if (fontStyle != NULL) {
2237 				fLink.StartMessage(B_OK);
2238 				fLink.Attach<int32>(fontStyle->TunedCount());
2239 			} else
2240 				fLink.StartMessage(B_BAD_VALUE);
2241 
2242 			fLink.Flush();
2243 			break;
2244 		}
2245 
2246 		case AS_GET_TUNED_INFO:
2247 		{
2248 			FTRACE(("ServerApp %s: AS_GET_TUNED_INFO unimplmemented\n",
2249 				Signature()));
2250 
2251 			// Attached Data:
2252 			// 1) uint16 - family ID
2253 			// 2) uint16 - style ID
2254 			// 3) uint32 - index of the particular font strike
2255 
2256 			// Returns:
2257 			// 1) tuned_font_info - info on the strike specified
2258 			// ToDo: implement me!
2259 
2260 			fLink.StartMessage(B_ERROR);
2261 			fLink.Flush();
2262 			break;
2263 		}
2264 
2265 		case AS_GET_EXTRA_FONT_FLAGS:
2266 		{
2267 			FTRACE(("ServerApp %s: AS_GET_EXTRA_FONT_FLAGS\n",
2268 				Signature()));
2269 
2270 			// Attached Data:
2271 			// 1) uint16 - family ID
2272 			// 2) uint16 - style ID
2273 
2274 			// Returns:
2275 			// 1) uint32 - extra font flags
2276 
2277 			uint16 familyID, styleID;
2278 			link.Read<uint16>(&familyID);
2279 			link.Read<uint16>(&styleID);
2280 
2281 			AutoLocker< ::FontManager> fontLock(gFontManager);
2282 
2283 			FontStyle* fontStyle = gFontManager->GetStyle(familyID, styleID);
2284 			if (fontStyle == NULL) {
2285 				fontLock.SetTo(fAppFontManager, false);
2286 
2287 				fontStyle = fAppFontManager->GetStyle(familyID, styleID);
2288 			}
2289 
2290 			if (fontStyle != NULL) {
2291 				fLink.StartMessage(B_OK);
2292 				fLink.Attach<uint32>(fontStyle->Flags());
2293 			} else
2294 				fLink.StartMessage(B_BAD_VALUE);
2295 
2296 			fLink.Flush();
2297 			break;
2298 		}
2299 
2300 		case AS_GET_FONT_HEIGHT:
2301 		{
2302 			FTRACE(("ServerApp %s: AS_GET_FONT_HEIGHT\n", Signature()));
2303 
2304 			// Attached Data:
2305 			// 1) uint16 family ID
2306 			// 2) uint16 style ID
2307 			// 3) float size
2308 
2309 			uint16 familyID, styleID;
2310 			float size;
2311 			link.Read<uint16>(&familyID);
2312 			link.Read<uint16>(&styleID);
2313 			link.Read<float>(&size);
2314 
2315 			AutoLocker< ::FontManager> fontLock(gFontManager);
2316 
2317 			FontStyle* fontStyle = gFontManager->GetStyle(familyID, styleID);
2318 			if (fontStyle == NULL) {
2319 				fontLock.SetTo(fAppFontManager, false);
2320 
2321 				fontStyle = fAppFontManager->GetStyle(familyID, styleID);
2322 			}
2323 
2324 			if (fontStyle != NULL) {
2325 				font_height height;
2326 				fontStyle->GetHeight(size, height);
2327 
2328 				fLink.StartMessage(B_OK);
2329 				fLink.Attach<font_height>(height);
2330 			} else
2331 				fLink.StartMessage(B_BAD_VALUE);
2332 
2333 			fLink.Flush();
2334 			break;
2335 		}
2336 
2337 		case AS_GET_UNICODE_BLOCKS:
2338 		{
2339 			FTRACE(("ServerApp %s: AS_GET_UNICODE_BLOCKS\n", Signature()));
2340 
2341 			// Attached Data:
2342 			// 1) uint16 family ID
2343 			// 2) uint16 style ID
2344 
2345 			// Returns:
2346 			// 1) unicode_block - bitfield of Unicode blocks in font
2347 
2348 			uint16 familyID, styleID;
2349 			link.Read<uint16>(&familyID);
2350 			link.Read<uint16>(&styleID);
2351 
2352 			ServerFont font;
2353 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2354 				fAppFontManager);
2355 
2356 			if (status == B_OK) {
2357 				unicode_block blocksForFont;
2358 				font.GetUnicodeBlocks(blocksForFont);
2359 
2360 				fLink.StartMessage(B_OK);
2361 				fLink.Attach<unicode_block>(blocksForFont);
2362 			} else
2363 				fLink.StartMessage(status);
2364 
2365 			fLink.Flush();
2366 			break;
2367 		}
2368 
2369 		case AS_GET_HAS_UNICODE_BLOCK:
2370 		{
2371 			FTRACE(("ServerApp %s: AS_INCLUDES_UNICODE_BLOCK\n", Signature()));
2372 
2373 			// Attached Data:
2374 			// 1) uint16 family ID
2375 			// 2) uint16 style ID
2376 			// 3) uint32 start of unicode block
2377 			// 4) uint32 end of unicode block
2378 
2379 			// Returns:
2380 			// 1) bool - whether or not font includes specified block range
2381 
2382 			uint16 familyID, styleID;
2383 			uint32 start, end;
2384 			link.Read<uint16>(&familyID);
2385 			link.Read<uint16>(&styleID);
2386 			link.Read<uint32>(&start);
2387 			link.Read<uint32>(&end);
2388 
2389 			ServerFont font;
2390 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2391 				fAppFontManager);
2392 
2393 			if (status == B_OK) {
2394 				bool hasBlock;
2395 
2396 				status = font.IncludesUnicodeBlock(start, end, hasBlock);
2397 				fLink.StartMessage(status);
2398 				fLink.Attach<bool>(hasBlock);
2399 			} else
2400 				fLink.StartMessage(status);
2401 
2402 			fLink.Flush();
2403 			break;
2404 		}
2405 
2406 		case AS_GET_GLYPH_SHAPES:
2407 		{
2408 			FTRACE(("ServerApp %s: AS_GET_GLYPH_SHAPES\n", Signature()));
2409 
2410 			// Attached Data:
2411 			// 1) uint16 - family ID
2412 			// 2) uint16 - style ID
2413 			// 3) float - point size
2414 			// 4) float - shear
2415 			// 5) float - rotation
2416 			// 6) float - false bold width
2417 			// 6) uint32 - flags
2418 			// 7) int32 - numChars
2419 			// 8) int32 - numBytes
2420 			// 8) char - chars (numBytes times)
2421 
2422 			// Returns:
2423 			// 1) BShape - glyph shape
2424 			// numChars times
2425 
2426 			uint16 familyID, styleID;
2427 			uint32 flags;
2428 			float size, shear, rotation, falseBoldWidth;
2429 
2430 			link.Read<uint16>(&familyID);
2431 			link.Read<uint16>(&styleID);
2432 			link.Read<float>(&size);
2433 			link.Read<float>(&shear);
2434 			link.Read<float>(&rotation);
2435 			link.Read<float>(&falseBoldWidth);
2436 			link.Read<uint32>(&flags);
2437 
2438 			int32 numChars, numBytes;
2439 			link.Read<int32>(&numChars);
2440 			link.Read<int32>(&numBytes);
2441 
2442 			BStackOrHeapArray<char, 256> charArray(numBytes);
2443 			BStackOrHeapArray<BShape*, 64> shapes(numChars);
2444 			if (!charArray.IsValid() || !shapes.IsValid()) {
2445 				fLink.StartMessage(B_NO_MEMORY);
2446 				fLink.Flush();
2447 				break;
2448 			}
2449 
2450 			link.Read(charArray, numBytes);
2451 
2452 			ServerFont font;
2453 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2454 				fAppFontManager);
2455 
2456 			if (status == B_OK) {
2457 				font.SetSize(size);
2458 				font.SetShear(shear);
2459 				font.SetRotation(rotation);
2460 				font.SetFalseBoldWidth(falseBoldWidth);
2461 				font.SetFlags(flags);
2462 
2463 				status = font.GetGlyphShapes(charArray, numChars, shapes);
2464 				if (status == B_OK) {
2465 					fLink.StartMessage(B_OK);
2466 					for (int32 i = 0; i < numChars; i++) {
2467 						fLink.AttachShape(*shapes[i]);
2468 						delete shapes[i];
2469 					}
2470 				}
2471 			}
2472 
2473 			if (status != B_OK)
2474 				fLink.StartMessage(status);
2475 
2476 			fLink.Flush();
2477 			break;
2478 		}
2479 
2480 		case AS_GET_HAS_GLYPHS:
2481 		{
2482 			FTRACE(("ServerApp %s: AS_GET_HAS_GLYPHS\n", Signature()));
2483 
2484 			// Attached Data:
2485 			// 1) uint16 - family ID
2486 			// 2) uint16 - style ID
2487 			// 3) int32 - numChars
2488 			// 4) int32 - numBytes
2489 			// 5) char - the char buffer with size numBytes
2490 
2491 			uint16 familyID, styleID;
2492 			link.Read<uint16>(&familyID);
2493 			link.Read<uint16>(&styleID);
2494 
2495 			int32 numChars, numBytes;
2496 			link.Read<int32>(&numChars);
2497 			link.Read<int32>(&numBytes);
2498 
2499 			BStackOrHeapArray<char, 256> charArray(numBytes);
2500 			BStackOrHeapArray<bool, 256> hasArray(numChars);
2501 			if (!charArray.IsValid() || !hasArray.IsValid()) {
2502 				fLink.StartMessage(B_NO_MEMORY);
2503 				fLink.Flush();
2504 				break;
2505 			}
2506 
2507 			link.Read(charArray, numBytes);
2508 
2509 			ServerFont font;
2510 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2511 				fAppFontManager);
2512 
2513 			if (status == B_OK) {
2514 				status = font.GetHasGlyphs(charArray, numBytes, numChars,
2515 					hasArray);
2516 				if (status == B_OK) {
2517 					fLink.StartMessage(B_OK);
2518 					fLink.Attach(hasArray, numChars * sizeof(bool));
2519 				}
2520 			}
2521 
2522 			if (status != B_OK)
2523 				fLink.StartMessage(status);
2524 
2525 			fLink.Flush();
2526 			break;
2527 		}
2528 
2529 		case AS_GET_EDGES:
2530 		{
2531 			FTRACE(("ServerApp %s: AS_GET_EDGES\n", Signature()));
2532 
2533 			// Attached Data:
2534 			// 1) uint16 - family ID
2535 			// 2) uint16 - style ID
2536 			// 3) int32 - numChars
2537 			// 4) int32 - numBytes
2538 			// 5) char - the char buffer with size numBytes
2539 
2540 			uint16 familyID, styleID;
2541 			link.Read<uint16>(&familyID);
2542 			link.Read<uint16>(&styleID);
2543 
2544 			int32 numChars;
2545 			link.Read<int32>(&numChars);
2546 
2547 			uint32 numBytes;
2548 			link.Read<uint32>(&numBytes);
2549 
2550 			BStackOrHeapArray<char, 256> charArray(numBytes);
2551 			BStackOrHeapArray<edge_info, 64> edgeArray(numChars);
2552 			if (!charArray.IsValid() || !edgeArray.IsValid()) {
2553 				fLink.StartMessage(B_NO_MEMORY);
2554 				fLink.Flush();
2555 				break;
2556 			}
2557 
2558 			link.Read(charArray, numBytes);
2559 
2560 			ServerFont font;
2561 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2562 				fAppFontManager);
2563 
2564 			if (status == B_OK) {
2565 				status = font.GetEdges(charArray, numBytes, numChars,
2566 					edgeArray);
2567 				if (status == B_OK) {
2568 					fLink.StartMessage(B_OK);
2569 					fLink.Attach(edgeArray, numChars * sizeof(edge_info));
2570 				}
2571 			}
2572 
2573 			if (status != B_OK)
2574 				fLink.StartMessage(status);
2575 
2576 			fLink.Flush();
2577 			break;
2578 		}
2579 
2580 		case AS_GET_ESCAPEMENTS:
2581 		{
2582 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS\n", Signature()));
2583 
2584 			// Attached Data:
2585 			// 1) uint16 - family ID
2586 			// 2) uint16 - style ID
2587 			// 3) float - point size
2588 			// 4) uint8 - spacing
2589 			// 5) float - rotation
2590 			// 6) uint32 - flags
2591 			// 7) int32 - numChars
2592 			// 8) char - char     -\       both
2593 			// 9) BPoint - offset -/ (numChars times)
2594 
2595 			// Returns:
2596 			// 1) BPoint - escapement
2597 			// numChars times
2598 
2599 			uint16 familyID, styleID;
2600 			uint32 flags;
2601 			float size, rotation;
2602 			uint8 spacing;
2603 
2604 			link.Read<uint16>(&familyID);
2605 			link.Read<uint16>(&styleID);
2606 			link.Read<float>(&size);
2607 			link.Read<uint8>(&spacing);
2608 			link.Read<float>(&rotation);
2609 			link.Read<uint32>(&flags);
2610 
2611 			escapement_delta delta;
2612 			link.Read<float>(&delta.nonspace);
2613 			link.Read<float>(&delta.space);
2614 
2615 			bool wantsOffsets;
2616 			link.Read<bool>(&wantsOffsets);
2617 
2618 			int32 numChars;
2619 			link.Read<int32>(&numChars);
2620 
2621 			uint32 numBytes;
2622 			link.Read<uint32>(&numBytes);
2623 
2624 			BStackOrHeapArray<char, 256> charArray(numBytes);
2625 			BStackOrHeapArray<BPoint, 64> escapements(numChars);
2626 			BPoint* offsets = NULL;
2627 			if (wantsOffsets)
2628 				offsets = new(std::nothrow) BPoint[numChars];
2629 
2630 			if (!charArray.IsValid() || !escapements.IsValid()
2631 				|| (offsets == NULL && wantsOffsets)) {
2632 				delete[] offsets;
2633 				fLink.StartMessage(B_NO_MEMORY);
2634 				fLink.Flush();
2635 				break;
2636 			}
2637 
2638 			link.Read(charArray, numBytes);
2639 
2640 			ServerFont font;
2641 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2642 				fAppFontManager);
2643 
2644 			if (status == B_OK) {
2645 				font.SetSize(size);
2646 				font.SetSpacing(spacing);
2647 				font.SetRotation(rotation);
2648 				font.SetFlags(flags);
2649 
2650 				status = font.GetEscapements(charArray, numBytes, numChars,
2651 					delta, escapements, offsets);
2652 
2653 				if (status == B_OK) {
2654 					fLink.StartMessage(B_OK);
2655 					for (int32 i = 0; i < numChars; i++)
2656 						fLink.Attach<BPoint>(escapements[i]);
2657 
2658 					if (wantsOffsets) {
2659 						for (int32 i = 0; i < numChars; i++)
2660 							fLink.Attach<BPoint>(offsets[i]);
2661 					}
2662 				}
2663 			}
2664 
2665 			if (status != B_OK)
2666 				fLink.StartMessage(status);
2667 
2668 			delete[] offsets;
2669 			fLink.Flush();
2670 			break;
2671 		}
2672 
2673 		case AS_GET_ESCAPEMENTS_AS_FLOATS:
2674 		{
2675 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS_AS_FLOATS\n", Signature()));
2676 
2677 			// Attached Data:
2678 			// 1) uint16 - family ID
2679 			// 2) uint16 - style ID
2680 			// 3) float - point size
2681 			// 4) uint8 - spacing
2682 			// 5) float - rotation
2683 			// 6) uint32 - flags
2684 			// 7) float - additional "nonspace" delta
2685 			// 8) float - additional "space" delta
2686 			// 9) int32 - numChars
2687 			// 10) int32 - numBytes
2688 			// 11) char - the char buffer with size numBytes
2689 
2690 			// Returns:
2691 			// 1) float - escapement buffer with numChar entries
2692 
2693 			uint16 familyID, styleID;
2694 			uint32 flags;
2695 			float size, rotation;
2696 			uint8 spacing;
2697 
2698 			link.Read<uint16>(&familyID);
2699 			link.Read<uint16>(&styleID);
2700 			link.Read<float>(&size);
2701 			link.Read<uint8>(&spacing);
2702 			link.Read<float>(&rotation);
2703 			link.Read<uint32>(&flags);
2704 
2705 			escapement_delta delta;
2706 			link.Read<float>(&delta.nonspace);
2707 			link.Read<float>(&delta.space);
2708 
2709 			int32 numChars;
2710 			link.Read<int32>(&numChars);
2711 
2712 			uint32 numBytes;
2713 			link.Read<uint32>(&numBytes);
2714 
2715 			BStackOrHeapArray<char, 256> charArray(numBytes);
2716 			BStackOrHeapArray<float, 64> escapements(numChars);
2717 			if (!charArray.IsValid() || !escapements.IsValid()) {
2718 				fLink.StartMessage(B_NO_MEMORY);
2719 				fLink.Flush();
2720 				break;
2721 			}
2722 
2723 			link.Read(charArray, numBytes);
2724 
2725 			// figure out escapements
2726 
2727 			ServerFont font;
2728 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2729 				fAppFontManager);
2730 
2731 			if (status == B_OK) {
2732 				font.SetSize(size);
2733 				font.SetSpacing(spacing);
2734 				font.SetRotation(rotation);
2735 				font.SetFlags(flags);
2736 
2737 				status = font.GetEscapements(charArray, numBytes, numChars,
2738 					delta, escapements);
2739 
2740 				if (status == B_OK) {
2741 					fLink.StartMessage(B_OK);
2742 					fLink.Attach(escapements, numChars * sizeof(float));
2743 				}
2744 			}
2745 
2746 			if (status != B_OK)
2747 				fLink.StartMessage(status);
2748 
2749 			fLink.Flush();
2750 			break;
2751 		}
2752 
2753 		case AS_GET_BOUNDINGBOXES_CHARS:
2754 		case AS_GET_BOUNDINGBOXES_STRING:
2755 		{
2756 			FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_CHARS\n", Signature()));
2757 
2758 			// Attached Data:
2759 			// 1) uint16 - family ID
2760 			// 2) uint16 - style ID
2761 			// 3) float - point size
2762 			// 4) float - rotation
2763 			// 5) float - shear
2764 			// 6) float - false bold width
2765 			// 7) uint8 - spacing
2766 			// 8) uint32 - flags
2767 			// 9) font_metric_mode - mode
2768 			// 10) bool - string escapement
2769 			// 11) escapement_delta - additional delta
2770 			// 12) int32 - numChars
2771 			// 13) int32 - numBytes
2772 			// 14) char - the char buffer with size numBytes
2773 
2774 			// Returns:
2775 			// 1) BRect - rects with numChar entries
2776 
2777 			uint16 familyID, styleID;
2778 			uint32 flags;
2779 			float size, rotation, shear, falseBoldWidth;
2780 			uint8 spacing;
2781 			font_metric_mode mode;
2782 			bool stringEscapement;
2783 
2784 			link.Read<uint16>(&familyID);
2785 			link.Read<uint16>(&styleID);
2786 			link.Read<float>(&size);
2787 			link.Read<float>(&rotation);
2788 			link.Read<float>(&shear);
2789 			link.Read<float>(&falseBoldWidth);
2790 			link.Read<uint8>(&spacing);
2791 			link.Read<uint32>(&flags);
2792 			link.Read<font_metric_mode>(&mode);
2793 			link.Read<bool>(&stringEscapement);
2794 
2795 			escapement_delta delta;
2796 			link.Read<escapement_delta>(&delta);
2797 
2798 			int32 numChars;
2799 			link.Read<int32>(&numChars);
2800 
2801 			uint32 numBytes;
2802 			link.Read<uint32>(&numBytes);
2803 
2804 			BStackOrHeapArray<char, 256> charArray(numBytes);
2805 			BStackOrHeapArray<BRect, 64> rectArray(numChars);
2806 			if (!charArray.IsValid() || !rectArray.IsValid()) {
2807 				fLink.StartMessage(B_NO_MEMORY);
2808 				fLink.Flush();
2809 				break;
2810 			}
2811 
2812 			link.Read(charArray, numBytes);
2813 
2814 			// figure out escapements
2815 
2816 			ServerFont font;
2817 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2818 				fAppFontManager);
2819 
2820 			if (status == B_OK) {
2821 				font.SetSize(size);
2822 				font.SetRotation(rotation);
2823 				font.SetShear(shear);
2824 				font.SetFalseBoldWidth(falseBoldWidth);
2825 				font.SetSpacing(spacing);
2826 				font.SetFlags(flags);
2827 
2828 				// TODO: implement for real
2829 				status = font.GetBoundingBoxes(charArray, numBytes,
2830 					numChars, rectArray, stringEscapement, mode, delta,
2831 					code == AS_GET_BOUNDINGBOXES_STRING);
2832 				if (status == B_OK) {
2833 					fLink.StartMessage(B_OK);
2834 					for (int32 i = 0; i < numChars; i++)
2835 						fLink.Attach<BRect>(rectArray[i]);
2836 				}
2837 			}
2838 
2839 			if (status != B_OK)
2840 				fLink.StartMessage(status);
2841 
2842 			fLink.Flush();
2843 			break;
2844 		}
2845 
2846 		case AS_GET_BOUNDINGBOXES_STRINGS:
2847 		{
2848 			FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_STRINGS\n",
2849 				Signature()));
2850 
2851 			// Attached Data:
2852 			// 1) uint16 - family ID
2853 			// 2) uint16 - style ID
2854 			// 3) float - point size
2855 			// 4) float - rotation
2856 			// 5) float - shear
2857 			// 6) float - false bold width
2858 			// 7) uint8 - spacing
2859 			// 8) uint32 - flags
2860 			// 9) font_metric_mode - mode
2861 			// 10) int32 numStrings
2862 			// 11) escapement_delta - additional delta (numStrings times)
2863 			// 12) int32 string length to measure (numStrings times)
2864 			// 13) string - string (numStrings times)
2865 
2866 			// Returns:
2867 			// 1) BRect - rects with numStrings entries
2868 
2869 			uint16 familyID, styleID;
2870 			uint32 flags;
2871 			float ptsize, rotation, shear, falseBoldWidth;
2872 			uint8 spacing;
2873 			font_metric_mode mode;
2874 
2875 			link.Read<uint16>(&familyID);
2876 			link.Read<uint16>(&styleID);
2877 			link.Read<float>(&ptsize);
2878 			link.Read<float>(&rotation);
2879 			link.Read<float>(&shear);
2880 			link.Read<float>(&falseBoldWidth);
2881 			link.Read<uint8>(&spacing);
2882 			link.Read<uint32>(&flags);
2883 			link.Read<font_metric_mode>(&mode);
2884 
2885 			int32 numStrings;
2886 			link.Read<int32>(&numStrings);
2887 
2888 			BStackOrHeapArray<escapement_delta, 64> deltaArray(numStrings);
2889 			BStackOrHeapArray<char*, 64> stringArray(numStrings);
2890 			BStackOrHeapArray<size_t, 64> lengthArray(numStrings);
2891 			BStackOrHeapArray<BRect, 64> rectArray(numStrings);
2892 			if (!deltaArray.IsValid() || !stringArray.IsValid()
2893 				|| !lengthArray.IsValid() || !rectArray.IsValid()) {
2894 				fLink.StartMessage(B_NO_MEMORY);
2895 				fLink.Flush();
2896 				break;
2897 			}
2898 
2899 			for (int32 i = 0; i < numStrings; i++) {
2900 				// This version of ReadString allocates the strings, we free
2901 				// them below
2902 				link.ReadString(&stringArray[i], &lengthArray[i]);
2903 				link.Read<escapement_delta>(&deltaArray[i]);
2904 			}
2905 
2906 			ServerFont font;
2907 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2908 				fAppFontManager);
2909 
2910 			if (status == B_OK) {
2911 				font.SetSize(ptsize);
2912 				font.SetRotation(rotation);
2913 				font.SetShear(shear);
2914 				font.SetFalseBoldWidth(falseBoldWidth);
2915 				font.SetSpacing(spacing);
2916 				font.SetFlags(flags);
2917 
2918 				status = font.GetBoundingBoxesForStrings(stringArray,
2919 					lengthArray, numStrings, rectArray, mode, deltaArray);
2920 				if (status == B_OK) {
2921 					fLink.StartMessage(B_OK);
2922 					fLink.Attach(rectArray, numStrings * sizeof(BRect));
2923 				}
2924 			}
2925 
2926 			for (int32 i = 0; i < numStrings; i++)
2927 				free(stringArray[i]);
2928 
2929 			if (status != B_OK)
2930 				fLink.StartMessage(status);
2931 
2932 			fLink.Flush();
2933 			break;
2934 		}
2935 
2936 		// Screen commands
2937 
2938 		case AS_VALID_SCREEN_ID:
2939 		{
2940 			// Attached data
2941 			// 1) int32 screen
2942 
2943 			int32 id;
2944 			if (link.Read<int32>(&id) == B_OK
2945 				&& id == B_MAIN_SCREEN_ID.id)
2946 				fLink.StartMessage(B_OK);
2947 			else
2948 				fLink.StartMessage(B_ERROR);
2949 
2950 			fLink.Flush();
2951 			break;
2952 		}
2953 
2954 		case AS_GET_NEXT_SCREEN_ID:
2955 		{
2956 			// Attached data
2957 			// 1) int32 screen
2958 
2959 			int32 id;
2960 			link.Read<int32>(&id);
2961 
2962 			// TODO: for now, just say we're the last one
2963 			fLink.StartMessage(B_ENTRY_NOT_FOUND);
2964 			fLink.Flush();
2965 			break;
2966 		}
2967 
2968 		case AS_GET_SCREEN_ID_FROM_WINDOW:
2969 		{
2970 			status_t status = B_BAD_VALUE;
2971 
2972 			// Attached data
2973 			// 1) int32 - window client token
2974 
2975 			int32 clientToken;
2976 			if (link.Read<int32>(&clientToken) != B_OK)
2977 				status = B_BAD_DATA;
2978 			else {
2979 				BAutolock locker(fWindowListLock);
2980 
2981 				for (int32 i = fWindowList.CountItems(); i-- > 0;) {
2982 					ServerWindow* serverWindow = fWindowList.ItemAt(i);
2983 
2984 					if (serverWindow->ClientToken() == clientToken) {
2985 						AutoReadLocker _(fDesktop->ScreenLocker());
2986 
2987 						// found it!
2988 						Window* window = serverWindow->Window();
2989 						const Screen* screen = NULL;
2990 						if (window != NULL)
2991 							screen = window->Screen();
2992 
2993 						if (screen == NULL) {
2994 							// The window hasn't been added to the desktop yet,
2995 							// or it's an offscreen window
2996 							break;
2997 						}
2998 
2999 						fLink.StartMessage(B_OK);
3000 						fLink.Attach<int32>(screen->ID());
3001 						status = B_OK;
3002 						break;
3003 					}
3004 				}
3005 			}
3006 
3007 			if (status != B_OK)
3008 				fLink.StartMessage(status);
3009 			fLink.Flush();
3010 			break;
3011 		}
3012 
3013 		case AS_SCREEN_GET_MODE:
3014 		{
3015 			STRACE(("ServerApp %s: AS_SCREEN_GET_MODE\n", Signature()));
3016 
3017 			// Attached data
3018 			// 1) int32 screen
3019 			// 2) uint32 workspace index
3020 
3021 			int32 id;
3022 			link.Read<int32>(&id);
3023 			uint32 workspace;
3024 			link.Read<uint32>(&workspace);
3025 
3026 			display_mode mode;
3027 			status_t status = fDesktop->GetScreenMode(workspace, id, mode);
3028 
3029 			fLink.StartMessage(status);
3030 			if (status == B_OK)
3031 				fLink.Attach<display_mode>(mode);
3032 			fLink.Flush();
3033 			break;
3034 		}
3035 
3036 		case AS_SCREEN_SET_MODE:
3037 		{
3038 			STRACE(("ServerApp %s: AS_SCREEN_SET_MODE\n", Signature()));
3039 
3040 			// Attached data
3041 			// 1) int32 screen
3042 			// 2) workspace index
3043 			// 3) display_mode to set
3044 			// 4) 'makeDefault' boolean
3045 
3046 			int32 id;
3047 			link.Read<int32>(&id);
3048 			uint32 workspace;
3049 			link.Read<uint32>(&workspace);
3050 
3051 			display_mode mode;
3052 			link.Read<display_mode>(&mode);
3053 
3054 			bool makeDefault = false;
3055 			status_t status = link.Read<bool>(&makeDefault);
3056 
3057 			if (status == B_OK) {
3058 				status = fDesktop->SetScreenMode(workspace, id, mode,
3059 					makeDefault);
3060 			}
3061 			if (status == B_OK) {
3062 				if (workspace == (uint32)B_CURRENT_WORKSPACE_INDEX
3063 					&& fDesktop->LockSingleWindow()) {
3064 					workspace = fDesktop->CurrentWorkspace();
3065 					fDesktop->UnlockSingleWindow();
3066 				}
3067 
3068 				if (!makeDefault) {
3069 					// Memorize the screen change, so that it can be reverted
3070 					// later
3071 					fTemporaryDisplayModeChange |= 1 << workspace;
3072 				} else
3073 					fTemporaryDisplayModeChange &= ~(1 << workspace);
3074 			}
3075 
3076 			fLink.StartMessage(status);
3077 			fLink.Flush();
3078 			break;
3079 		}
3080 
3081 		case AS_PROPOSE_MODE:
3082 		{
3083 			STRACE(("ServerApp %s: AS_PROPOSE_MODE\n", Signature()));
3084 			int32 id;
3085 			link.Read<int32>(&id);
3086 
3087 			display_mode target, low, high;
3088 			link.Read<display_mode>(&target);
3089 			link.Read<display_mode>(&low);
3090 			link.Read<display_mode>(&high);
3091 			status_t status = fDesktop->HWInterface()->ProposeMode(&target,
3092 				&low, &high);
3093 
3094 			// ProposeMode() returns B_BAD_VALUE to hint that the candidate is
3095 			// not within the given limits (but is supported)
3096 			if (status == B_OK || status == B_BAD_VALUE) {
3097 				fLink.StartMessage(B_OK);
3098 				fLink.Attach<display_mode>(target);
3099 				fLink.Attach<bool>(status == B_OK);
3100 			} else
3101 				fLink.StartMessage(status);
3102 
3103 			fLink.Flush();
3104 			break;
3105 		}
3106 
3107 		case AS_GET_MODE_LIST:
3108 		{
3109 			int32 id;
3110 			link.Read<int32>(&id);
3111 			// TODO: use this screen id
3112 
3113 			display_mode* modeList;
3114 			uint32 count;
3115 			status_t status = fDesktop->HWInterface()->GetModeList(&modeList,
3116 				&count);
3117 			if (status == B_OK) {
3118 				fLink.StartMessage(B_OK);
3119 				fLink.Attach<uint32>(count);
3120 				fLink.Attach(modeList, sizeof(display_mode) * count);
3121 
3122 				delete[] modeList;
3123 			} else
3124 				fLink.StartMessage(status);
3125 
3126 			fLink.Flush();
3127 			break;
3128 		}
3129 
3130 		case AS_GET_SCREEN_FRAME:
3131 		{
3132 			STRACE(("ServerApp %s: AS_GET_SCREEN_FRAME\n", Signature()));
3133 
3134 			// Attached data
3135 			// 1) int32 screen
3136 			// 2) uint32 workspace index
3137 
3138 			int32 id;
3139 			link.Read<int32>(&id);
3140 			uint32 workspace;
3141 			link.Read<uint32>(&workspace);
3142 
3143 			BRect frame;
3144 			status_t status = fDesktop->GetScreenFrame(workspace, id, frame);
3145 
3146 			fLink.StartMessage(status);
3147 			if (status == B_OK)
3148 				fLink.Attach<BRect>(frame);
3149 
3150 			fLink.Flush();
3151 			break;
3152 		}
3153 
3154 		case AS_SCREEN_GET_COLORMAP:
3155 		{
3156 			STRACE(("ServerApp %s: AS_SCREEN_GET_COLORMAP\n", Signature()));
3157 
3158 			int32 id;
3159 			link.Read<int32>(&id);
3160 
3161 			const color_map* colorMap = SystemColorMap();
3162 			if (colorMap != NULL) {
3163 				fLink.StartMessage(B_OK);
3164 				fLink.Attach<color_map>(*colorMap);
3165 			} else
3166 				fLink.StartMessage(B_ERROR);
3167 
3168 			fLink.Flush();
3169 			break;
3170 		}
3171 
3172 		case AS_GET_DESKTOP_COLOR:
3173 		{
3174 			STRACE(("ServerApp %s: get desktop color\n", Signature()));
3175 
3176 			uint32 index;
3177 			link.Read<uint32>(&index);
3178 
3179 			fLink.StartMessage(B_OK);
3180 			fDesktop->LockSingleWindow();
3181 
3182 			// we're nice to our children (and also take the default case
3183 			// into account which asks for the current workspace)
3184 			if (index >= (uint32)kMaxWorkspaces)
3185 				index = fDesktop->CurrentWorkspace();
3186 
3187 			Workspace workspace(*fDesktop, index, true);
3188 			fLink.Attach<rgb_color>(workspace.Color());
3189 
3190 			fDesktop->UnlockSingleWindow();
3191 			fLink.Flush();
3192 			break;
3193 		}
3194 
3195 		case AS_SET_DESKTOP_COLOR:
3196 		{
3197 			STRACE(("ServerApp %s: set desktop color\n", Signature()));
3198 
3199 			rgb_color color;
3200 			uint32 index;
3201 			bool makeDefault;
3202 
3203 			link.Read<rgb_color>(&color);
3204 			link.Read<uint32>(&index);
3205 			if (link.Read<bool>(&makeDefault) != B_OK)
3206 				break;
3207 
3208 			fDesktop->LockAllWindows();
3209 
3210 			// we're nice to our children (and also take the default case
3211 			// into account which asks for the current workspace)
3212 			if (index >= (uint32)kMaxWorkspaces)
3213 				index = fDesktop->CurrentWorkspace();
3214 
3215 			Workspace workspace(*fDesktop, index);
3216 			workspace.SetColor(color, makeDefault);
3217 
3218 			fDesktop->UnlockAllWindows();
3219 			break;
3220 		}
3221 
3222 		case AS_GET_ACCELERANT_INFO:
3223 		{
3224 			STRACE(("ServerApp %s: get accelerant info\n", Signature()));
3225 
3226 			// We aren't using the screen_id for now...
3227 			int32 id;
3228 			link.Read<int32>(&id);
3229 
3230 			accelerant_device_info accelerantInfo;
3231 			// TODO: I wonder if there should be a "desktop" lock...
3232 			status_t status
3233 				= fDesktop->HWInterface()->GetDeviceInfo(&accelerantInfo);
3234 			if (status == B_OK) {
3235 				fLink.StartMessage(B_OK);
3236 				fLink.Attach<accelerant_device_info>(accelerantInfo);
3237 			} else
3238 				fLink.StartMessage(status);
3239 
3240 			fLink.Flush();
3241 			break;
3242 		}
3243 
3244 		case AS_GET_MONITOR_INFO:
3245 		{
3246 			STRACE(("ServerApp %s: get monitor info\n", Signature()));
3247 
3248 			// We aren't using the screen_id for now...
3249 			int32 id;
3250 			link.Read<int32>(&id);
3251 
3252 			monitor_info info;
3253 			// TODO: I wonder if there should be a "desktop" lock...
3254 			status_t status = fDesktop->HWInterface()->GetMonitorInfo(&info);
3255 			if (status == B_OK) {
3256 				fLink.StartMessage(B_OK);
3257 				fLink.Attach<monitor_info>(info);
3258 			} else
3259 				fLink.StartMessage(status);
3260 
3261 			fLink.Flush();
3262 			break;
3263 		}
3264 
3265 		case AS_GET_FRAME_BUFFER_CONFIG:
3266 		{
3267 			STRACE(("ServerApp %s: get frame buffer config\n", Signature()));
3268 
3269 			// We aren't using the screen_id for now...
3270 			int32 id;
3271 			link.Read<int32>(&id);
3272 
3273 			frame_buffer_config config;
3274 			// TODO: I wonder if there should be a "desktop" lock...
3275 			status_t status = fDesktop->HWInterface()->GetFrameBufferConfig(config);
3276 			if (status == B_OK) {
3277 				fLink.StartMessage(B_OK);
3278 				fLink.Attach<frame_buffer_config>(config);
3279 			} else
3280 				fLink.StartMessage(status);
3281 
3282 			fLink.Flush();
3283 			break;
3284 		}
3285 
3286 		case AS_GET_RETRACE_SEMAPHORE:
3287 		{
3288 			STRACE(("ServerApp %s: get retrace semaphore\n", Signature()));
3289 
3290 			// We aren't using the screen_id for now...
3291 			int32 id;
3292 			link.Read<int32>(&id);
3293 
3294 			fLink.StartMessage(B_OK);
3295 			fLink.Attach<sem_id>(fDesktop->HWInterface()->RetraceSemaphore());
3296 			fLink.Flush();
3297 			break;
3298 		}
3299 
3300 		case AS_GET_TIMING_CONSTRAINTS:
3301 		{
3302 			STRACE(("ServerApp %s: get timing constraints\n", Signature()));
3303 
3304 			// We aren't using the screen_id for now...
3305 			int32 id;
3306 			link.Read<int32>(&id);
3307 
3308 			display_timing_constraints constraints;
3309 			status_t status = fDesktop->HWInterface()->GetTimingConstraints(
3310 				&constraints);
3311 			if (status == B_OK) {
3312 				fLink.StartMessage(B_OK);
3313 				fLink.Attach<display_timing_constraints>(constraints);
3314 			} else
3315 				fLink.StartMessage(status);
3316 
3317 			fLink.Flush();
3318 			break;
3319 		}
3320 
3321 		case AS_GET_PIXEL_CLOCK_LIMITS:
3322 		{
3323 			STRACE(("ServerApp %s: get pixel clock limits\n", Signature()));
3324 			// We aren't using the screen_id for now...
3325 			int32 id;
3326 			link.Read<int32>(&id);
3327 			display_mode mode;
3328 			link.Read<display_mode>(&mode);
3329 
3330 			uint32 low, high;
3331 			status_t status = fDesktop->HWInterface()->GetPixelClockLimits(&mode,
3332 				&low, &high);
3333 			if (status == B_OK) {
3334 				fLink.StartMessage(B_OK);
3335 				fLink.Attach<uint32>(low);
3336 				fLink.Attach<uint32>(high);
3337 			} else
3338 				fLink.StartMessage(status);
3339 
3340 			fLink.Flush();
3341 			break;
3342 		}
3343 
3344 		case AS_SET_DPMS:
3345 		{
3346 			STRACE(("ServerApp %s: AS_SET_DPMS\n", Signature()));
3347 			int32 id;
3348 			link.Read<int32>(&id);
3349 
3350 			uint32 mode;
3351 			link.Read<uint32>(&mode);
3352 
3353 			status_t status = fDesktop->HWInterface()->SetDPMSMode(mode);
3354 			fLink.StartMessage(status);
3355 
3356 			fLink.Flush();
3357 			break;
3358 		}
3359 
3360 		case AS_GET_DPMS_STATE:
3361 		{
3362 			STRACE(("ServerApp %s: AS_GET_DPMS_STATE\n", Signature()));
3363 
3364 			int32 id;
3365 			link.Read<int32>(&id);
3366 
3367 			uint32 state = fDesktop->HWInterface()->DPMSMode();
3368 			fLink.StartMessage(B_OK);
3369 			fLink.Attach<uint32>(state);
3370 			fLink.Flush();
3371 			break;
3372 		}
3373 
3374 		case AS_GET_DPMS_CAPABILITIES:
3375 		{
3376 			STRACE(("ServerApp %s: AS_GET_DPMS_CAPABILITIES\n", Signature()));
3377 			int32 id;
3378 			link.Read<int32>(&id);
3379 
3380 			uint32 capabilities = fDesktop->HWInterface()->DPMSCapabilities();
3381 			fLink.StartMessage(B_OK);
3382 			fLink.Attach<uint32>(capabilities);
3383 			fLink.Flush();
3384 			break;
3385 		}
3386 
3387 		case AS_SCREEN_SET_BRIGHTNESS:
3388 		{
3389 			STRACE(("ServerApp %s: AS_SCREEN_SET_BRIGHTNESS\n", Signature()));
3390 			int32 id;
3391 			link.Read<int32>(&id);
3392 
3393 			float brightness;
3394 			link.Read<float>(&brightness);
3395 
3396 			status_t status = fDesktop->SetBrightness(id, brightness);
3397 			fLink.StartMessage(status);
3398 
3399 			fLink.Flush();
3400 			break;
3401 		}
3402 
3403 		case AS_SCREEN_GET_BRIGHTNESS:
3404 		{
3405 			STRACE(("ServerApp %s: AS_SCREEN_GET_BRIGHTNESS\n", Signature()));
3406 			int32 id;
3407 			link.Read<int32>(&id);
3408 
3409 			float brightness;
3410 			status_t result = fDesktop->HWInterface()->GetBrightness(&brightness);
3411 			fLink.StartMessage(result);
3412 			if (result == B_OK)
3413 				fLink.Attach<float>(brightness);
3414 			fLink.Flush();
3415 			break;
3416 		}
3417 
3418 		case AS_READ_BITMAP:
3419 		{
3420 			STRACE(("ServerApp %s: AS_READ_BITMAP\n", Signature()));
3421 			int32 token;
3422 			link.Read<int32>(&token);
3423 
3424 			bool drawCursor = true;
3425 			link.Read<bool>(&drawCursor);
3426 
3427 			BRect bounds;
3428 			link.Read<BRect>(&bounds);
3429 
3430 			bool success = false;
3431 
3432 			BReference<ServerBitmap> bitmap(GetBitmap(token), true);
3433 			if (bitmap != NULL) {
3434 				if (fDesktop->GetDrawingEngine()->LockExclusiveAccess()) {
3435 					success = fDesktop->GetDrawingEngine()->ReadBitmap(bitmap,
3436 						drawCursor, bounds) == B_OK;
3437 					fDesktop->GetDrawingEngine()->UnlockExclusiveAccess();
3438 				}
3439 			}
3440 
3441 			if (success)
3442 				fLink.StartMessage(B_OK);
3443 			else
3444 				fLink.StartMessage(B_BAD_VALUE);
3445 
3446 			fLink.Flush();
3447 			break;
3448 		}
3449 
3450 		case AS_GET_ACCELERANT_PATH:
3451 		{
3452 			int32 id;
3453 			fLink.Read<int32>(&id);
3454 
3455 			BString path;
3456 			status_t status = fDesktop->HWInterface()->GetAccelerantPath(path);
3457 			fLink.StartMessage(status);
3458 			if (status == B_OK)
3459 				fLink.AttachString(path.String());
3460 
3461 			fLink.Flush();
3462 			break;
3463 		}
3464 
3465 		case AS_GET_DRIVER_PATH:
3466 		{
3467 			int32 id;
3468 			fLink.Read<int32>(&id);
3469 
3470 			BString path;
3471 			status_t status = fDesktop->HWInterface()->GetDriverPath(path);
3472 			fLink.StartMessage(status);
3473 			if (status == B_OK)
3474 				fLink.AttachString(path.String());
3475 
3476 			fLink.Flush();
3477 			break;
3478 		}
3479 
3480 		// BWindowScreen communication
3481 
3482 		case AS_DIRECT_SCREEN_LOCK:
3483 		{
3484 			bool lock;
3485 			link.Read<bool>(&lock);
3486 
3487 			status_t status;
3488 			if (lock)
3489 				status = fDesktop->LockDirectScreen(ClientTeam());
3490 			else
3491 				status = fDesktop->UnlockDirectScreen(ClientTeam());
3492 
3493 			fLink.StartMessage(status);
3494 			fLink.Flush();
3495 			break;
3496 		}
3497 
3498 		// Hinting and aliasing
3499 
3500 		case AS_SET_SUBPIXEL_ANTIALIASING:
3501 		{
3502 			bool subpix;
3503 			if (link.Read<bool>(&subpix) == B_OK) {
3504 				LockedDesktopSettings settings(fDesktop);
3505 				settings.SetSubpixelAntialiasing(subpix);
3506 			}
3507 			fDesktop->Redraw();
3508 			break;
3509 		}
3510 
3511 		case AS_GET_SUBPIXEL_ANTIALIASING:
3512 		{
3513 			DesktopSettings settings(fDesktop);
3514 			fLink.StartMessage(B_OK);
3515 			fLink.Attach<bool>(settings.SubpixelAntialiasing());
3516 			fLink.Flush();
3517 			break;
3518 		}
3519 
3520 		case AS_SET_HINTING:
3521 		{
3522 			uint8 hinting;
3523 			if (link.Read<uint8>(&hinting) == B_OK && hinting < 3) {
3524 				LockedDesktopSettings settings(fDesktop);
3525 				if (hinting != settings.Hinting()) {
3526 					settings.SetHinting(hinting);
3527 					fDesktop->Redraw();
3528 				}
3529 			}
3530 			break;
3531 		}
3532 
3533 		case AS_GET_HINTING:
3534 		{
3535 			DesktopSettings settings(fDesktop);
3536 			fLink.StartMessage(B_OK);
3537 			fLink.Attach<uint8>(settings.Hinting());
3538 			fLink.Flush();
3539 			break;
3540 		}
3541 
3542 		case AS_SET_SUBPIXEL_AVERAGE_WEIGHT:
3543 		{
3544 			uint8 averageWeight;
3545 			if (link.Read<uint8>(&averageWeight) == B_OK) {
3546 				LockedDesktopSettings settings(fDesktop);
3547 				settings.SetSubpixelAverageWeight(averageWeight);
3548 			}
3549 			fDesktop->Redraw();
3550 			break;
3551 		}
3552 
3553 		case AS_GET_SUBPIXEL_AVERAGE_WEIGHT:
3554 		{
3555 			DesktopSettings settings(fDesktop);
3556 			fLink.StartMessage(B_OK);
3557 			fLink.Attach<uint8>(settings.SubpixelAverageWeight());
3558 			fLink.Flush();
3559 			break;
3560 		}
3561 
3562 		case AS_SET_SUBPIXEL_ORDERING:
3563 		{
3564 			bool subpixelOrdering;
3565 			if (link.Read<bool>(&subpixelOrdering) == B_OK) {
3566 				LockedDesktopSettings settings(fDesktop);
3567 				settings.SetSubpixelOrderingRegular(subpixelOrdering);
3568 			}
3569 			fDesktop->Redraw();
3570 			break;
3571 		}
3572 
3573 		case AS_GET_SUBPIXEL_ORDERING:
3574 		{
3575 			DesktopSettings settings(fDesktop);
3576 			fLink.StartMessage(B_OK);
3577 			fLink.Attach<bool>(settings.IsSubpixelOrderingRegular());
3578 			fLink.Flush();
3579 			break;
3580 		}
3581 
3582 		default:
3583 			printf("ServerApp %s received unhandled message code %" B_PRId32
3584 				"\n", Signature(), code);
3585 
3586 			if (link.NeedsReply()) {
3587 				// the client is now blocking and waiting for a reply!
3588 				fLink.StartMessage(B_ERROR);
3589 				fLink.Flush();
3590 			} else
3591 				puts("message doesn't need a reply!");
3592 			break;
3593 	}
3594 }
3595 
3596 
3597 /*!	\brief The thread function ServerApps use to monitor messages
3598 */
3599 void
3600 ServerApp::_MessageLooper()
3601 {
3602 	// Message-dispatching loop for the ServerApp
3603 
3604 	// get our own team ID
3605 	thread_info threadInfo;
3606 	get_thread_info(fThread, &threadInfo);
3607 
3608 	// First let's tell the client how to talk with us.
3609 	fLink.StartMessage(B_OK);
3610 	fLink.Attach<port_id>(fMessagePort);
3611 	fLink.Attach<area_id>(fDesktop->SharedReadOnlyArea());
3612 	fLink.Attach<team_id>(threadInfo.team);
3613 	fLink.Flush();
3614 
3615 	BPrivate::LinkReceiver &receiver = fLink.Receiver();
3616 
3617 	int32 code;
3618 	status_t err = B_OK;
3619 
3620 	while (!fQuitting) {
3621 		STRACE(("info: ServerApp::_MessageLooper() listening on port %" B_PRId32
3622 			".\n", fMessagePort));
3623 
3624 		err = receiver.GetNextMessage(code);
3625 		if (err != B_OK || code == B_QUIT_REQUESTED) {
3626 			STRACE(("ServerApp: application seems to be gone...\n"));
3627 
3628 			// Tell desktop to quit us
3629 			BPrivate::LinkSender link(fDesktop->MessagePort());
3630 			link.StartMessage(AS_DELETE_APP);
3631 			link.Attach<thread_id>(Thread());
3632 			link.Flush();
3633 			break;
3634 		}
3635 
3636 		switch (code) {
3637 			case kMsgAppQuit:
3638 				// we receive this from our destructor on quit
3639 				fQuitting = true;
3640 				break;
3641 
3642 			case AS_QUIT_APP:
3643 			{
3644 				// This message is received only when the app_server is asked
3645 				// to shut down in test/debug mode. Of course, if we are testing
3646 				// while using AccelerantDriver, we do NOT want to shut down
3647 				// client applications. The server can be quit in this fashion
3648 				// through the driver's interface, such as closing the
3649 				// ViewDriver's window.
3650 
3651 				STRACE(("ServerApp %s:Server shutdown notification received\n",
3652 					Signature()));
3653 
3654 				// If we are using the real, accelerated version of the
3655 				// DrawingEngine, we do NOT want the user to be able shut down
3656 				// the server. The results would NOT be pretty
3657 #if TEST_MODE
3658 				BMessage pleaseQuit(B_QUIT_REQUESTED);
3659 				SendMessageToClient(&pleaseQuit);
3660 #endif
3661 				break;
3662 			}
3663 
3664 			default:
3665 				STRACE(("ServerApp %s: Got a Message to dispatch\n",
3666 					Signature()));
3667 				_DispatchMessage(code, receiver);
3668 				break;
3669 		}
3670 	}
3671 
3672 	// Quit() will send us a message; we're handling the exiting procedure
3673 	thread_id sender;
3674 	sem_id shutdownSemaphore;
3675 	receive_data(&sender, &shutdownSemaphore, sizeof(sem_id));
3676 
3677 	delete this;
3678 
3679 	if (shutdownSemaphore >= B_OK)
3680 		release_sem(shutdownSemaphore);
3681 }
3682 
3683 
3684 status_t
3685 ServerApp::_CreateWindow(int32 code, BPrivate::LinkReceiver& link,
3686 	port_id& clientReplyPort)
3687 {
3688 	// Attached data:
3689 	// 1) int32 bitmap token (only for AS_CREATE_OFFSCREEN_WINDOW)
3690 	// 2) BRect window frame
3691 	// 3) uint32 window look
3692 	// 4) uint32 window feel
3693 	// 5) uint32 window flags
3694 	// 6) uint32 workspace index
3695 	// 7) int32 BHandler token of the window
3696 	// 8) port_id window's reply port
3697 	// 9) port_id window's looper port
3698 	// 10) const char * title
3699 
3700 	BRect frame;
3701 	int32 bitmapToken;
3702 	uint32 look;
3703 	uint32 feel;
3704 	uint32 flags;
3705 	uint32 workspaces;
3706 	int32 token;
3707 	port_id looperPort;
3708 	char* title;
3709 
3710 	if (code == AS_CREATE_OFFSCREEN_WINDOW)
3711 		link.Read<int32>(&bitmapToken);
3712 
3713 	link.Read<BRect>(&frame);
3714 	link.Read<uint32>(&look);
3715 	link.Read<uint32>(&feel);
3716 	link.Read<uint32>(&flags);
3717 	link.Read<uint32>(&workspaces);
3718 	link.Read<int32>(&token);
3719 	link.Read<port_id>(&clientReplyPort);
3720 	link.Read<port_id>(&looperPort);
3721 	if (link.ReadString(&title) != B_OK)
3722 		return B_ERROR;
3723 
3724 	if (!frame.IsValid()) {
3725 		// make sure we pass a valid rectangle to ServerWindow
3726 		frame.right = frame.left + 1;
3727 		frame.bottom = frame.top + 1;
3728 	}
3729 
3730 	status_t status = B_NO_MEMORY;
3731 	ServerWindow *window = NULL;
3732 
3733 	if (code == AS_CREATE_OFFSCREEN_WINDOW) {
3734 		ServerBitmap* bitmap = GetBitmap(bitmapToken);
3735 
3736 		if (bitmap != NULL) {
3737 			window = new (nothrow) OffscreenServerWindow(title, this,
3738 				clientReplyPort, looperPort, token, bitmap);
3739 		} else
3740 			status = B_ERROR;
3741 	} else {
3742 		window = new (nothrow) ServerWindow(title, this, clientReplyPort,
3743 			looperPort, token);
3744 		STRACE(("\nServerApp %s: New Window %s (%g:%g, %g:%g)\n",
3745 			Signature(), title, frame.left, frame.top,
3746 			frame.right, frame.bottom));
3747 	}
3748 
3749 	free(title);
3750 
3751 	// NOTE: the reply to the client is handled in ServerWindow::Run()
3752 	if (window != NULL) {
3753 		status = window->Init(frame, (window_look)look, (window_feel)feel,
3754 			flags, workspaces);
3755 		if (status == B_OK) {
3756 			status = window->Run();
3757 			if (status != B_OK) {
3758 				syslog(LOG_ERR, "ServerApp::_CreateWindow() - failed to run "
3759 					"the window thread\n");
3760 			}
3761 		}
3762 
3763 		if (status != B_OK)
3764 			delete window;
3765 	}
3766 
3767 	return status;
3768 }
3769 
3770 
3771 bool
3772 ServerApp::_HasWindowUnderMouse()
3773 {
3774 	BAutolock locker(fWindowListLock);
3775 
3776 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
3777 		ServerWindow* serverWindow = fWindowList.ItemAt(i);
3778 
3779 		if (fDesktop->ViewUnderMouse(serverWindow->Window()) != B_NULL_TOKEN)
3780 			return true;
3781 	}
3782 
3783 	return false;
3784 }
3785 
3786 
3787 bool
3788 ServerApp::_AddBitmap(ServerBitmap* bitmap)
3789 {
3790 	BAutolock _(fMapLocker);
3791 
3792 	try {
3793 		fBitmapMap.insert(std::make_pair(bitmap->Token(), BReference<ServerBitmap>(bitmap, false)));
3794 	} catch (std::bad_alloc& exception) {
3795 		return false;
3796 	}
3797 
3798 	bitmap->SetOwner(this);
3799 	return true;
3800 }
3801 
3802 
3803 void
3804 ServerApp::_DeleteBitmap(ServerBitmap* bitmap)
3805 {
3806 	ASSERT(fMapLocker.IsLocked());
3807 
3808 	gBitmapManager->BitmapRemoved(bitmap);
3809 	fBitmapMap.erase(bitmap->Token());
3810 }
3811 
3812 
3813 ServerBitmap*
3814 ServerApp::_FindBitmap(int32 token) const
3815 {
3816 	ASSERT(fMapLocker.IsLocked());
3817 
3818 	BitmapMap::const_iterator iterator = fBitmapMap.find(token);
3819 	if (iterator == fBitmapMap.end())
3820 		return NULL;
3821 
3822 	return iterator->second;
3823 }
3824 
3825 
3826 ServerPicture*
3827 ServerApp::_FindPicture(int32 token) const
3828 {
3829 	ASSERT(fMapLocker.IsLocked());
3830 
3831 	PictureMap::const_iterator iterator = fPictureMap.find(token);
3832 	if (iterator == fPictureMap.end())
3833 		return NULL;
3834 
3835 	return iterator->second;
3836 }
3837