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