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