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