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