xref: /haiku/src/servers/app/ServerApp.cpp (revision 56030d2d7ba63bd78b1198b5197a1f10ba314770)
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 
1642 			// Returns:
1643 			// 1) uint16 - family ID of added font
1644 			// 2) uint16 - style ID of added font
1645 			// 3) uint16 - face of added font
1646 
1647 			AutoLocker< ::FontManager> fontLock(fAppFontManager);
1648 
1649 			if (fAppFontManager->CountFamilies() > MAX_USER_FONTS) {
1650 				fLink.StartMessage(B_NOT_ALLOWED);
1651 				fLink.Flush();
1652 				break;
1653 			}
1654 
1655 			area_id fontAreaID, fontAreaCloneID;
1656 			area_info fontAreaInfo;
1657 			char* area_addr;
1658 			size_t size, offset;
1659 			uint16 index;
1660 
1661 			link.Read<int32>(&fontAreaID);
1662 			link.Read<size_t>(&size);
1663 			link.Read<size_t>(&offset);
1664 			link.Read<uint16>(&index);
1665 			fontAreaCloneID = clone_area("user font",
1666 				(void **)&area_addr,
1667 				B_ANY_ADDRESS,
1668 				B_READ_AREA,
1669 				fontAreaID);
1670 
1671 			if (fontAreaCloneID < B_OK) {
1672 				fLink.StartMessage(fontAreaCloneID);
1673 				fLink.Flush();
1674 				break;
1675 			}
1676 
1677 			status_t status = get_area_info(fontAreaCloneID, &fontAreaInfo);
1678 			if (status != B_OK) {
1679 				fLink.StartMessage(status);
1680 				fLink.Flush();
1681 				delete_area(fontAreaCloneID);
1682 				break;
1683 			}
1684 
1685 			size_t fontMemorySize = fontAreaInfo.size - offset;
1686 
1687 			if (size == 0)
1688 				size = fontMemorySize;
1689 
1690 			// Check size of font area and reject if it's too large
1691 			if (size > MAX_FONT_DATA_SIZE_BYTES
1692 				|| size > fontMemorySize) {
1693 				fLink.StartMessage(B_BAD_DATA);
1694 				fLink.Flush();
1695 				delete_area(fontAreaCloneID);
1696 				break;
1697 			}
1698 
1699 			FT_Byte* fontData = (FT_Byte*)(malloc (sizeof(FT_Byte) * size));
1700 			if (fontData == NULL) {
1701 				delete_area(fontAreaCloneID);
1702 				fLink.StartMessage(B_BAD_DATA);
1703 				fLink.Flush();
1704 				break;
1705 			}
1706 
1707 			memcpy(fontData, (FT_Byte*)fontAreaInfo.address + offset, size);
1708 
1709 			delete_area(fontAreaCloneID);
1710 
1711 			uint16 familyID, styleID;
1712 
1713 			status = fAppFontManager->AddUserFontFromMemory(fontData, size, index,
1714 				familyID, styleID);
1715 
1716 			if (status != B_OK) {
1717 				fLink.StartMessage(status);
1718 				free(fontData);
1719 			} else {
1720 				ServerFont font;
1721 				status = font.SetFamilyAndStyle(familyID, styleID,
1722 					fAppFontManager);
1723 
1724 				if (status == B_OK) {
1725 					font.SetFontData(fontData, size);
1726 					fLink.StartMessage(B_OK);
1727 					fLink.Attach<uint16>(font.FamilyID());
1728 					fLink.Attach<uint16>(font.StyleID());
1729 					fLink.Attach<uint16>(font.Face());
1730 				} else {
1731 					fLink.StartMessage(status);
1732 					free(fontData);
1733 				}
1734 			}
1735 
1736 			fLink.Flush();
1737 			break;
1738 		}
1739 
1740 		case AS_REMOVE_FONT:
1741 		{
1742 			STRACE(("ServerApp %s: Received BFont removal request\n",
1743 				Signature()));
1744 
1745 			// Remove an application-added font
1746 
1747 			// Attached Data:
1748 			// 1) uint16 - familyID of font to remove
1749 			// 2) uint16 - styleID of font to remove
1750 
1751 			uint16 familyID, styleID;
1752 			link.Read<uint16>(&familyID);
1753 			link.Read<uint16>(&styleID);
1754 
1755 			status_t status = B_OK;
1756 
1757 			AutoLocker< ::FontManager> fontLock(fAppFontManager);
1758 			status = fAppFontManager->RemoveUserFont(familyID, styleID);
1759 
1760 			fLink.StartMessage(status);
1761 			fLink.Flush();
1762 			break;
1763 		}
1764 
1765 		case AS_SET_SYSTEM_FONT:
1766 		{
1767 			FTRACE(("ServerApp %s: AS_SET_SYSTEM_FONT\n", Signature()));
1768 			// gets:
1769 			//	1) string - font type ("plain", ...)
1770 			//	2) string - family
1771 			//	3) string - style
1772 			//	4) float - size
1773 
1774 			char type[B_OS_NAME_LENGTH];
1775 			font_family familyName;
1776 			font_style styleName;
1777 			float size;
1778 
1779 			if (link.ReadString(type, sizeof(type)) == B_OK
1780 				&& link.ReadString(familyName, sizeof(familyName)) == B_OK
1781 				&& link.ReadString(styleName, sizeof(styleName)) == B_OK
1782 				&& link.Read<float>(&size) == B_OK) {
1783 				gFontManager->Lock();
1784 
1785 				FontStyle* style
1786 					= gFontManager->GetStyle(familyName, styleName);
1787 				if (style != NULL) {
1788 					ServerFont font(*style, size);
1789 					gFontManager->Unlock();
1790 						// We must not have locked the font manager when
1791 						// locking the desktop (through LockedDesktopSettings
1792 						// below)
1793 
1794 					LockedDesktopSettings settings(fDesktop);
1795 
1796 					// TODO: Should we also update our internal copies now?
1797 					if (strcmp(type, "plain") == 0)
1798 						settings.SetDefaultPlainFont(font);
1799 					else if (strcmp(type, "bold") == 0)
1800 						settings.SetDefaultBoldFont(font);
1801 					else if (strcmp(type, "fixed") == 0)
1802 						settings.SetDefaultFixedFont(font);
1803 				} else
1804 					gFontManager->Unlock();
1805 			}
1806 			break;
1807 		}
1808 
1809 		case AS_GET_SYSTEM_DEFAULT_FONT:
1810 		{
1811 			// input:
1812 			//	1) string - font type ("plain", ...)
1813 
1814 			ServerFont font;
1815 
1816 			char type[B_OS_NAME_LENGTH];
1817 			status_t status = link.ReadString(type, sizeof(type));
1818 			if (status == B_OK) {
1819 				if (strcmp(type, "plain") == 0)
1820 					font = *gFontManager->DefaultPlainFont();
1821 				else if (strcmp(type, "bold") == 0)
1822 					font = *gFontManager->DefaultBoldFont();
1823 				else if (strcmp(type, "fixed") == 0)
1824 					font = *gFontManager->DefaultFixedFont();
1825 				else
1826 					status = B_BAD_VALUE;
1827 			}
1828 
1829 			if (status == B_OK) {
1830 				// returns:
1831 				//	1) string - family
1832 				//	2) string - style
1833 				//	3) float - size
1834 
1835 				fLink.StartMessage(B_OK);
1836 				fLink.AttachString(font.Family());
1837 				fLink.AttachString(font.Style());
1838 				fLink.Attach<float>(font.Size());
1839 			} else
1840 				fLink.StartMessage(status);
1841 
1842 			fLink.Flush();
1843 			break;
1844 		}
1845 
1846 		case AS_GET_SYSTEM_FONTS:
1847 		{
1848 			FTRACE(("ServerApp %s: AS_GET_SYSTEM_FONTS\n", Signature()));
1849 			// Returns:
1850 			// 1) uint16 - family ID
1851 			// 2) uint16 - style ID
1852 			// 3) float - size in points
1853 			// 4) uint16 - face flags
1854 			// 5) uint32 - font flags
1855 
1856 			if (!fDesktop->LockSingleWindow()) {
1857 				fLink.StartMessage(B_OK);
1858 				fLink.Flush();
1859 				break;
1860 			}
1861 
1862 			// The client is requesting the system fonts, this
1863 			// could have happened either at application start up,
1864 			// or because the client is resyncing with the global
1865 			// fonts. So we record the current system wide fonts
1866 			// into our own copies at this point.
1867 			DesktopSettings settings(fDesktop);
1868 
1869 			settings.GetDefaultPlainFont(fPlainFont);
1870 			settings.GetDefaultBoldFont(fBoldFont);
1871 			settings.GetDefaultFixedFont(fFixedFont);
1872 
1873 			fLink.StartMessage(B_OK);
1874 
1875 			for (int32 i = 0; i < 3; i++) {
1876 				ServerFont* font = NULL;
1877 				switch (i) {
1878 					case 0:
1879 						font = &fPlainFont;
1880 						fLink.AttachString("plain");
1881 						break;
1882 
1883 					case 1:
1884 						font = &fBoldFont;
1885 						fLink.AttachString("bold");
1886 						break;
1887 
1888 					case 2:
1889 						font = &fFixedFont;
1890 						fLink.AttachString("fixed");
1891 						break;
1892 				}
1893 
1894 				fLink.Attach<uint16>(font->FamilyID());
1895 				fLink.Attach<uint16>(font->StyleID());
1896 				fLink.Attach<float>(font->Size());
1897 				fLink.Attach<uint16>(font->Face());
1898 				fLink.Attach<uint32>(font->Flags());
1899 			}
1900 
1901 			fDesktop->UnlockSingleWindow();
1902 			fLink.Flush();
1903 			break;
1904 		}
1905 
1906 		case AS_GET_FONT_LIST_REVISION:
1907 		{
1908 			FTRACE(("ServerApp %s: AS_GET_FONT_LIST_REVISION\n", Signature()));
1909 
1910 			fLink.StartMessage(B_OK);
1911 			fLink.Attach<int32>(
1912 				gFontManager->CheckRevision(fDesktop->UserID()));
1913 			fLink.Flush();
1914 			break;
1915 		}
1916 
1917 		case AS_GET_FAMILY_AND_STYLES:
1918 		{
1919 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLES\n", Signature()));
1920 
1921 			// Attached Data:
1922 			// 1) int32 the index of the font family to get
1923 
1924 			// Returns:
1925 			// 1) string - name of family
1926 			// 2) uint32 - flags of font family (B_IS_FIXED || B_HAS_TUNED_FONT)
1927 			// 3) count of styles in that family
1928 			// For each style:
1929 			//		1) string - name of style
1930 			//		2) uint16 - face of style
1931 			//		3) uint32 - flags of style
1932 
1933 			int32 index;
1934 			link.Read<int32>(&index);
1935 
1936 			AutoLocker< ::FontManager> fontLock(gFontManager);
1937 
1938 			FontFamily* family = gFontManager->FamilyAt(index);
1939 			if (family == NULL) {
1940 				fontLock.SetTo(fAppFontManager, false);
1941 
1942 				family = fAppFontManager->FamilyAt(index);
1943 			}
1944 
1945 			if (family) {
1946 				fLink.StartMessage(B_OK);
1947 				fLink.AttachString(family->Name());
1948 				fLink.Attach<uint32>(family->Flags());
1949 
1950 				int32 count = family->CountStyles();
1951 
1952 				fLink.Attach<int32>(count);
1953 
1954 				for (int32 i = 0; i < count; i++) {
1955 					FontStyle* style = family->StyleAt(i);
1956 
1957 					fLink.AttachString(style->Name());
1958 					fLink.Attach<uint16>(style->Face());
1959 					fLink.Attach<uint32>(style->Flags());
1960 				}
1961 			} else
1962 				fLink.StartMessage(B_BAD_VALUE);
1963 
1964 
1965 			fLink.Flush();
1966 			break;
1967 		}
1968 
1969 		case AS_GET_FAMILY_AND_STYLE:
1970 		{
1971 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE\n", Signature()));
1972 
1973 			// Attached Data:
1974 			// 1) uint16 - family ID
1975 			// 2) uint16 - style ID
1976 
1977 			// Returns:
1978 			// 1) font_family The name of the font family
1979 			// 2) font_style - name of the style
1980 
1981 			uint16 familyID, styleID;
1982 			link.Read<uint16>(&familyID);
1983 			link.Read<uint16>(&styleID);
1984 
1985 			AutoLocker< ::FontManager> fontLock(gFontManager);
1986 
1987 			FontStyle* fontStyle = gFontManager->GetStyle(familyID, styleID);
1988 			if (fontStyle == NULL) {
1989 				fontLock.SetTo(fAppFontManager, false);
1990 
1991 				fontStyle = fAppFontManager->GetStyle(familyID, styleID);
1992 			}
1993 
1994 			if (fontStyle != NULL) {
1995 				fLink.StartMessage(B_OK);
1996 				fLink.AttachString(fontStyle->Family()->Name());
1997 				fLink.AttachString(fontStyle->Name());
1998 			} else
1999 				fLink.StartMessage(B_BAD_VALUE);
2000 
2001 			fLink.Flush();
2002 
2003 			break;
2004 		}
2005 
2006 		case AS_GET_FAMILY_AND_STYLE_IDS:
2007 		{
2008 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE_IDS\n",
2009 				Signature()));
2010 
2011 			// Attached Data:
2012 			// 1) font_family - name of font family to use
2013 			// 2) font_style - name of style in family
2014 			// 3) family ID - only used if 1) is empty
2015 			// 4) style ID - only used if 2) is empty
2016 			// 5) face - the font's current face
2017 
2018 			// Returns:
2019 			// 1) uint16 - family ID
2020 			// 2) uint16 - style ID
2021 			// 3) uint16 - face
2022 
2023 			font_family family;
2024 			font_style style;
2025 			uint16 familyID, styleID;
2026 			uint16 face;
2027 			if (link.ReadString(family, sizeof(font_family)) == B_OK
2028 				&& link.ReadString(style, sizeof(font_style)) == B_OK
2029 				&& link.Read<uint16>(&familyID) == B_OK
2030 				&& link.Read<uint16>(&styleID) == B_OK
2031 				&& link.Read<uint16>(&face) == B_OK) {
2032 				// get the font and return IDs and face
2033 				AutoLocker< ::FontManager> fontLock(gFontManager);
2034 
2035 				FontStyle* fontStyle = gFontManager->GetStyle(family, style,
2036 					familyID, styleID, face);
2037 				if (fontStyle == NULL) {
2038 					fontLock.SetTo(fAppFontManager, false);
2039 
2040 					fontStyle = fAppFontManager->GetStyle(family, style,
2041 						familyID, styleID, face);
2042 				}
2043 
2044 				if (fontStyle != NULL) {
2045 					fLink.StartMessage(B_OK);
2046 					fLink.Attach<uint16>(fontStyle->Family()->ID());
2047 					fLink.Attach<uint16>(fontStyle->ID());
2048 
2049 					// we try to keep the font face close to what we got
2050 					face = fontStyle->PreservedFace(face);
2051 
2052 					fLink.Attach<uint16>(face);
2053 				} else
2054 					fLink.StartMessage(B_NAME_NOT_FOUND);
2055 			} else
2056 				fLink.StartMessage(B_BAD_VALUE);
2057 
2058 			fLink.Flush();
2059 			break;
2060 		}
2061 
2062 		case AS_GET_FONT_FILE_FORMAT:
2063 		{
2064 			FTRACE(("ServerApp %s: AS_GET_FONT_FILE_FORMAT\n", Signature()));
2065 
2066 			// Attached Data:
2067 			// 1) uint16 - family ID
2068 			// 2) uint16 - style ID
2069 
2070 			// Returns:
2071 			// 1) uint16 font_file_format of font
2072 
2073 			int32 familyID, styleID;
2074 			link.Read<int32>(&familyID);
2075 			link.Read<int32>(&styleID);
2076 
2077 			AutoLocker< ::FontManager> fontLock(gFontManager);
2078 
2079 			FontStyle* fontStyle = gFontManager->GetStyle(familyID, styleID);
2080 			if (fontStyle == NULL) {
2081 				fontLock.SetTo(fAppFontManager, false);
2082 
2083 				fontStyle = fAppFontManager->GetStyle(familyID, styleID);
2084 			}
2085 
2086 			if (fontStyle != NULL) {
2087 				fLink.StartMessage(B_OK);
2088 				fLink.Attach<uint16>((uint16)fontStyle->FileFormat());
2089 			} else
2090 				fLink.StartMessage(B_BAD_VALUE);
2091 
2092 			fLink.Flush();
2093 			break;
2094 		}
2095 
2096 		case AS_GET_STRING_WIDTHS:
2097 		{
2098 			FTRACE(("ServerApp %s: AS_GET_STRING_WIDTHS\n", Signature()));
2099 
2100 			// Attached Data:
2101 			// 1) uint16 ID of family
2102 			// 2) uint16 ID of style
2103 			// 3) float point size of font
2104 			// 4) uint8 spacing to use
2105 			// 5) int32 numStrings
2106 			// 6) int32 string length to measure (numStrings times)
2107 			// 7) string String to measure (numStrings times)
2108 
2109 			// Returns:
2110 			// 1) float - width of the string in pixels (numStrings times)
2111 
2112 			uint16 familyID, styleID;
2113 			float size;
2114 			uint8 spacing;
2115 
2116 			link.Read<uint16>(&familyID);
2117 			link.Read<uint16>(&styleID);
2118 			link.Read<float>(&size);
2119 			link.Read<uint8>(&spacing);
2120 			int32 numStrings;
2121 			if (link.Read<int32>(&numStrings) != B_OK) {
2122 				// this results in a B_BAD_VALUE return
2123 				numStrings = 0;
2124 				size = 0.0f;
2125 			}
2126 
2127 			BStackOrHeapArray<float, 64> widthArray(numStrings);
2128 			BStackOrHeapArray<int32, 64> lengthArray(numStrings);
2129 			BStackOrHeapArray<char*, 64> stringArray(numStrings);
2130 			if (!widthArray.IsValid() || !lengthArray.IsValid()
2131 				|| !stringArray.IsValid()) {
2132 				fLink.StartMessage(B_NO_MEMORY);
2133 				fLink.Flush();
2134 				break;
2135 			}
2136 
2137 			for (int32 i = 0; i < numStrings; i++) {
2138 				// This version of ReadString allocates the strings, we free
2139 				// them below
2140 				link.ReadString(&stringArray[i], (size_t *)&lengthArray[i]);
2141 			}
2142 
2143 			ServerFont font;
2144 
2145 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2146 				fAppFontManager);
2147 
2148 			if (status == B_OK && size > 0) {
2149 				font.SetSize(size);
2150 				font.SetSpacing(spacing);
2151 
2152 				for (int32 i = 0; i < numStrings; i++) {
2153 					if (!stringArray[i] || lengthArray[i] <= 0)
2154 						widthArray[i] = 0.0;
2155 					else {
2156 						widthArray[i] = font.StringWidth(stringArray[i],
2157 							lengthArray[i]);
2158 					}
2159 				}
2160 
2161 				fLink.StartMessage(B_OK);
2162 				fLink.Attach(widthArray, numStrings * sizeof(float));
2163 			} else
2164 				fLink.StartMessage(B_BAD_VALUE);
2165 
2166 			fLink.Flush();
2167 
2168 			for (int32 i = 0; i < numStrings; i++)
2169 				free(stringArray[i]);
2170 			break;
2171 		}
2172 
2173 		case AS_GET_FONT_BOUNDING_BOX:
2174 		{
2175 			FTRACE(("ServerApp %s: AS_GET_BOUNDING_BOX\n",
2176 				Signature()));
2177 
2178 			// Attached Data:
2179 			// 1) uint16 - family ID
2180 			// 2) uint16 - style ID
2181 			// 3) float - font size
2182 
2183 			// Returns:
2184 			// 1) BRect - box holding entire font
2185 
2186 			uint16 familyID, styleID;
2187 			float size;
2188 
2189 			link.Read<uint16>(&familyID);
2190 			link.Read<uint16>(&styleID);
2191 			link.Read<float>(&size);
2192 
2193 			ServerFont font;
2194 
2195 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2196 				fAppFontManager);
2197 
2198 			if (status == B_OK && size > 0) {
2199 				font.SetSize(size);
2200 
2201 				fLink.StartMessage(B_OK);
2202 				fLink.Attach<BRect>(font.BoundingBox());
2203 			} else
2204 				fLink.StartMessage(B_BAD_VALUE);
2205 
2206 			fLink.Flush();
2207 			break;
2208 		}
2209 
2210 		case AS_GET_TUNED_COUNT:
2211 		{
2212 			FTRACE(("ServerApp %s: AS_GET_TUNED_COUNT\n", Signature()));
2213 
2214 			// Attached Data:
2215 			// 1) uint16 - family ID
2216 			// 2) uint16 - style ID
2217 
2218 			// Returns:
2219 			// 1) int32 - number of font strikes available
2220 
2221 			uint16 familyID, styleID;
2222 			link.Read<uint16>(&familyID);
2223 			link.Read<uint16>(&styleID);
2224 
2225 			AutoLocker< ::FontManager> fontLock(gFontManager);
2226 
2227 			FontStyle* fontStyle = gFontManager->GetStyle(familyID, styleID);
2228 			if (fontStyle == NULL) {
2229 				fontLock.SetTo(fAppFontManager, false);
2230 
2231 				fontStyle = fAppFontManager->GetStyle(familyID, styleID);
2232 			}
2233 
2234 			if (fontStyle != NULL) {
2235 				fLink.StartMessage(B_OK);
2236 				fLink.Attach<int32>(fontStyle->TunedCount());
2237 			} else
2238 				fLink.StartMessage(B_BAD_VALUE);
2239 
2240 			fLink.Flush();
2241 			break;
2242 		}
2243 
2244 		case AS_GET_TUNED_INFO:
2245 		{
2246 			FTRACE(("ServerApp %s: AS_GET_TUNED_INFO unimplmemented\n",
2247 				Signature()));
2248 
2249 			// Attached Data:
2250 			// 1) uint16 - family ID
2251 			// 2) uint16 - style ID
2252 			// 3) uint32 - index of the particular font strike
2253 
2254 			// Returns:
2255 			// 1) tuned_font_info - info on the strike specified
2256 			// ToDo: implement me!
2257 
2258 			fLink.StartMessage(B_ERROR);
2259 			fLink.Flush();
2260 			break;
2261 		}
2262 
2263 		case AS_GET_EXTRA_FONT_FLAGS:
2264 		{
2265 			FTRACE(("ServerApp %s: AS_GET_EXTRA_FONT_FLAGS\n",
2266 				Signature()));
2267 
2268 			// Attached Data:
2269 			// 1) uint16 - family ID
2270 			// 2) uint16 - style ID
2271 
2272 			// Returns:
2273 			// 1) uint32 - extra font flags
2274 
2275 			uint16 familyID, styleID;
2276 			link.Read<uint16>(&familyID);
2277 			link.Read<uint16>(&styleID);
2278 
2279 			AutoLocker< ::FontManager> fontLock(gFontManager);
2280 
2281 			FontStyle* fontStyle = gFontManager->GetStyle(familyID, styleID);
2282 			if (fontStyle == NULL) {
2283 				fontLock.SetTo(fAppFontManager, false);
2284 
2285 				fontStyle = fAppFontManager->GetStyle(familyID, styleID);
2286 			}
2287 
2288 			if (fontStyle != NULL) {
2289 				fLink.StartMessage(B_OK);
2290 				fLink.Attach<uint32>(fontStyle->Flags());
2291 			} else
2292 				fLink.StartMessage(B_BAD_VALUE);
2293 
2294 			fLink.Flush();
2295 			break;
2296 		}
2297 
2298 		case AS_GET_FONT_HEIGHT:
2299 		{
2300 			FTRACE(("ServerApp %s: AS_GET_FONT_HEIGHT\n", Signature()));
2301 
2302 			// Attached Data:
2303 			// 1) uint16 family ID
2304 			// 2) uint16 style ID
2305 			// 3) float size
2306 
2307 			uint16 familyID, styleID;
2308 			float size;
2309 			link.Read<uint16>(&familyID);
2310 			link.Read<uint16>(&styleID);
2311 			link.Read<float>(&size);
2312 
2313 			AutoLocker< ::FontManager> fontLock(gFontManager);
2314 
2315 			FontStyle* fontStyle = gFontManager->GetStyle(familyID, styleID);
2316 			if (fontStyle == NULL) {
2317 				fontLock.SetTo(fAppFontManager, false);
2318 
2319 				fontStyle = fAppFontManager->GetStyle(familyID, styleID);
2320 			}
2321 
2322 			if (fontStyle != NULL) {
2323 				font_height height;
2324 				fontStyle->GetHeight(size, height);
2325 
2326 				fLink.StartMessage(B_OK);
2327 				fLink.Attach<font_height>(height);
2328 			} else
2329 				fLink.StartMessage(B_BAD_VALUE);
2330 
2331 			fLink.Flush();
2332 			break;
2333 		}
2334 
2335 		case AS_GET_UNICODE_BLOCKS:
2336 		{
2337 			FTRACE(("ServerApp %s: AS_GET_UNICODE_BLOCKS\n", Signature()));
2338 
2339 			// Attached Data:
2340 			// 1) uint16 family ID
2341 			// 2) uint16 style ID
2342 
2343 			// Returns:
2344 			// 1) unicode_block - bitfield of Unicode blocks in font
2345 
2346 			uint16 familyID, styleID;
2347 			link.Read<uint16>(&familyID);
2348 			link.Read<uint16>(&styleID);
2349 
2350 			ServerFont font;
2351 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2352 				fAppFontManager);
2353 
2354 			if (status == B_OK) {
2355 				unicode_block blocksForFont;
2356 				font.GetUnicodeBlocks(blocksForFont);
2357 
2358 				fLink.StartMessage(B_OK);
2359 				fLink.Attach<unicode_block>(blocksForFont);
2360 			} else
2361 				fLink.StartMessage(status);
2362 
2363 			fLink.Flush();
2364 			break;
2365 		}
2366 
2367 		case AS_GET_HAS_UNICODE_BLOCK:
2368 		{
2369 			FTRACE(("ServerApp %s: AS_INCLUDES_UNICODE_BLOCK\n", Signature()));
2370 
2371 			// Attached Data:
2372 			// 1) uint16 family ID
2373 			// 2) uint16 style ID
2374 			// 3) uint32 start of unicode block
2375 			// 4) uint32 end of unicode block
2376 
2377 			// Returns:
2378 			// 1) bool - whether or not font includes specified block range
2379 
2380 			uint16 familyID, styleID;
2381 			uint32 start, end;
2382 			link.Read<uint16>(&familyID);
2383 			link.Read<uint16>(&styleID);
2384 			link.Read<uint32>(&start);
2385 			link.Read<uint32>(&end);
2386 
2387 			ServerFont font;
2388 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2389 				fAppFontManager);
2390 
2391 			if (status == B_OK) {
2392 				bool hasBlock;
2393 
2394 				status = font.IncludesUnicodeBlock(start, end, hasBlock);
2395 				fLink.StartMessage(status);
2396 				fLink.Attach<bool>(hasBlock);
2397 			} else
2398 				fLink.StartMessage(status);
2399 
2400 			fLink.Flush();
2401 			break;
2402 		}
2403 
2404 		case AS_GET_GLYPH_SHAPES:
2405 		{
2406 			FTRACE(("ServerApp %s: AS_GET_GLYPH_SHAPES\n", Signature()));
2407 
2408 			// Attached Data:
2409 			// 1) uint16 - family ID
2410 			// 2) uint16 - style ID
2411 			// 3) float - point size
2412 			// 4) float - shear
2413 			// 5) float - rotation
2414 			// 6) float - false bold width
2415 			// 6) uint32 - flags
2416 			// 7) int32 - numChars
2417 			// 8) int32 - numBytes
2418 			// 8) char - chars (numBytes times)
2419 
2420 			// Returns:
2421 			// 1) BShape - glyph shape
2422 			// numChars times
2423 
2424 			uint16 familyID, styleID;
2425 			uint32 flags;
2426 			float size, shear, rotation, falseBoldWidth;
2427 
2428 			link.Read<uint16>(&familyID);
2429 			link.Read<uint16>(&styleID);
2430 			link.Read<float>(&size);
2431 			link.Read<float>(&shear);
2432 			link.Read<float>(&rotation);
2433 			link.Read<float>(&falseBoldWidth);
2434 			link.Read<uint32>(&flags);
2435 
2436 			int32 numChars, numBytes;
2437 			link.Read<int32>(&numChars);
2438 			link.Read<int32>(&numBytes);
2439 
2440 			BStackOrHeapArray<char, 256> charArray(numBytes);
2441 			BStackOrHeapArray<BShape*, 64> shapes(numChars);
2442 			if (!charArray.IsValid() || !shapes.IsValid()) {
2443 				fLink.StartMessage(B_NO_MEMORY);
2444 				fLink.Flush();
2445 				break;
2446 			}
2447 
2448 			link.Read(charArray, numBytes);
2449 
2450 			ServerFont font;
2451 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2452 				fAppFontManager);
2453 
2454 			if (status == B_OK) {
2455 				font.SetSize(size);
2456 				font.SetShear(shear);
2457 				font.SetRotation(rotation);
2458 				font.SetFalseBoldWidth(falseBoldWidth);
2459 				font.SetFlags(flags);
2460 
2461 				status = font.GetGlyphShapes(charArray, numChars, shapes);
2462 				if (status == B_OK) {
2463 					fLink.StartMessage(B_OK);
2464 					for (int32 i = 0; i < numChars; i++) {
2465 						fLink.AttachShape(*shapes[i]);
2466 						delete shapes[i];
2467 					}
2468 				}
2469 			}
2470 
2471 			if (status != B_OK)
2472 				fLink.StartMessage(status);
2473 
2474 			fLink.Flush();
2475 			break;
2476 		}
2477 
2478 		case AS_GET_HAS_GLYPHS:
2479 		{
2480 			FTRACE(("ServerApp %s: AS_GET_HAS_GLYPHS\n", Signature()));
2481 
2482 			// Attached Data:
2483 			// 1) uint16 - family ID
2484 			// 2) uint16 - style ID
2485 			// 3) int32 - numChars
2486 			// 4) int32 - numBytes
2487 			// 5) char - the char buffer with size numBytes
2488 
2489 			uint16 familyID, styleID;
2490 			link.Read<uint16>(&familyID);
2491 			link.Read<uint16>(&styleID);
2492 
2493 			int32 numChars, numBytes;
2494 			link.Read<int32>(&numChars);
2495 			link.Read<int32>(&numBytes);
2496 
2497 			BStackOrHeapArray<char, 256> charArray(numBytes);
2498 			BStackOrHeapArray<bool, 256> hasArray(numChars);
2499 			if (!charArray.IsValid() || !hasArray.IsValid()) {
2500 				fLink.StartMessage(B_NO_MEMORY);
2501 				fLink.Flush();
2502 				break;
2503 			}
2504 
2505 			link.Read(charArray, numBytes);
2506 
2507 			ServerFont font;
2508 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2509 				fAppFontManager);
2510 
2511 			if (status == B_OK) {
2512 				status = font.GetHasGlyphs(charArray, numBytes, numChars,
2513 					hasArray);
2514 				if (status == B_OK) {
2515 					fLink.StartMessage(B_OK);
2516 					fLink.Attach(hasArray, numChars * sizeof(bool));
2517 				}
2518 			}
2519 
2520 			if (status != B_OK)
2521 				fLink.StartMessage(status);
2522 
2523 			fLink.Flush();
2524 			break;
2525 		}
2526 
2527 		case AS_GET_EDGES:
2528 		{
2529 			FTRACE(("ServerApp %s: AS_GET_EDGES\n", Signature()));
2530 
2531 			// Attached Data:
2532 			// 1) uint16 - family ID
2533 			// 2) uint16 - style ID
2534 			// 3) int32 - numChars
2535 			// 4) int32 - numBytes
2536 			// 5) char - the char buffer with size numBytes
2537 
2538 			uint16 familyID, styleID;
2539 			link.Read<uint16>(&familyID);
2540 			link.Read<uint16>(&styleID);
2541 
2542 			int32 numChars;
2543 			link.Read<int32>(&numChars);
2544 
2545 			uint32 numBytes;
2546 			link.Read<uint32>(&numBytes);
2547 
2548 			BStackOrHeapArray<char, 256> charArray(numBytes);
2549 			BStackOrHeapArray<edge_info, 64> edgeArray(numChars);
2550 			if (!charArray.IsValid() || !edgeArray.IsValid()) {
2551 				fLink.StartMessage(B_NO_MEMORY);
2552 				fLink.Flush();
2553 				break;
2554 			}
2555 
2556 			link.Read(charArray, numBytes);
2557 
2558 			ServerFont font;
2559 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2560 				fAppFontManager);
2561 
2562 			if (status == B_OK) {
2563 				status = font.GetEdges(charArray, numBytes, numChars,
2564 					edgeArray);
2565 				if (status == B_OK) {
2566 					fLink.StartMessage(B_OK);
2567 					fLink.Attach(edgeArray, numChars * sizeof(edge_info));
2568 				}
2569 			}
2570 
2571 			if (status != B_OK)
2572 				fLink.StartMessage(status);
2573 
2574 			fLink.Flush();
2575 			break;
2576 		}
2577 
2578 		case AS_GET_ESCAPEMENTS:
2579 		{
2580 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS\n", Signature()));
2581 
2582 			// Attached Data:
2583 			// 1) uint16 - family ID
2584 			// 2) uint16 - style ID
2585 			// 3) float - point size
2586 			// 4) uint8 - spacing
2587 			// 5) float - rotation
2588 			// 6) uint32 - flags
2589 			// 7) int32 - numChars
2590 			// 8) char - char     -\       both
2591 			// 9) BPoint - offset -/ (numChars times)
2592 
2593 			// Returns:
2594 			// 1) BPoint - escapement
2595 			// numChars times
2596 
2597 			uint16 familyID, styleID;
2598 			uint32 flags;
2599 			float size, rotation;
2600 			uint8 spacing;
2601 
2602 			link.Read<uint16>(&familyID);
2603 			link.Read<uint16>(&styleID);
2604 			link.Read<float>(&size);
2605 			link.Read<uint8>(&spacing);
2606 			link.Read<float>(&rotation);
2607 			link.Read<uint32>(&flags);
2608 
2609 			escapement_delta delta;
2610 			link.Read<float>(&delta.nonspace);
2611 			link.Read<float>(&delta.space);
2612 
2613 			bool wantsOffsets;
2614 			link.Read<bool>(&wantsOffsets);
2615 
2616 			int32 numChars;
2617 			link.Read<int32>(&numChars);
2618 
2619 			uint32 numBytes;
2620 			link.Read<uint32>(&numBytes);
2621 
2622 			BStackOrHeapArray<char, 256> charArray(numBytes);
2623 			BStackOrHeapArray<BPoint, 64> escapements(numChars);
2624 			BPoint* offsets = NULL;
2625 			if (wantsOffsets)
2626 				offsets = new(std::nothrow) BPoint[numChars];
2627 
2628 			if (!charArray.IsValid() || !escapements.IsValid()
2629 				|| (offsets == NULL && wantsOffsets)) {
2630 				delete[] offsets;
2631 				fLink.StartMessage(B_NO_MEMORY);
2632 				fLink.Flush();
2633 				break;
2634 			}
2635 
2636 			link.Read(charArray, numBytes);
2637 
2638 			ServerFont font;
2639 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2640 				fAppFontManager);
2641 
2642 			if (status == B_OK) {
2643 				font.SetSize(size);
2644 				font.SetSpacing(spacing);
2645 				font.SetRotation(rotation);
2646 				font.SetFlags(flags);
2647 
2648 				status = font.GetEscapements(charArray, numBytes, numChars,
2649 					delta, escapements, offsets);
2650 
2651 				if (status == B_OK) {
2652 					fLink.StartMessage(B_OK);
2653 					for (int32 i = 0; i < numChars; i++)
2654 						fLink.Attach<BPoint>(escapements[i]);
2655 
2656 					if (wantsOffsets) {
2657 						for (int32 i = 0; i < numChars; i++)
2658 							fLink.Attach<BPoint>(offsets[i]);
2659 					}
2660 				}
2661 			}
2662 
2663 			if (status != B_OK)
2664 				fLink.StartMessage(status);
2665 
2666 			delete[] offsets;
2667 			fLink.Flush();
2668 			break;
2669 		}
2670 
2671 		case AS_GET_ESCAPEMENTS_AS_FLOATS:
2672 		{
2673 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS_AS_FLOATS\n", Signature()));
2674 
2675 			// Attached Data:
2676 			// 1) uint16 - family ID
2677 			// 2) uint16 - style ID
2678 			// 3) float - point size
2679 			// 4) uint8 - spacing
2680 			// 5) float - rotation
2681 			// 6) uint32 - flags
2682 			// 7) float - additional "nonspace" delta
2683 			// 8) float - additional "space" delta
2684 			// 9) int32 - numChars
2685 			// 10) int32 - numBytes
2686 			// 11) char - the char buffer with size numBytes
2687 
2688 			// Returns:
2689 			// 1) float - escapement buffer with numChar entries
2690 
2691 			uint16 familyID, styleID;
2692 			uint32 flags;
2693 			float size, rotation;
2694 			uint8 spacing;
2695 
2696 			link.Read<uint16>(&familyID);
2697 			link.Read<uint16>(&styleID);
2698 			link.Read<float>(&size);
2699 			link.Read<uint8>(&spacing);
2700 			link.Read<float>(&rotation);
2701 			link.Read<uint32>(&flags);
2702 
2703 			escapement_delta delta;
2704 			link.Read<float>(&delta.nonspace);
2705 			link.Read<float>(&delta.space);
2706 
2707 			int32 numChars;
2708 			link.Read<int32>(&numChars);
2709 
2710 			uint32 numBytes;
2711 			link.Read<uint32>(&numBytes);
2712 
2713 			BStackOrHeapArray<char, 256> charArray(numBytes);
2714 			BStackOrHeapArray<float, 64> escapements(numChars);
2715 			if (!charArray.IsValid() || !escapements.IsValid()) {
2716 				fLink.StartMessage(B_NO_MEMORY);
2717 				fLink.Flush();
2718 				break;
2719 			}
2720 
2721 			link.Read(charArray, numBytes);
2722 
2723 			// figure out escapements
2724 
2725 			ServerFont font;
2726 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2727 				fAppFontManager);
2728 
2729 			if (status == B_OK) {
2730 				font.SetSize(size);
2731 				font.SetSpacing(spacing);
2732 				font.SetRotation(rotation);
2733 				font.SetFlags(flags);
2734 
2735 				status = font.GetEscapements(charArray, numBytes, numChars,
2736 					delta, escapements);
2737 
2738 				if (status == B_OK) {
2739 					fLink.StartMessage(B_OK);
2740 					fLink.Attach(escapements, numChars * sizeof(float));
2741 				}
2742 			}
2743 
2744 			if (status != B_OK)
2745 				fLink.StartMessage(status);
2746 
2747 			fLink.Flush();
2748 			break;
2749 		}
2750 
2751 		case AS_GET_BOUNDINGBOXES_CHARS:
2752 		case AS_GET_BOUNDINGBOXES_STRING:
2753 		{
2754 			FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_CHARS\n", Signature()));
2755 
2756 			// Attached Data:
2757 			// 1) uint16 - family ID
2758 			// 2) uint16 - style ID
2759 			// 3) float - point size
2760 			// 4) float - rotation
2761 			// 5) float - shear
2762 			// 6) float - false bold width
2763 			// 7) uint8 - spacing
2764 			// 8) uint32 - flags
2765 			// 9) font_metric_mode - mode
2766 			// 10) bool - string escapement
2767 			// 11) escapement_delta - additional delta
2768 			// 12) int32 - numChars
2769 			// 13) int32 - numBytes
2770 			// 14) char - the char buffer with size numBytes
2771 
2772 			// Returns:
2773 			// 1) BRect - rects with numChar entries
2774 
2775 			uint16 familyID, styleID;
2776 			uint32 flags;
2777 			float size, rotation, shear, falseBoldWidth;
2778 			uint8 spacing;
2779 			font_metric_mode mode;
2780 			bool stringEscapement;
2781 
2782 			link.Read<uint16>(&familyID);
2783 			link.Read<uint16>(&styleID);
2784 			link.Read<float>(&size);
2785 			link.Read<float>(&rotation);
2786 			link.Read<float>(&shear);
2787 			link.Read<float>(&falseBoldWidth);
2788 			link.Read<uint8>(&spacing);
2789 			link.Read<uint32>(&flags);
2790 			link.Read<font_metric_mode>(&mode);
2791 			link.Read<bool>(&stringEscapement);
2792 
2793 			escapement_delta delta;
2794 			link.Read<escapement_delta>(&delta);
2795 
2796 			int32 numChars;
2797 			link.Read<int32>(&numChars);
2798 
2799 			uint32 numBytes;
2800 			link.Read<uint32>(&numBytes);
2801 
2802 			BStackOrHeapArray<char, 256> charArray(numBytes);
2803 			BStackOrHeapArray<BRect, 64> rectArray(numChars);
2804 			if (!charArray.IsValid() || !rectArray.IsValid()) {
2805 				fLink.StartMessage(B_NO_MEMORY);
2806 				fLink.Flush();
2807 				break;
2808 			}
2809 
2810 			link.Read(charArray, numBytes);
2811 
2812 			// figure out escapements
2813 
2814 			ServerFont font;
2815 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2816 				fAppFontManager);
2817 
2818 			if (status == B_OK) {
2819 				font.SetSize(size);
2820 				font.SetRotation(rotation);
2821 				font.SetShear(shear);
2822 				font.SetFalseBoldWidth(falseBoldWidth);
2823 				font.SetSpacing(spacing);
2824 				font.SetFlags(flags);
2825 
2826 				// TODO: implement for real
2827 				status = font.GetBoundingBoxes(charArray, numBytes,
2828 					numChars, rectArray, stringEscapement, mode, delta,
2829 					code == AS_GET_BOUNDINGBOXES_STRING);
2830 				if (status == B_OK) {
2831 					fLink.StartMessage(B_OK);
2832 					for (int32 i = 0; i < numChars; i++)
2833 						fLink.Attach<BRect>(rectArray[i]);
2834 				}
2835 			}
2836 
2837 			if (status != B_OK)
2838 				fLink.StartMessage(status);
2839 
2840 			fLink.Flush();
2841 			break;
2842 		}
2843 
2844 		case AS_GET_BOUNDINGBOXES_STRINGS:
2845 		{
2846 			FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_STRINGS\n",
2847 				Signature()));
2848 
2849 			// Attached Data:
2850 			// 1) uint16 - family ID
2851 			// 2) uint16 - style ID
2852 			// 3) float - point size
2853 			// 4) float - rotation
2854 			// 5) float - shear
2855 			// 6) float - false bold width
2856 			// 7) uint8 - spacing
2857 			// 8) uint32 - flags
2858 			// 9) font_metric_mode - mode
2859 			// 10) int32 numStrings
2860 			// 11) escapement_delta - additional delta (numStrings times)
2861 			// 12) int32 string length to measure (numStrings times)
2862 			// 13) string - string (numStrings times)
2863 
2864 			// Returns:
2865 			// 1) BRect - rects with numStrings entries
2866 
2867 			uint16 familyID, styleID;
2868 			uint32 flags;
2869 			float ptsize, rotation, shear, falseBoldWidth;
2870 			uint8 spacing;
2871 			font_metric_mode mode;
2872 
2873 			link.Read<uint16>(&familyID);
2874 			link.Read<uint16>(&styleID);
2875 			link.Read<float>(&ptsize);
2876 			link.Read<float>(&rotation);
2877 			link.Read<float>(&shear);
2878 			link.Read<float>(&falseBoldWidth);
2879 			link.Read<uint8>(&spacing);
2880 			link.Read<uint32>(&flags);
2881 			link.Read<font_metric_mode>(&mode);
2882 
2883 			int32 numStrings;
2884 			link.Read<int32>(&numStrings);
2885 
2886 			BStackOrHeapArray<escapement_delta, 64> deltaArray(numStrings);
2887 			BStackOrHeapArray<char*, 64> stringArray(numStrings);
2888 			BStackOrHeapArray<size_t, 64> lengthArray(numStrings);
2889 			BStackOrHeapArray<BRect, 64> rectArray(numStrings);
2890 			if (!deltaArray.IsValid() || !stringArray.IsValid()
2891 				|| !lengthArray.IsValid() || !rectArray.IsValid()) {
2892 				fLink.StartMessage(B_NO_MEMORY);
2893 				fLink.Flush();
2894 				break;
2895 			}
2896 
2897 			for (int32 i = 0; i < numStrings; i++) {
2898 				// This version of ReadString allocates the strings, we free
2899 				// them below
2900 				link.ReadString(&stringArray[i], &lengthArray[i]);
2901 				link.Read<escapement_delta>(&deltaArray[i]);
2902 			}
2903 
2904 			ServerFont font;
2905 			status_t status = font.SetFamilyAndStyle(familyID, styleID,
2906 				fAppFontManager);
2907 
2908 			if (status == B_OK) {
2909 				font.SetSize(ptsize);
2910 				font.SetRotation(rotation);
2911 				font.SetShear(shear);
2912 				font.SetFalseBoldWidth(falseBoldWidth);
2913 				font.SetSpacing(spacing);
2914 				font.SetFlags(flags);
2915 
2916 				status = font.GetBoundingBoxesForStrings(stringArray,
2917 					lengthArray, numStrings, rectArray, mode, deltaArray);
2918 				if (status == B_OK) {
2919 					fLink.StartMessage(B_OK);
2920 					fLink.Attach(rectArray, numStrings * sizeof(BRect));
2921 				}
2922 			}
2923 
2924 			for (int32 i = 0; i < numStrings; i++)
2925 				free(stringArray[i]);
2926 
2927 			if (status != B_OK)
2928 				fLink.StartMessage(status);
2929 
2930 			fLink.Flush();
2931 			break;
2932 		}
2933 
2934 		// Screen commands
2935 
2936 		case AS_VALID_SCREEN_ID:
2937 		{
2938 			// Attached data
2939 			// 1) int32 screen
2940 
2941 			int32 id;
2942 			if (link.Read<int32>(&id) == B_OK
2943 				&& id == B_MAIN_SCREEN_ID.id)
2944 				fLink.StartMessage(B_OK);
2945 			else
2946 				fLink.StartMessage(B_ERROR);
2947 
2948 			fLink.Flush();
2949 			break;
2950 		}
2951 
2952 		case AS_GET_NEXT_SCREEN_ID:
2953 		{
2954 			// Attached data
2955 			// 1) int32 screen
2956 
2957 			int32 id;
2958 			link.Read<int32>(&id);
2959 
2960 			// TODO: for now, just say we're the last one
2961 			fLink.StartMessage(B_ENTRY_NOT_FOUND);
2962 			fLink.Flush();
2963 			break;
2964 		}
2965 
2966 		case AS_GET_SCREEN_ID_FROM_WINDOW:
2967 		{
2968 			status_t status = B_BAD_VALUE;
2969 
2970 			// Attached data
2971 			// 1) int32 - window client token
2972 
2973 			int32 clientToken;
2974 			if (link.Read<int32>(&clientToken) != B_OK)
2975 				status = B_BAD_DATA;
2976 			else {
2977 				BAutolock locker(fWindowListLock);
2978 
2979 				for (int32 i = fWindowList.CountItems(); i-- > 0;) {
2980 					ServerWindow* serverWindow = fWindowList.ItemAt(i);
2981 
2982 					if (serverWindow->ClientToken() == clientToken) {
2983 						AutoReadLocker _(fDesktop->ScreenLocker());
2984 
2985 						// found it!
2986 						Window* window = serverWindow->Window();
2987 						const Screen* screen = NULL;
2988 						if (window != NULL)
2989 							screen = window->Screen();
2990 
2991 						if (screen == NULL) {
2992 							// The window hasn't been added to the desktop yet,
2993 							// or it's an offscreen window
2994 							break;
2995 						}
2996 
2997 						fLink.StartMessage(B_OK);
2998 						fLink.Attach<int32>(screen->ID());
2999 						status = B_OK;
3000 						break;
3001 					}
3002 				}
3003 			}
3004 
3005 			if (status != B_OK)
3006 				fLink.StartMessage(status);
3007 			fLink.Flush();
3008 			break;
3009 		}
3010 
3011 		case AS_SCREEN_GET_MODE:
3012 		{
3013 			STRACE(("ServerApp %s: AS_SCREEN_GET_MODE\n", Signature()));
3014 
3015 			// Attached data
3016 			// 1) int32 screen
3017 			// 2) uint32 workspace index
3018 
3019 			int32 id;
3020 			link.Read<int32>(&id);
3021 			uint32 workspace;
3022 			link.Read<uint32>(&workspace);
3023 
3024 			display_mode mode;
3025 			status_t status = fDesktop->GetScreenMode(workspace, id, mode);
3026 
3027 			fLink.StartMessage(status);
3028 			if (status == B_OK)
3029 				fLink.Attach<display_mode>(mode);
3030 			fLink.Flush();
3031 			break;
3032 		}
3033 
3034 		case AS_SCREEN_SET_MODE:
3035 		{
3036 			STRACE(("ServerApp %s: AS_SCREEN_SET_MODE\n", Signature()));
3037 
3038 			// Attached data
3039 			// 1) int32 screen
3040 			// 2) workspace index
3041 			// 3) display_mode to set
3042 			// 4) 'makeDefault' boolean
3043 
3044 			int32 id;
3045 			link.Read<int32>(&id);
3046 			uint32 workspace;
3047 			link.Read<uint32>(&workspace);
3048 
3049 			display_mode mode;
3050 			link.Read<display_mode>(&mode);
3051 
3052 			bool makeDefault = false;
3053 			status_t status = link.Read<bool>(&makeDefault);
3054 
3055 			if (status == B_OK) {
3056 				status = fDesktop->SetScreenMode(workspace, id, mode,
3057 					makeDefault);
3058 			}
3059 			if (status == B_OK) {
3060 				if (workspace == (uint32)B_CURRENT_WORKSPACE_INDEX
3061 					&& fDesktop->LockSingleWindow()) {
3062 					workspace = fDesktop->CurrentWorkspace();
3063 					fDesktop->UnlockSingleWindow();
3064 				}
3065 
3066 				if (!makeDefault) {
3067 					// Memorize the screen change, so that it can be reverted
3068 					// later
3069 					fTemporaryDisplayModeChange |= 1 << workspace;
3070 				} else
3071 					fTemporaryDisplayModeChange &= ~(1 << workspace);
3072 			}
3073 
3074 			fLink.StartMessage(status);
3075 			fLink.Flush();
3076 			break;
3077 		}
3078 
3079 		case AS_PROPOSE_MODE:
3080 		{
3081 			STRACE(("ServerApp %s: AS_PROPOSE_MODE\n", Signature()));
3082 			int32 id;
3083 			link.Read<int32>(&id);
3084 
3085 			display_mode target, low, high;
3086 			link.Read<display_mode>(&target);
3087 			link.Read<display_mode>(&low);
3088 			link.Read<display_mode>(&high);
3089 			status_t status = fDesktop->HWInterface()->ProposeMode(&target,
3090 				&low, &high);
3091 
3092 			// ProposeMode() returns B_BAD_VALUE to hint that the candidate is
3093 			// not within the given limits (but is supported)
3094 			if (status == B_OK || status == B_BAD_VALUE) {
3095 				fLink.StartMessage(B_OK);
3096 				fLink.Attach<display_mode>(target);
3097 				fLink.Attach<bool>(status == B_OK);
3098 			} else
3099 				fLink.StartMessage(status);
3100 
3101 			fLink.Flush();
3102 			break;
3103 		}
3104 
3105 		case AS_GET_MODE_LIST:
3106 		{
3107 			int32 id;
3108 			link.Read<int32>(&id);
3109 			// TODO: use this screen id
3110 
3111 			display_mode* modeList;
3112 			uint32 count;
3113 			status_t status = fDesktop->HWInterface()->GetModeList(&modeList,
3114 				&count);
3115 			if (status == B_OK) {
3116 				fLink.StartMessage(B_OK);
3117 				fLink.Attach<uint32>(count);
3118 				fLink.Attach(modeList, sizeof(display_mode) * count);
3119 
3120 				delete[] modeList;
3121 			} else
3122 				fLink.StartMessage(status);
3123 
3124 			fLink.Flush();
3125 			break;
3126 		}
3127 
3128 		case AS_GET_SCREEN_FRAME:
3129 		{
3130 			STRACE(("ServerApp %s: AS_GET_SCREEN_FRAME\n", Signature()));
3131 
3132 			// Attached data
3133 			// 1) int32 screen
3134 			// 2) uint32 workspace index
3135 
3136 			int32 id;
3137 			link.Read<int32>(&id);
3138 			uint32 workspace;
3139 			link.Read<uint32>(&workspace);
3140 
3141 			BRect frame;
3142 			status_t status = fDesktop->GetScreenFrame(workspace, id, frame);
3143 
3144 			fLink.StartMessage(status);
3145 			if (status == B_OK)
3146 				fLink.Attach<BRect>(frame);
3147 
3148 			fLink.Flush();
3149 			break;
3150 		}
3151 
3152 		case AS_SCREEN_GET_COLORMAP:
3153 		{
3154 			STRACE(("ServerApp %s: AS_SCREEN_GET_COLORMAP\n", Signature()));
3155 
3156 			int32 id;
3157 			link.Read<int32>(&id);
3158 
3159 			const color_map* colorMap = SystemColorMap();
3160 			if (colorMap != NULL) {
3161 				fLink.StartMessage(B_OK);
3162 				fLink.Attach<color_map>(*colorMap);
3163 			} else
3164 				fLink.StartMessage(B_ERROR);
3165 
3166 			fLink.Flush();
3167 			break;
3168 		}
3169 
3170 		case AS_GET_DESKTOP_COLOR:
3171 		{
3172 			STRACE(("ServerApp %s: get desktop color\n", Signature()));
3173 
3174 			uint32 index;
3175 			link.Read<uint32>(&index);
3176 
3177 			fLink.StartMessage(B_OK);
3178 			fDesktop->LockSingleWindow();
3179 
3180 			// we're nice to our children (and also take the default case
3181 			// into account which asks for the current workspace)
3182 			if (index >= (uint32)kMaxWorkspaces)
3183 				index = fDesktop->CurrentWorkspace();
3184 
3185 			Workspace workspace(*fDesktop, index, true);
3186 			fLink.Attach<rgb_color>(workspace.Color());
3187 
3188 			fDesktop->UnlockSingleWindow();
3189 			fLink.Flush();
3190 			break;
3191 		}
3192 
3193 		case AS_SET_DESKTOP_COLOR:
3194 		{
3195 			STRACE(("ServerApp %s: set desktop color\n", Signature()));
3196 
3197 			rgb_color color;
3198 			uint32 index;
3199 			bool makeDefault;
3200 
3201 			link.Read<rgb_color>(&color);
3202 			link.Read<uint32>(&index);
3203 			if (link.Read<bool>(&makeDefault) != B_OK)
3204 				break;
3205 
3206 			fDesktop->LockAllWindows();
3207 
3208 			// we're nice to our children (and also take the default case
3209 			// into account which asks for the current workspace)
3210 			if (index >= (uint32)kMaxWorkspaces)
3211 				index = fDesktop->CurrentWorkspace();
3212 
3213 			Workspace workspace(*fDesktop, index);
3214 			workspace.SetColor(color, makeDefault);
3215 
3216 			fDesktop->UnlockAllWindows();
3217 			break;
3218 		}
3219 
3220 		case AS_GET_ACCELERANT_INFO:
3221 		{
3222 			STRACE(("ServerApp %s: get accelerant info\n", Signature()));
3223 
3224 			// We aren't using the screen_id for now...
3225 			int32 id;
3226 			link.Read<int32>(&id);
3227 
3228 			accelerant_device_info accelerantInfo;
3229 			// TODO: I wonder if there should be a "desktop" lock...
3230 			status_t status
3231 				= fDesktop->HWInterface()->GetDeviceInfo(&accelerantInfo);
3232 			if (status == B_OK) {
3233 				fLink.StartMessage(B_OK);
3234 				fLink.Attach<accelerant_device_info>(accelerantInfo);
3235 			} else
3236 				fLink.StartMessage(status);
3237 
3238 			fLink.Flush();
3239 			break;
3240 		}
3241 
3242 		case AS_GET_MONITOR_INFO:
3243 		{
3244 			STRACE(("ServerApp %s: get monitor info\n", Signature()));
3245 
3246 			// We aren't using the screen_id for now...
3247 			int32 id;
3248 			link.Read<int32>(&id);
3249 
3250 			monitor_info info;
3251 			// TODO: I wonder if there should be a "desktop" lock...
3252 			status_t status = fDesktop->HWInterface()->GetMonitorInfo(&info);
3253 			if (status == B_OK) {
3254 				fLink.StartMessage(B_OK);
3255 				fLink.Attach<monitor_info>(info);
3256 			} else
3257 				fLink.StartMessage(status);
3258 
3259 			fLink.Flush();
3260 			break;
3261 		}
3262 
3263 		case AS_GET_FRAME_BUFFER_CONFIG:
3264 		{
3265 			STRACE(("ServerApp %s: get frame buffer config\n", Signature()));
3266 
3267 			// We aren't using the screen_id for now...
3268 			int32 id;
3269 			link.Read<int32>(&id);
3270 
3271 			frame_buffer_config config;
3272 			// TODO: I wonder if there should be a "desktop" lock...
3273 			status_t status = fDesktop->HWInterface()->GetFrameBufferConfig(config);
3274 			if (status == B_OK) {
3275 				fLink.StartMessage(B_OK);
3276 				fLink.Attach<frame_buffer_config>(config);
3277 			} else
3278 				fLink.StartMessage(status);
3279 
3280 			fLink.Flush();
3281 			break;
3282 		}
3283 
3284 		case AS_GET_RETRACE_SEMAPHORE:
3285 		{
3286 			STRACE(("ServerApp %s: get retrace semaphore\n", Signature()));
3287 
3288 			// We aren't using the screen_id for now...
3289 			int32 id;
3290 			link.Read<int32>(&id);
3291 
3292 			fLink.StartMessage(B_OK);
3293 			fLink.Attach<sem_id>(fDesktop->HWInterface()->RetraceSemaphore());
3294 			fLink.Flush();
3295 			break;
3296 		}
3297 
3298 		case AS_GET_TIMING_CONSTRAINTS:
3299 		{
3300 			STRACE(("ServerApp %s: get timing constraints\n", Signature()));
3301 
3302 			// We aren't using the screen_id for now...
3303 			int32 id;
3304 			link.Read<int32>(&id);
3305 
3306 			display_timing_constraints constraints;
3307 			status_t status = fDesktop->HWInterface()->GetTimingConstraints(
3308 				&constraints);
3309 			if (status == B_OK) {
3310 				fLink.StartMessage(B_OK);
3311 				fLink.Attach<display_timing_constraints>(constraints);
3312 			} else
3313 				fLink.StartMessage(status);
3314 
3315 			fLink.Flush();
3316 			break;
3317 		}
3318 
3319 		case AS_GET_PIXEL_CLOCK_LIMITS:
3320 		{
3321 			STRACE(("ServerApp %s: get pixel clock limits\n", Signature()));
3322 			// We aren't using the screen_id for now...
3323 			int32 id;
3324 			link.Read<int32>(&id);
3325 			display_mode mode;
3326 			link.Read<display_mode>(&mode);
3327 
3328 			uint32 low, high;
3329 			status_t status = fDesktop->HWInterface()->GetPixelClockLimits(&mode,
3330 				&low, &high);
3331 			if (status == B_OK) {
3332 				fLink.StartMessage(B_OK);
3333 				fLink.Attach<uint32>(low);
3334 				fLink.Attach<uint32>(high);
3335 			} else
3336 				fLink.StartMessage(status);
3337 
3338 			fLink.Flush();
3339 			break;
3340 		}
3341 
3342 		case AS_SET_DPMS:
3343 		{
3344 			STRACE(("ServerApp %s: AS_SET_DPMS\n", Signature()));
3345 			int32 id;
3346 			link.Read<int32>(&id);
3347 
3348 			uint32 mode;
3349 			link.Read<uint32>(&mode);
3350 
3351 			status_t status = fDesktop->HWInterface()->SetDPMSMode(mode);
3352 			fLink.StartMessage(status);
3353 
3354 			fLink.Flush();
3355 			break;
3356 		}
3357 
3358 		case AS_GET_DPMS_STATE:
3359 		{
3360 			STRACE(("ServerApp %s: AS_GET_DPMS_STATE\n", Signature()));
3361 
3362 			int32 id;
3363 			link.Read<int32>(&id);
3364 
3365 			uint32 state = fDesktop->HWInterface()->DPMSMode();
3366 			fLink.StartMessage(B_OK);
3367 			fLink.Attach<uint32>(state);
3368 			fLink.Flush();
3369 			break;
3370 		}
3371 
3372 		case AS_GET_DPMS_CAPABILITIES:
3373 		{
3374 			STRACE(("ServerApp %s: AS_GET_DPMS_CAPABILITIES\n", Signature()));
3375 			int32 id;
3376 			link.Read<int32>(&id);
3377 
3378 			uint32 capabilities = fDesktop->HWInterface()->DPMSCapabilities();
3379 			fLink.StartMessage(B_OK);
3380 			fLink.Attach<uint32>(capabilities);
3381 			fLink.Flush();
3382 			break;
3383 		}
3384 
3385 		case AS_SCREEN_SET_BRIGHTNESS:
3386 		{
3387 			STRACE(("ServerApp %s: AS_SCREEN_SET_BRIGHTNESS\n", Signature()));
3388 			int32 id;
3389 			link.Read<int32>(&id);
3390 
3391 			float brightness;
3392 			link.Read<float>(&brightness);
3393 
3394 			status_t status = fDesktop->SetBrightness(id, brightness);
3395 			fLink.StartMessage(status);
3396 
3397 			fLink.Flush();
3398 			break;
3399 		}
3400 
3401 		case AS_SCREEN_GET_BRIGHTNESS:
3402 		{
3403 			STRACE(("ServerApp %s: AS_SCREEN_GET_BRIGHTNESS\n", Signature()));
3404 			int32 id;
3405 			link.Read<int32>(&id);
3406 
3407 			float brightness;
3408 			status_t result = fDesktop->HWInterface()->GetBrightness(&brightness);
3409 			fLink.StartMessage(result);
3410 			if (result == B_OK)
3411 				fLink.Attach<float>(brightness);
3412 			fLink.Flush();
3413 			break;
3414 		}
3415 
3416 		case AS_READ_BITMAP:
3417 		{
3418 			STRACE(("ServerApp %s: AS_READ_BITMAP\n", Signature()));
3419 			int32 token;
3420 			link.Read<int32>(&token);
3421 
3422 			bool drawCursor = true;
3423 			link.Read<bool>(&drawCursor);
3424 
3425 			BRect bounds;
3426 			link.Read<BRect>(&bounds);
3427 
3428 			bool success = false;
3429 
3430 			BReference<ServerBitmap> bitmap(GetBitmap(token), true);
3431 			if (bitmap != NULL) {
3432 				if (fDesktop->GetDrawingEngine()->LockExclusiveAccess()) {
3433 					success = fDesktop->GetDrawingEngine()->ReadBitmap(bitmap,
3434 						drawCursor, bounds) == B_OK;
3435 					fDesktop->GetDrawingEngine()->UnlockExclusiveAccess();
3436 				}
3437 			}
3438 
3439 			if (success)
3440 				fLink.StartMessage(B_OK);
3441 			else
3442 				fLink.StartMessage(B_BAD_VALUE);
3443 
3444 			fLink.Flush();
3445 			break;
3446 		}
3447 
3448 		case AS_GET_ACCELERANT_PATH:
3449 		{
3450 			int32 id;
3451 			fLink.Read<int32>(&id);
3452 
3453 			BString path;
3454 			status_t status = fDesktop->HWInterface()->GetAccelerantPath(path);
3455 			fLink.StartMessage(status);
3456 			if (status == B_OK)
3457 				fLink.AttachString(path.String());
3458 
3459 			fLink.Flush();
3460 			break;
3461 		}
3462 
3463 		case AS_GET_DRIVER_PATH:
3464 		{
3465 			int32 id;
3466 			fLink.Read<int32>(&id);
3467 
3468 			BString path;
3469 			status_t status = fDesktop->HWInterface()->GetDriverPath(path);
3470 			fLink.StartMessage(status);
3471 			if (status == B_OK)
3472 				fLink.AttachString(path.String());
3473 
3474 			fLink.Flush();
3475 			break;
3476 		}
3477 
3478 		// BWindowScreen communication
3479 
3480 		case AS_DIRECT_SCREEN_LOCK:
3481 		{
3482 			bool lock;
3483 			link.Read<bool>(&lock);
3484 
3485 			status_t status;
3486 			if (lock)
3487 				status = fDesktop->LockDirectScreen(ClientTeam());
3488 			else
3489 				status = fDesktop->UnlockDirectScreen(ClientTeam());
3490 
3491 			fLink.StartMessage(status);
3492 			fLink.Flush();
3493 			break;
3494 		}
3495 
3496 		// Hinting and aliasing
3497 
3498 		case AS_SET_SUBPIXEL_ANTIALIASING:
3499 		{
3500 			bool subpix;
3501 			if (link.Read<bool>(&subpix) == B_OK) {
3502 				LockedDesktopSettings settings(fDesktop);
3503 				settings.SetSubpixelAntialiasing(subpix);
3504 			}
3505 			fDesktop->Redraw();
3506 			break;
3507 		}
3508 
3509 		case AS_GET_SUBPIXEL_ANTIALIASING:
3510 		{
3511 			DesktopSettings settings(fDesktop);
3512 			fLink.StartMessage(B_OK);
3513 			fLink.Attach<bool>(settings.SubpixelAntialiasing());
3514 			fLink.Flush();
3515 			break;
3516 		}
3517 
3518 		case AS_SET_HINTING:
3519 		{
3520 			uint8 hinting;
3521 			if (link.Read<uint8>(&hinting) == B_OK && hinting < 3) {
3522 				LockedDesktopSettings settings(fDesktop);
3523 				if (hinting != settings.Hinting()) {
3524 					settings.SetHinting(hinting);
3525 					fDesktop->Redraw();
3526 				}
3527 			}
3528 			break;
3529 		}
3530 
3531 		case AS_GET_HINTING:
3532 		{
3533 			DesktopSettings settings(fDesktop);
3534 			fLink.StartMessage(B_OK);
3535 			fLink.Attach<uint8>(settings.Hinting());
3536 			fLink.Flush();
3537 			break;
3538 		}
3539 
3540 		case AS_SET_SUBPIXEL_AVERAGE_WEIGHT:
3541 		{
3542 			uint8 averageWeight;
3543 			if (link.Read<uint8>(&averageWeight) == B_OK) {
3544 				LockedDesktopSettings settings(fDesktop);
3545 				settings.SetSubpixelAverageWeight(averageWeight);
3546 			}
3547 			fDesktop->Redraw();
3548 			break;
3549 		}
3550 
3551 		case AS_GET_SUBPIXEL_AVERAGE_WEIGHT:
3552 		{
3553 			DesktopSettings settings(fDesktop);
3554 			fLink.StartMessage(B_OK);
3555 			fLink.Attach<uint8>(settings.SubpixelAverageWeight());
3556 			fLink.Flush();
3557 			break;
3558 		}
3559 
3560 		case AS_SET_SUBPIXEL_ORDERING:
3561 		{
3562 			bool subpixelOrdering;
3563 			if (link.Read<bool>(&subpixelOrdering) == B_OK) {
3564 				LockedDesktopSettings settings(fDesktop);
3565 				settings.SetSubpixelOrderingRegular(subpixelOrdering);
3566 			}
3567 			fDesktop->Redraw();
3568 			break;
3569 		}
3570 
3571 		case AS_GET_SUBPIXEL_ORDERING:
3572 		{
3573 			DesktopSettings settings(fDesktop);
3574 			fLink.StartMessage(B_OK);
3575 			fLink.Attach<bool>(settings.IsSubpixelOrderingRegular());
3576 			fLink.Flush();
3577 			break;
3578 		}
3579 
3580 		default:
3581 			printf("ServerApp %s received unhandled message code %" B_PRId32
3582 				"\n", Signature(), code);
3583 
3584 			if (link.NeedsReply()) {
3585 				// the client is now blocking and waiting for a reply!
3586 				fLink.StartMessage(B_ERROR);
3587 				fLink.Flush();
3588 			} else
3589 				puts("message doesn't need a reply!");
3590 			break;
3591 	}
3592 }
3593 
3594 
3595 /*!	\brief The thread function ServerApps use to monitor messages
3596 */
3597 void
3598 ServerApp::_MessageLooper()
3599 {
3600 	// Message-dispatching loop for the ServerApp
3601 
3602 	// get our own team ID
3603 	thread_info threadInfo;
3604 	get_thread_info(fThread, &threadInfo);
3605 
3606 	// First let's tell the client how to talk with us.
3607 	fLink.StartMessage(B_OK);
3608 	fLink.Attach<port_id>(fMessagePort);
3609 	fLink.Attach<area_id>(fDesktop->SharedReadOnlyArea());
3610 	fLink.Attach<team_id>(threadInfo.team);
3611 	fLink.Flush();
3612 
3613 	BPrivate::LinkReceiver &receiver = fLink.Receiver();
3614 
3615 	int32 code;
3616 	status_t err = B_OK;
3617 
3618 	while (!fQuitting) {
3619 		STRACE(("info: ServerApp::_MessageLooper() listening on port %" B_PRId32
3620 			".\n", fMessagePort));
3621 
3622 		err = receiver.GetNextMessage(code);
3623 		if (err != B_OK || code == B_QUIT_REQUESTED) {
3624 			STRACE(("ServerApp: application seems to be gone...\n"));
3625 
3626 			// Tell desktop to quit us
3627 			BPrivate::LinkSender link(fDesktop->MessagePort());
3628 			link.StartMessage(AS_DELETE_APP);
3629 			link.Attach<thread_id>(Thread());
3630 			link.Flush();
3631 			break;
3632 		}
3633 
3634 		switch (code) {
3635 			case kMsgAppQuit:
3636 				// we receive this from our destructor on quit
3637 				fQuitting = true;
3638 				break;
3639 
3640 			case AS_QUIT_APP:
3641 			{
3642 				// This message is received only when the app_server is asked
3643 				// to shut down in test/debug mode. Of course, if we are testing
3644 				// while using AccelerantDriver, we do NOT want to shut down
3645 				// client applications. The server can be quit in this fashion
3646 				// through the driver's interface, such as closing the
3647 				// ViewDriver's window.
3648 
3649 				STRACE(("ServerApp %s:Server shutdown notification received\n",
3650 					Signature()));
3651 
3652 				// If we are using the real, accelerated version of the
3653 				// DrawingEngine, we do NOT want the user to be able shut down
3654 				// the server. The results would NOT be pretty
3655 #if TEST_MODE
3656 				BMessage pleaseQuit(B_QUIT_REQUESTED);
3657 				SendMessageToClient(&pleaseQuit);
3658 #endif
3659 				break;
3660 			}
3661 
3662 			default:
3663 				STRACE(("ServerApp %s: Got a Message to dispatch\n",
3664 					Signature()));
3665 				_DispatchMessage(code, receiver);
3666 				break;
3667 		}
3668 	}
3669 
3670 	// Quit() will send us a message; we're handling the exiting procedure
3671 	thread_id sender;
3672 	sem_id shutdownSemaphore;
3673 	receive_data(&sender, &shutdownSemaphore, sizeof(sem_id));
3674 
3675 	delete this;
3676 
3677 	if (shutdownSemaphore >= B_OK)
3678 		release_sem(shutdownSemaphore);
3679 }
3680 
3681 
3682 status_t
3683 ServerApp::_CreateWindow(int32 code, BPrivate::LinkReceiver& link,
3684 	port_id& clientReplyPort)
3685 {
3686 	// Attached data:
3687 	// 1) int32 bitmap token (only for AS_CREATE_OFFSCREEN_WINDOW)
3688 	// 2) BRect window frame
3689 	// 3) uint32 window look
3690 	// 4) uint32 window feel
3691 	// 5) uint32 window flags
3692 	// 6) uint32 workspace index
3693 	// 7) int32 BHandler token of the window
3694 	// 8) port_id window's reply port
3695 	// 9) port_id window's looper port
3696 	// 10) const char * title
3697 
3698 	BRect frame;
3699 	int32 bitmapToken;
3700 	uint32 look;
3701 	uint32 feel;
3702 	uint32 flags;
3703 	uint32 workspaces;
3704 	int32 token;
3705 	port_id looperPort;
3706 	char* title;
3707 
3708 	if (code == AS_CREATE_OFFSCREEN_WINDOW)
3709 		link.Read<int32>(&bitmapToken);
3710 
3711 	link.Read<BRect>(&frame);
3712 	link.Read<uint32>(&look);
3713 	link.Read<uint32>(&feel);
3714 	link.Read<uint32>(&flags);
3715 	link.Read<uint32>(&workspaces);
3716 	link.Read<int32>(&token);
3717 	link.Read<port_id>(&clientReplyPort);
3718 	link.Read<port_id>(&looperPort);
3719 	if (link.ReadString(&title) != B_OK)
3720 		return B_ERROR;
3721 
3722 	if (!frame.IsValid()) {
3723 		// make sure we pass a valid rectangle to ServerWindow
3724 		frame.right = frame.left + 1;
3725 		frame.bottom = frame.top + 1;
3726 	}
3727 
3728 	status_t status = B_NO_MEMORY;
3729 	ServerWindow *window = NULL;
3730 
3731 	if (code == AS_CREATE_OFFSCREEN_WINDOW) {
3732 		ServerBitmap* bitmap = GetBitmap(bitmapToken);
3733 
3734 		if (bitmap != NULL) {
3735 			window = new (nothrow) OffscreenServerWindow(title, this,
3736 				clientReplyPort, looperPort, token, bitmap);
3737 		} else
3738 			status = B_ERROR;
3739 	} else {
3740 		window = new (nothrow) ServerWindow(title, this, clientReplyPort,
3741 			looperPort, token);
3742 		STRACE(("\nServerApp %s: New Window %s (%g:%g, %g:%g)\n",
3743 			Signature(), title, frame.left, frame.top,
3744 			frame.right, frame.bottom));
3745 	}
3746 
3747 	free(title);
3748 
3749 	// NOTE: the reply to the client is handled in ServerWindow::Run()
3750 	if (window != NULL) {
3751 		status = window->Init(frame, (window_look)look, (window_feel)feel,
3752 			flags, workspaces);
3753 		if (status == B_OK) {
3754 			status = window->Run();
3755 			if (status != B_OK) {
3756 				syslog(LOG_ERR, "ServerApp::_CreateWindow() - failed to run "
3757 					"the window thread\n");
3758 			}
3759 		}
3760 
3761 		if (status != B_OK)
3762 			delete window;
3763 	}
3764 
3765 	return status;
3766 }
3767 
3768 
3769 bool
3770 ServerApp::_HasWindowUnderMouse()
3771 {
3772 	BAutolock locker(fWindowListLock);
3773 
3774 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
3775 		ServerWindow* serverWindow = fWindowList.ItemAt(i);
3776 
3777 		if (fDesktop->ViewUnderMouse(serverWindow->Window()) != B_NULL_TOKEN)
3778 			return true;
3779 	}
3780 
3781 	return false;
3782 }
3783 
3784 
3785 bool
3786 ServerApp::_AddBitmap(ServerBitmap* bitmap)
3787 {
3788 	BAutolock _(fMapLocker);
3789 
3790 	try {
3791 		fBitmapMap.insert(std::make_pair(bitmap->Token(), BReference<ServerBitmap>(bitmap, false)));
3792 	} catch (std::bad_alloc& exception) {
3793 		return false;
3794 	}
3795 
3796 	bitmap->SetOwner(this);
3797 	return true;
3798 }
3799 
3800 
3801 void
3802 ServerApp::_DeleteBitmap(ServerBitmap* bitmap)
3803 {
3804 	ASSERT(fMapLocker.IsLocked());
3805 
3806 	gBitmapManager->BitmapRemoved(bitmap);
3807 	fBitmapMap.erase(bitmap->Token());
3808 }
3809 
3810 
3811 ServerBitmap*
3812 ServerApp::_FindBitmap(int32 token) const
3813 {
3814 	ASSERT(fMapLocker.IsLocked());
3815 
3816 	BitmapMap::const_iterator iterator = fBitmapMap.find(token);
3817 	if (iterator == fBitmapMap.end())
3818 		return NULL;
3819 
3820 	return iterator->second;
3821 }
3822 
3823 
3824 ServerPicture*
3825 ServerApp::_FindPicture(int32 token) const
3826 {
3827 	ASSERT(fMapLocker.IsLocked());
3828 
3829 	PictureMap::const_iterator iterator = fPictureMap.find(token);
3830 	if (iterator == fPictureMap.end())
3831 		return NULL;
3832 
3833 	return iterator->second;
3834 }
3835