xref: /haiku/src/servers/app/ServerApp.cpp (revision 03187b607b2b5eec7ee059f1ead09bdba14991fb)
1 /*
2  * Copyright 2001-2009, 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  */
15 
16 
17 /*!	\class ServerApp ServerApp.h
18 	\brief Counterpart to BApplication within the app_server
19 */
20 
21 
22 #include "ServerApp.h"
23 
24 #include <new>
25 #include <stdio.h>
26 #include <string.h>
27 #include <syslog.h>
28 
29 #include <AppDefs.h>
30 #include <Autolock.h>
31 #include <Debug.h>
32 #include <List.h>
33 #include <ScrollBar.h>
34 #include <Shape.h>
35 #include <String.h>
36 
37 #include <FontPrivate.h>
38 #include <MessengerPrivate.h>
39 #include <PrivateScreen.h>
40 #include <RosterPrivate.h>
41 #include <ServerProtocol.h>
42 #include <WindowPrivate.h>
43 
44 #include "AppServer.h"
45 #include "BitmapManager.h"
46 #include "CursorManager.h"
47 #include "CursorSet.h"
48 #include "Desktop.h"
49 #include "DecorManager.h"
50 #include "DrawingEngine.h"
51 #include "EventStream.h"
52 #include "FontManager.h"
53 #include "HWInterface.h"
54 #include "InputManager.h"
55 #include "OffscreenServerWindow.h"
56 #include "Screen.h"
57 #include "ServerBitmap.h"
58 #include "ServerConfig.h"
59 #include "ServerCursor.h"
60 #include "ServerPicture.h"
61 #include "ServerTokenSpace.h"
62 #include "ServerWindow.h"
63 #include "SystemPalette.h"
64 #include "Window.h"
65 
66 
67 //#define DEBUG_SERVERAPP
68 #ifdef DEBUG_SERVERAPP
69 #	define STRACE(x) debug_printf x
70 #else
71 #	define STRACE(x) ;
72 #endif
73 
74 //#define DEBUG_SERVERAPP_FONT
75 #ifdef DEBUG_SERVERAPP_FONT
76 #	define FTRACE(x) debug_printf x
77 #else
78 #	define FTRACE(x) ;
79 #endif
80 
81 using std::nothrow;
82 
83 static const uint32 kMsgUpdateShowAllDraggers = '_adg';
84 static const uint32 kMsgAppQuit = 'appQ';
85 
86 
87 ServerApp::ServerApp(Desktop* desktop, port_id clientReplyPort,
88 		port_id clientLooperPort, team_id clientTeam,
89 		int32 clientToken, const char* signature)
90 	:
91 	MessageLooper("application"),
92 
93 	fMessagePort(-1),
94 	fClientReplyPort(clientReplyPort),
95 	fDesktop(desktop),
96 	fSignature(signature),
97 	fClientTeam(clientTeam),
98 	fWindowListLock("window list"),
99 	fTemporaryDisplayModeChange(0),
100 	fAppCursor(NULL),
101 	fViewCursor(NULL),
102 	fCursorHideLevel(0),
103 	fIsActive(false),
104 	fMemoryAllocator(this)
105 {
106 	if (fSignature == "")
107 		fSignature = "application/no-signature";
108 
109 	char name[B_OS_NAME_LENGTH];
110 	snprintf(name, sizeof(name), "a<%ld:%s", clientTeam, SignatureLeaf());
111 
112 	fMessagePort = create_port(DEFAULT_MONITOR_PORT_SIZE, name);
113 	if (fMessagePort < B_OK)
114 		return;
115 
116 	fLink.SetSenderPort(fClientReplyPort);
117 	fLink.SetReceiverPort(fMessagePort);
118 
119 	// we let the application own the port, so that we get aware when it's gone
120 	if (set_port_owner(fMessagePort, clientTeam) < B_OK) {
121 		delete_port(fMessagePort);
122 		fMessagePort = -1;
123 		return;
124 	}
125 
126 	BMessenger::Private(fHandlerMessenger).SetTo(fClientTeam,
127 		clientLooperPort, clientToken);
128 
129 	fInitialWorkspace = desktop->CurrentWorkspace();
130 		// TODO: this should probably be retrieved when the app is loaded!
131 
132 	// record the current system wide fonts..
133 	desktop->LockSingleWindow();
134 	DesktopSettings settings(desktop);
135 	settings.GetDefaultPlainFont(fPlainFont);
136 	settings.GetDefaultBoldFont(fBoldFont);
137 	settings.GetDefaultFixedFont(fFixedFont);
138 	desktop->UnlockSingleWindow();
139 
140 	STRACE(("ServerApp %s:\n", Signature()));
141 	STRACE(("\tBApp port: %ld\n", fClientReplyPort));
142 	STRACE(("\tReceiver port: %ld\n", fMessagePort));
143 }
144 
145 
146 ServerApp::~ServerApp()
147 {
148 	STRACE(("*ServerApp %s:~ServerApp()\n", Signature()));
149 	ASSERT(fQuitting);
150 
151 	// quit all server windows
152 
153 	fWindowListLock.Lock();
154 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
155 		ServerWindow* window = fWindowList.ItemAt(i);
156 		window->Quit();
157 	}
158 	fWindowListLock.Unlock();
159 
160 	// wait for the windows to quit
161 	snooze(20000);
162 
163 	fDesktop->RevertScreenModes(fTemporaryDisplayModeChange);
164 
165 	fWindowListLock.Lock();
166 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
167 		ServerWindow* window = fWindowList.ItemAt(i);
168 
169 		// A window could have been removed in the mean time
170 		// (if those 20 milli seconds from above weren't enough)
171 		if (window == NULL)
172 			continue;
173 
174 		sem_id deathSemaphore = window->DeathSemaphore();
175 		fWindowListLock.Unlock();
176 
177 		// wait 3 seconds for our window to quit - that's quite a long
178 		// time, but killing it might have desastrous effects
179 		if (MessageLooper::WaitForQuit(deathSemaphore, 3000000) != B_OK) {
180 			// This really shouldn't happen, as it shows we're buggy
181 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
182 			syslog(LOG_ERR, "ServerApp %s: ServerWindow doesn't respond!\n",
183 				Signature());
184 #else
185 			debugger("ServerWindow doesn't respond!\n");
186 #endif
187 		}
188 		fWindowListLock.Lock();
189 	}
190 
191 	for (int32 i = fBitmapList.CountItems(); i-- > 0;) {
192 		gBitmapManager->DeleteBitmap((ServerBitmap*)fBitmapList.ItemAt(i));
193 	}
194 
195 	for (int32 i = fPictureList.CountItems(); i-- > 0;) {
196 		delete (ServerPicture*)fPictureList.ItemAtFast(i);
197 	}
198 
199 	fDesktop->GetCursorManager().DeleteCursors(fClientTeam);
200 
201 	STRACE(("ServerApp %s::~ServerApp(): Exiting\n", Signature()));
202 }
203 
204 
205 /*!	\brief Checks if the application was initialized correctly
206 */
207 status_t
208 ServerApp::InitCheck()
209 {
210 	if (fMessagePort < B_OK)
211 		return fMessagePort;
212 
213 	if (fClientReplyPort < B_OK)
214 		return fClientReplyPort;
215 
216 	if (fWindowListLock.Sem() < B_OK)
217 		return fWindowListLock.Sem();
218 
219 	return B_OK;
220 }
221 
222 
223 /*!	\brief This quits the application and deletes it. You're not supposed
224 		to call its destructor directly.
225 
226 	At the point you're calling this method, the application should already
227 	be removed from the application list.
228 */
229 void
230 ServerApp::Quit(sem_id shutdownSemaphore)
231 {
232 	if (fThread < B_OK) {
233 		delete this;
234 		return;
235 	}
236 
237 	// execute application deletion in the message looper thread
238 
239 	fQuitting = true;
240 	PostMessage(kMsgAppQuit);
241 
242 	send_data(fThread, 'QUIT', &shutdownSemaphore, sizeof(sem_id));
243 }
244 
245 
246 /*!	\brief Send a message to the ServerApp's BApplication
247 	\param message The message to send
248 */
249 void
250 ServerApp::SendMessageToClient(BMessage* message) const
251 {
252 	status_t status = fHandlerMessenger.SendMessage(message, (BHandler*)NULL,
253 		100000);
254 	if (status != B_OK) {
255 		syslog(LOG_ERR, "app %s send to client failed: %s\n", Signature(),
256 			strerror(status));
257 	}
258 }
259 
260 
261 bool
262 ServerApp::_HasWindowUnderMouse()
263 {
264 	BAutolock locker(fWindowListLock);
265 
266 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
267 		ServerWindow* serverWindow = fWindowList.ItemAt(i);
268 
269 		if (fDesktop->ViewUnderMouse(serverWindow->Window()) != B_NULL_TOKEN)
270 			return true;
271 	}
272 
273 	return false;
274 }
275 
276 
277 /*!	\brief Sets the ServerApp's active status
278 	\param value The new status of the ServerApp.
279 
280 	This changes an internal flag and also sets the current cursor to the one
281 	specified by the application
282 */
283 void
284 ServerApp::Activate(bool value)
285 {
286 	if (fIsActive == value)
287 		return;
288 
289 	fIsActive = value;
290 
291 	if (fIsActive) {
292 		// notify registrar about the active app
293 		BRoster::Private roster;
294 		roster.UpdateActiveApp(ClientTeam());
295 
296 		if (_HasWindowUnderMouse()) {
297 			// Set the cursor to the application cursor, if any
298 			fDesktop->SetCursor(CurrentCursor());
299 		}
300 		fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0);
301 	}
302 }
303 
304 
305 void
306 ServerApp::SetCurrentCursor(ServerCursor* cursor)
307 {
308 	if (fViewCursor == cursor)
309 		return;
310 
311 	if (fViewCursor)
312 		fViewCursor->Release();
313 
314 	fViewCursor = cursor;
315 
316 	if (fViewCursor)
317 		fViewCursor->Acquire();
318 
319 	fDesktop->SetCursor(CurrentCursor());
320 }
321 
322 
323 ServerCursor*
324 ServerApp::CurrentCursor() const
325 {
326 	if (fViewCursor != NULL)
327 		return fViewCursor;
328 
329 	return fAppCursor;
330 }
331 
332 
333 void
334 ServerApp::_GetLooperName(char* name, size_t length)
335 {
336 	snprintf(name, length, "a:%ld:%s", ClientTeam(), SignatureLeaf());
337 }
338 
339 
340 /*!	\brief The thread function ServerApps use to monitor messages
341 */
342 void
343 ServerApp::_MessageLooper()
344 {
345 	// Message-dispatching loop for the ServerApp
346 
347 	// First let's tell the client how to talk with us.
348 	fLink.StartMessage(B_OK);
349 	fLink.Attach<port_id>(fMessagePort);
350 	fLink.Attach<area_id>(fDesktop->SharedReadOnlyArea());
351 	fLink.Flush();
352 
353 	BPrivate::LinkReceiver &receiver = fLink.Receiver();
354 
355 	int32 code;
356 	status_t err = B_OK;
357 
358 	while (!fQuitting) {
359 		STRACE(("info: ServerApp::_MessageLooper() listening on port %ld.\n",
360 			fMessagePort));
361 
362 		err = receiver.GetNextMessage(code, B_INFINITE_TIMEOUT);
363 		if (err != B_OK || code == B_QUIT_REQUESTED) {
364 			STRACE(("ServerApp: application seems to be gone...\n"));
365 
366 			// Tell desktop to quit us
367 			BPrivate::LinkSender link(fDesktop->MessagePort());
368 			link.StartMessage(AS_DELETE_APP);
369 			link.Attach<thread_id>(Thread());
370 			link.Flush();
371 			break;
372 		}
373 
374 		switch (code) {
375 			case kMsgAppQuit:
376 				// we receive this from our destructor on quit
377 				fQuitting = true;
378 				break;
379 
380 			case AS_QUIT_APP:
381 			{
382 				// This message is received only when the app_server is asked to
383 				// shut down in test/debug mode. Of course, if we are testing
384 				// while using AccelerantDriver, we do NOT want to shut down
385 				// client applications. The server can be quit in this fashion
386 				// through the driver's interface, such as closing the
387 				// ViewDriver's window.
388 
389 				STRACE(("ServerApp %s:Server shutdown notification received\n",
390 					Signature()));
391 
392 				// If we are using the real, accelerated version of the
393 				// DrawingEngine, we do NOT want the user to be able shut down
394 				// the server. The results would NOT be pretty
395 #if TEST_MODE
396 				BMessage pleaseQuit(B_QUIT_REQUESTED);
397 				SendMessageToClient(&pleaseQuit);
398 #endif
399 				break;
400 			}
401 
402 			default:
403 				STRACE(("ServerApp %s: Got a Message to dispatch\n",
404 					Signature()));
405 				_DispatchMessage(code, receiver);
406 				break;
407 		}
408 	}
409 
410 	// Quit() will send us a message; we're handling the exiting procedure
411 	thread_id sender;
412 	sem_id shutdownSemaphore;
413 	receive_data(&sender, &shutdownSemaphore, sizeof(sem_id));
414 
415 	delete this;
416 
417 	if (shutdownSemaphore >= B_OK)
418 		release_sem(shutdownSemaphore);
419 }
420 
421 
422 /*!	\brief Handler function for BApplication API messages
423 	\param code Identifier code for the message. Equivalent to BMessage::what
424 	\param buffer Any attachments
425 
426 	Note that the buffer's exact format is determined by the particular message.
427 	All attachments are placed in the buffer via a PortLink, so it will be a
428 	matter of casting and incrementing an index variable to access them.
429 */
430 void
431 ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
432 {
433 	switch (code) {
434 		case AS_REGISTER_INPUT_SERVER:
435 		{
436 			EventStream* stream
437 				= new(std::nothrow) InputServerStream(fHandlerMessenger);
438 			if (stream != NULL
439 				&& (!stream->IsValid() || !gInputManager->AddStream(stream))) {
440 				delete stream;
441 				break;
442 			}
443 
444 			// TODO: this should be done using notifications (so that an
445 			// abandoned stream will get noticed directly)
446 			if (fDesktop->EventDispatcher().InitCheck() != B_OK)
447 				fDesktop->EventDispatcher().SetTo(gInputManager->GetStream());
448 			break;
449 		}
450 
451 		case AS_APP_CRASHED:
452 			// Allow the debugger to show its window: if needed, remove any
453 			// kWindowScreenFeels from the windows of this application
454 			if (fDesktop->LockAllWindows()) {
455 				if (fWindowListLock.Lock()) {
456 					for (int32 i = fWindowList.CountItems(); i-- > 0;) {
457 						ServerWindow* serverWindow = fWindowList.ItemAt(i);
458 
459 						Window* window = serverWindow->Window();
460 						if (window == NULL || window->IsOffscreenWindow())
461 							continue;
462 
463 						if (window->Feel() == kWindowScreenFeel)
464 							fDesktop->SetWindowFeel(window, B_NORMAL_WINDOW_FEEL);
465 					}
466 
467 					fWindowListLock.Unlock();
468 				}
469 				fDesktop->UnlockAllWindows();
470 			}
471 			break;
472 
473 		case AS_CREATE_WINDOW:
474 		case AS_CREATE_OFFSCREEN_WINDOW:
475 		{
476 			port_id clientReplyPort = -1;
477 			status_t status = _CreateWindow(code, link, clientReplyPort);
478 
479 			// if sucessful, ServerWindow::Run() will already have replied
480 			if (status < B_OK) {
481 				// window creation failed, we need to notify the client
482 				BPrivate::LinkSender reply(clientReplyPort);
483 				reply.StartMessage(status);
484 				reply.Flush();
485 			}
486 			break;
487 		}
488 
489 		case AS_GET_WINDOW_LIST:
490 		{
491 			team_id team;
492 			if (link.Read<team_id>(&team) == B_OK)
493 				fDesktop->WriteWindowList(team, fLink.Sender());
494 			break;
495 		}
496 
497 		case AS_GET_WINDOW_INFO:
498 		{
499 			int32 serverToken;
500 			if (link.Read<int32>(&serverToken) == B_OK)
501 				fDesktop->WriteWindowInfo(serverToken, fLink.Sender());
502 			break;
503 		}
504 
505 		case AS_GET_WINDOW_ORDER:
506 		{
507 			int32 workspace;
508 			if (link.Read<int32>(&workspace) == B_OK)
509 				fDesktop->WriteWindowOrder(workspace, fLink.Sender());
510 			break;
511 		}
512 
513 		case AS_GET_APPLICATION_ORDER:
514 		{
515 			int32 workspace;
516 			if (link.Read<int32>(&workspace) == B_OK)
517 				fDesktop->WriteApplicationOrder(workspace, fLink.Sender());
518 			break;
519 		}
520 
521 		case AS_MINIMIZE_TEAM:
522 		{
523 			team_id team;
524 			if (link.Read<team_id>(&team) == B_OK)
525 				fDesktop->MinimizeApplication(team);
526 			break;
527 		}
528 
529 		case AS_BRING_TEAM_TO_FRONT:
530 		{
531 			team_id team;
532 			if (link.Read<team_id>(&team) == B_OK)
533 				fDesktop->BringApplicationToFront(team);
534 			break;
535 		}
536 
537 		case AS_WINDOW_ACTION:
538 		{
539 			int32 token;
540 			int32 action;
541 
542 			link.Read<int32>(&token);
543 			if (link.Read<int32>(&action) != B_OK)
544 				break;
545 
546 			fDesktop->WindowAction(token, action);
547 			break;
548 		}
549 
550 		// Decorator commands
551 
552 		case AS_SET_DECORATOR:
553 		{
554 			// Attached Data:
555 			// int32 the index of the decorator to use
556 
557 			int32 index;
558 			link.Read<int32>(&index);
559 			if (gDecorManager.SetDecorator(index))
560 				fDesktop->BroadcastToAllApps(AS_UPDATE_DECORATOR);
561 			break;
562 		}
563 		case AS_COUNT_DECORATORS:
564 		{
565 			fLink.StartMessage(B_OK);
566 			fLink.Attach<int32>(gDecorManager.CountDecorators());
567 			fLink.Flush();
568 			break;
569 		}
570 		case AS_GET_DECORATOR:
571 		{
572 			fLink.StartMessage(B_OK);
573 			fLink.Attach<int32>(gDecorManager.GetDecorator());
574 			fLink.Flush();
575 			break;
576 		}
577 		case AS_GET_DECORATOR_NAME:
578 		{
579 			int32 index;
580 			link.Read<int32>(&index);
581 
582 			BString str(gDecorManager.GetDecoratorName(index));
583 			if (str.CountChars() > 0) {
584 				fLink.StartMessage(B_OK);
585 				fLink.AttachString(str.String());
586 			} else
587 				fLink.StartMessage(B_ERROR);
588 
589 			fLink.Flush();
590 			break;
591 		}
592 		case AS_R5_SET_DECORATOR:
593 		{
594 			// Sort of supports Tracker's nifty Easter Egg. It was easy to do
595 			// and it's kind of neat, so why not?
596 
597 			// Attached Data:
598 			// int32 value of the decorator to use
599 			// 0: BeOS
600 			// 1: Amiga
601 			// 2: Windows
602 			// 3: MacOS
603 
604 			int32 decindex = 0;
605 			link.Read<int32>(&decindex);
606 
607 			if (gDecorManager.SetR5Decorator(decindex))
608 				fDesktop->BroadcastToAllApps(AS_UPDATE_DECORATOR);
609 
610 			break;
611 		}
612 		case AS_CREATE_BITMAP:
613 		{
614 			STRACE(("ServerApp %s: Received BBitmap creation request\n",
615 				Signature()));
616 
617 			// Allocate a bitmap for an application
618 
619 			// Attached Data:
620 			// 1) BRect bounds
621 			// 2) color_space space
622 			// 3) int32 bitmap_flags
623 			// 4) int32 bytes_per_row
624 			// 5) int32 screen_id
625 
626 			// Reply Data:
627 			//	1) int32 server token
628 			//	2) area_id id of the area in which the bitmap data resides
629 			//	3) int32 area pointer offset used to calculate fBasePtr
630 
631 			// First, let's attempt to allocate the bitmap
632 			ServerBitmap* bitmap = NULL;
633 			uint8 allocationFlags = kAllocator;
634 
635 			BRect frame;
636 			color_space colorSpace;
637 			uint32 flags;
638 			int32 bytesPerRow;
639 			int32 screenID;
640 
641 			link.Read<BRect>(&frame);
642 			link.Read<color_space>(&colorSpace);
643 			link.Read<uint32>(&flags);
644 			link.Read<int32>(&bytesPerRow);
645 			if (link.Read<int32>(&screenID) == B_OK) {
646 				// TODO: choose the right HWInterface with regards to the
647 				// screenID
648 				bitmap = gBitmapManager->CreateBitmap(&fMemoryAllocator,
649 					*fDesktop->HWInterface(), frame, colorSpace, flags,
650 					bytesPerRow, screenID, &allocationFlags);
651 			}
652 
653 			STRACE(("ServerApp %s: Create Bitmap (%.1fx%.1f)\n",
654 				Signature(), frame.Width() + 1, frame.Height() + 1));
655 
656 			if (bitmap != NULL && fBitmapList.AddItem(bitmap)) {
657 				bitmap->SetOwner(this);
658 
659 				fLink.StartMessage(B_OK);
660 				fLink.Attach<int32>(bitmap->Token());
661 				fLink.Attach<uint8>(allocationFlags);
662 
663 				fLink.Attach<area_id>(
664 					fMemoryAllocator.Area(bitmap->AllocationCookie()));
665 				fLink.Attach<int32>(
666 					fMemoryAllocator.AreaOffset(bitmap->AllocationCookie()));
667 
668 				if (allocationFlags & kFramebuffer)
669 					fLink.Attach<int32>(bitmap->BytesPerRow());
670 			} else {
671 				if (bitmap != NULL)
672 					gBitmapManager->DeleteBitmap(bitmap);
673 
674 				fLink.StartMessage(B_NO_MEMORY);
675 			}
676 
677 			fLink.Flush();
678 			break;
679 		}
680 		case AS_DELETE_BITMAP:
681 		{
682 			STRACE(("ServerApp %s: received BBitmap delete request\n",
683 				Signature()));
684 
685 			// Delete a bitmap's allocated memory
686 
687 			// Attached Data:
688 			// 1) int32 token
689 			int32 token;
690 			link.Read<int32>(&token);
691 
692 			ServerBitmap *bitmap = FindBitmap(token);
693 			if (bitmap && fBitmapList.RemoveItem(bitmap)) {
694 				STRACE(("ServerApp %s: Deleting Bitmap %ld\n", Signature(),
695 					token));
696 
697 				gBitmapManager->DeleteBitmap(bitmap);
698 			}
699 			break;
700 		}
701 		case AS_GET_BITMAP_OVERLAY_RESTRICTIONS:
702 		{
703 			overlay_restrictions restrictions;
704 			status_t status = B_ERROR;
705 
706 			int32 token;
707 			if (link.Read<int32>(&token) != B_OK)
708 				break;
709 
710 			ServerBitmap *bitmap = FindBitmap(token);
711 			if (bitmap != NULL) {
712 				STRACE(("ServerApp %s: Get overlay restrictions for bitmap "
713 					"%ld\n", Signature(), token));
714 
715 				status = fDesktop->HWInterface()->GetOverlayRestrictions(
716 					bitmap->Overlay(), &restrictions);
717 			}
718 
719 			fLink.StartMessage(status);
720 			if (status == B_OK)
721 				fLink.Attach(&restrictions, sizeof(overlay_restrictions));
722 
723 			fLink.Flush();
724 			break;
725 		}
726 		case AS_GET_BITMAP_SUPPORT_FLAGS:
727 		{
728 			uint32 colorSpace;
729 			if (link.Read<uint32>(&colorSpace) != B_OK)
730 				break;
731 
732 			bool overlay = fDesktop->HWInterface()->CheckOverlayRestrictions(
733 				64, 64, (color_space)colorSpace);
734 			uint32 flags = overlay ? B_BITMAPS_SUPPORT_OVERLAY : 0;
735 
736 			fLink.StartMessage(B_OK);
737 			fLink.Attach<int32>(flags);
738 			fLink.Flush();
739 			break;
740 		}
741 
742 		case AS_CREATE_PICTURE:
743 		{
744 			// TODO: Maybe rename this to AS_UPLOAD_PICTURE ?
745 			STRACE(("ServerApp %s: Create Picture\n", Signature()));
746 			status_t status = B_ERROR;
747 			ServerPicture *picture = CreatePicture();
748 			if (picture != NULL) {
749 				int32 subPicturesCount = 0;
750 				link.Read<int32>(&subPicturesCount);
751 				for (int32 c = 0; c < subPicturesCount; c++) {
752 					int32 token = -1;
753 					link.Read<int32>(&token);
754 					if (ServerPicture *subPicture = FindPicture(token))
755 						picture->NestPicture(subPicture);
756 				}
757 				status = picture->ImportData(link);
758 			}
759 			if (status == B_OK) {
760 				fLink.StartMessage(B_OK);
761 				fLink.Attach<int32>(picture->Token());
762 			} else
763 				fLink.StartMessage(B_ERROR);
764 
765 			fLink.Flush();
766 			break;
767 		}
768 
769 		case AS_DELETE_PICTURE:
770 		{
771 			STRACE(("ServerApp %s: Delete Picture\n", Signature()));
772 			int32 token;
773 			if (link.Read<int32>(&token) == B_OK)
774 				DeletePicture(token);
775 
776 			break;
777 		}
778 
779 		case AS_CLONE_PICTURE:
780 		{
781 			STRACE(("ServerApp %s: Clone Picture\n", Signature()));
782 			int32 token;
783 			ServerPicture *original = NULL;
784 			if (link.Read<int32>(&token) == B_OK)
785 				original = FindPicture(token);
786 
787 			ServerPicture *cloned = NULL;
788 			if (original != NULL)
789 				cloned = CreatePicture(original);
790 
791 			if (cloned != NULL) {
792 				fLink.StartMessage(B_OK);
793 				fLink.Attach<int32>(cloned->Token());
794 			} else
795 				fLink.StartMessage(B_ERROR);
796 
797 			fLink.Flush();
798 			break;
799 		}
800 
801 		case AS_DOWNLOAD_PICTURE:
802 		{
803 			STRACE(("ServerApp %s: Download Picture\n", Signature()));
804 			int32 token;
805 			link.Read<int32>(&token);
806 			ServerPicture *picture = FindPicture(token);
807 			if (picture != NULL) {
808 				picture->ExportData(fLink);
809 					// ExportData() calls StartMessage() already
810 			} else
811 				fLink.StartMessage(B_ERROR);
812 
813 			fLink.Flush();
814 
815 			break;
816 		}
817 
818 		case AS_CURRENT_WORKSPACE:
819 			STRACE(("ServerApp %s: get current workspace\n", Signature()));
820 
821 			if (fDesktop->LockSingleWindow()) {
822 				fLink.StartMessage(B_OK);
823 				fLink.Attach<int32>(fDesktop->CurrentWorkspace());
824 				fDesktop->UnlockSingleWindow();
825 			} else
826 				fLink.StartMessage(B_ERROR);
827 
828 			fLink.Flush();
829 			break;
830 
831 		case AS_ACTIVATE_WORKSPACE:
832 		{
833 			STRACE(("ServerApp %s: activate workspace\n", Signature()));
834 
835 			// TODO: See above
836 			int32 index;
837 			link.Read<int32>(&index);
838 
839 			fDesktop->SetWorkspace(index);
840 			break;
841 		}
842 
843 		case AS_SET_WORKSPACE_LAYOUT:
844 		{
845 			int32 newColumns;
846 			int32 newRows;
847 			if (link.Read<int32>(&newColumns) == B_OK
848 				&& link.Read<int32>(&newRows) == B_OK)
849 				fDesktop->SetWorkspacesLayout(newColumns, newRows);
850 			break;
851 		}
852 
853 		case AS_GET_WORKSPACE_LAYOUT:
854 		{
855 			if (fDesktop->LockSingleWindow()) {
856 				DesktopSettings settings(fDesktop);
857 
858 				fLink.StartMessage(B_OK);
859 				fLink.Attach<int32>(settings.WorkspacesColumns());
860 				fLink.Attach<int32>(settings.WorkspacesRows());
861 
862 				fDesktop->UnlockSingleWindow();
863 			} else
864 				fLink.StartMessage(B_ERROR);
865 
866 			fLink.Flush();
867 			break;
868 		}
869 
870 		case AS_IDLE_TIME:
871 			STRACE(("ServerApp %s: idle time\n", Signature()));
872 
873 			fLink.StartMessage(B_OK);
874 			fLink.Attach<bigtime_t>(fDesktop->EventDispatcher().IdleTime());
875 			fLink.Flush();
876 			break;
877 
878 		case AS_SHOW_CURSOR:
879 		{
880 			STRACE(("ServerApp %s: Show Cursor\n", Signature()));
881 			fCursorHideLevel--;
882 			if (fCursorHideLevel < 0)
883 				fCursorHideLevel = 0;
884 			fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0);
885 			break;
886 		}
887 		case AS_HIDE_CURSOR:
888 		{
889 			STRACE(("ServerApp %s: Hide Cursor\n", Signature()));
890 			fCursorHideLevel++;
891 			fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0);
892 			break;
893 		}
894 		case AS_OBSCURE_CURSOR:
895 		{
896 			STRACE(("ServerApp %s: Obscure Cursor\n", Signature()));
897 			fDesktop->HWInterface()->ObscureCursor();
898 			break;
899 		}
900 		case AS_QUERY_CURSOR_HIDDEN:
901 		{
902 			STRACE(("ServerApp %s: Received IsCursorHidden request\n",
903 				Signature()));
904 
905 			fLink.StartMessage(fCursorHideLevel > 0 ? B_OK : B_ERROR);
906 			fLink.Flush();
907 			break;
908 		}
909 		case AS_SET_CURSOR:
910 		{
911 			STRACE(("ServerApp %s: SetCursor\n", Signature()));
912 
913 			// Attached data:
914 			// 1) bool flag to send a reply
915 			// 2) int32 token ID of the cursor to set
916 			// 3) port_id port to receive a reply. Only exists if the sync flag
917 			//    is true.
918 			bool sync;
919 			int32 token;
920 
921 			link.Read<bool>(&sync);
922 			if (link.Read<int32>(&token) != B_OK)
923 				break;
924 
925 			if (!fDesktop->GetCursorManager().Lock())
926 				break;
927 
928 			ServerCursor* oldCursor = fAppCursor;
929 			fAppCursor = fDesktop->GetCursorManager().FindCursor(token);
930 			if (fAppCursor != NULL)
931 				fAppCursor->Acquire();
932 
933 			if (_HasWindowUnderMouse())
934 				fDesktop->SetCursor(CurrentCursor());
935 
936 			if (oldCursor != NULL)
937 				oldCursor->Release();
938 
939 			fDesktop->GetCursorManager().Unlock();
940 
941 			if (sync) {
942 				// The application is expecting a reply
943 				fLink.StartMessage(B_OK);
944 				fLink.Flush();
945 			}
946 			break;
947 		}
948 		case AS_SET_VIEW_CURSOR:
949 		{
950 			STRACE(("ServerApp %s: AS_SET_VIEW_CURSOR:\n", Signature()));
951 
952 			ViewSetViewCursorInfo info;
953 			if (link.Read<ViewSetViewCursorInfo>(&info) != B_OK)
954 				break;
955 
956 			if (fDesktop->GetCursorManager().Lock()) {
957 				ServerCursor* cursor = fDesktop->GetCursorManager().FindCursor(
958 					info.cursorToken);
959 				// If we found a cursor, make sure it doesn't go away. If we
960 				// get a NULL cursor, it probably means we are supposed to use
961 				// the system default cursor.
962 				if (cursor != NULL)
963 					cursor->Acquire();
964 
965 				fDesktop->GetCursorManager().Unlock();
966 
967 				// We need to acquire the write lock here, since we cannot
968 				// afford that the window thread to which the view belongs
969 				// is running and messing with that same view.
970 				fDesktop->LockAllWindows();
971 
972 				// Find the corresponding view by the given token. It's ok
973 				// if this view does not exist anymore, since it may have
974 				// already be deleted in the window thread before this
975 				// message got here.
976 				View* view;
977 				if (fViewTokens.GetToken(info.viewToken, B_HANDLER_TOKEN,
978 					(void**)&view) == B_OK) {
979 					// Set the cursor on the view.
980 					view->SetCursor(cursor);
981 
982 					// The cursor might need to be updated now.
983 					Window* window = view->Window();
984 					if (window != NULL && window->IsFocus()) {
985 						if (fDesktop->ViewUnderMouse(window) == view->Token())
986 							SetCurrentCursor(cursor);
987 					}
988 				}
989 
990 				fDesktop->UnlockAllWindows();
991 
992 				// Release the temporary reference.
993 				if (cursor != NULL)
994 					cursor->Release();
995 			}
996 
997 			if (info.sync) {
998 				// sync the client (it can now delete the cursor)
999 				fLink.StartMessage(B_OK);
1000 				fLink.Flush();
1001 			}
1002 			break;
1003 		}
1004 		case AS_CREATE_CURSOR:
1005 		{
1006 			STRACE(("ServerApp %s: Create Cursor\n", Signature()));
1007 			// Attached data:
1008 			// 1) 68 bytes of fAppCursor data
1009 			// 2) port_id reply port
1010 
1011 			status_t status = B_ERROR;
1012 			uint8 cursorData[68];
1013 			ServerCursor* cursor = NULL;
1014 
1015 //			if (link.Read(cursorData, sizeof(cursorData)) >= B_OK) {
1016 //				cursor = new (nothrow) ServerCursor(cursorData);
1017 //				if (cursor == NULL)
1018 //					status = B_NO_MEMORY;
1019 //			}
1020 //
1021 //			if (cursor != NULL) {
1022 //				cursor->SetOwningTeam(fClientTeam);
1023 //				fDesktop->GetCursorManager().AddCursor(cursor);
1024 //
1025 //				// Synchronous message - BApplication is waiting on the cursor's ID
1026 //				fLink.StartMessage(B_OK);
1027 //				fLink.Attach<int32>(cursor->Token());
1028 //			} else
1029 //				fLink.StartMessage(status);
1030 
1031 			if (link.Read(cursorData, sizeof(cursorData)) >= B_OK) {
1032 				cursor = fDesktop->GetCursorManager().CreateCursor(fClientTeam,
1033 					cursorData);
1034 				if (cursor == NULL)
1035 					status = B_NO_MEMORY;
1036 			}
1037 
1038 			if (cursor != NULL) {
1039 				// Synchronous message - BApplication is waiting on the
1040 				// cursor's ID
1041 				fLink.StartMessage(B_OK);
1042 				fLink.Attach<int32>(cursor->Token());
1043 			} else
1044 				fLink.StartMessage(status);
1045 
1046 			fLink.Flush();
1047 			break;
1048 		}
1049 		case AS_REFERENCE_CURSOR:
1050 		{
1051 			STRACE(("ServerApp %s: Reference BCursor\n", Signature()));
1052 			// Attached data:
1053 			// 1) int32 token ID of the cursor to reference
1054 			int32 token;
1055 			if (link.Read<int32>(&token) != B_OK)
1056 				break;
1057 
1058 			if (!fDesktop->GetCursorManager().Lock())
1059 				break;
1060 
1061 			ServerCursor* cursor
1062 				= fDesktop->GetCursorManager().FindCursor(token);
1063 			if (cursor != NULL)
1064 				cursor->Acquire();
1065 
1066 			fDesktop->GetCursorManager().Unlock();
1067 
1068 			break;
1069 		}
1070 		case AS_DELETE_CURSOR:
1071 		{
1072 			STRACE(("ServerApp %s: Delete BCursor\n", Signature()));
1073 			// Attached data:
1074 			// 1) int32 token ID of the cursor to delete
1075 			int32 token;
1076 			if (link.Read<int32>(&token) != B_OK)
1077 				break;
1078 
1079 			if (!fDesktop->GetCursorManager().Lock())
1080 				break;
1081 
1082 			ServerCursor* cursor
1083 				= fDesktop->GetCursorManager().FindCursor(token);
1084 			if (cursor != NULL)
1085 				cursor->Release();
1086 
1087 			fDesktop->GetCursorManager().Unlock();
1088 
1089 			break;
1090 		}
1091 
1092 		case AS_GET_SCROLLBAR_INFO:
1093 		{
1094 			STRACE(("ServerApp %s: Get ScrollBar info\n", Signature()));
1095 
1096 			if (fDesktop->LockSingleWindow()) {
1097 				scroll_bar_info info;
1098 				DesktopSettings settings(fDesktop);
1099 				settings.GetScrollBarInfo(info);
1100 
1101 				fLink.StartMessage(B_OK);
1102 				fLink.Attach<scroll_bar_info>(info);
1103 				fDesktop->UnlockSingleWindow();
1104 			} else
1105 				fLink.StartMessage(B_ERROR);
1106 
1107 				fLink.Flush();
1108 			break;
1109 		}
1110 		case AS_SET_SCROLLBAR_INFO:
1111 		{
1112 			STRACE(("ServerApp %s: Set ScrollBar info\n", Signature()));
1113 			// Attached Data:
1114 			// 1) scroll_bar_info scroll bar info structure
1115 			scroll_bar_info info;
1116 			if (link.Read<scroll_bar_info>(&info) == B_OK) {
1117 				LockedDesktopSettings settings(fDesktop);
1118 				settings.SetScrollBarInfo(info);
1119 			}
1120 
1121 			fLink.StartMessage(B_OK);
1122 			fLink.Flush();
1123 			break;
1124 		}
1125 
1126 		case AS_GET_MENU_INFO:
1127 		{
1128 			STRACE(("ServerApp %s: Get menu info\n", Signature()));
1129 			if (fDesktop->LockSingleWindow()) {
1130 				menu_info info;
1131 				DesktopSettings settings(fDesktop);
1132 				settings.GetMenuInfo(info);
1133 
1134 				fLink.StartMessage(B_OK);
1135 				fLink.Attach<menu_info>(info);
1136 
1137 				fDesktop->UnlockSingleWindow();
1138 			} else
1139 				fLink.StartMessage(B_ERROR);
1140 
1141 			fLink.Flush();
1142 			break;
1143 		}
1144 		case AS_SET_MENU_INFO:
1145 		{
1146 			STRACE(("ServerApp %s: Set menu info\n", Signature()));
1147 			menu_info info;
1148 			if (link.Read<menu_info>(&info) == B_OK) {
1149 				LockedDesktopSettings settings(fDesktop);
1150 				settings.SetMenuInfo(info);
1151 					// TODO: SetMenuInfo() should do some validity check, so
1152 					//	that the answer we're giving can actually be useful
1153 			}
1154 
1155 			fLink.StartMessage(B_OK);
1156 			fLink.Flush();
1157 			break;
1158 		}
1159 
1160 		case AS_SET_MOUSE_MODE:
1161 		{
1162 			STRACE(("ServerApp %s: Set Focus Follows Mouse mode\n",
1163 				Signature()));
1164 			// Attached Data:
1165 			// 1) enum mode_mouse FFM mouse mode
1166 			mode_mouse mouseMode;
1167 			if (link.Read<mode_mouse>(&mouseMode) == B_OK) {
1168 				LockedDesktopSettings settings(fDesktop);
1169 				settings.SetMouseMode(mouseMode);
1170 			}
1171 			break;
1172 		}
1173 		case AS_GET_MOUSE_MODE:
1174 		{
1175 			STRACE(("ServerApp %s: Get Focus Follows Mouse mode\n",
1176 				Signature()));
1177 
1178 			if (fDesktop->LockSingleWindow()) {
1179 				DesktopSettings settings(fDesktop);
1180 
1181 				fLink.StartMessage(B_OK);
1182 				fLink.Attach<mode_mouse>(settings.MouseMode());
1183 
1184 				fDesktop->UnlockSingleWindow();
1185 			} else
1186 				fLink.StartMessage(B_ERROR);
1187 
1188 			fLink.Flush();
1189 			break;
1190 		}
1191 
1192 		case AS_GET_SHOW_ALL_DRAGGERS:
1193 		{
1194 			STRACE(("ServerApp %s: Get Show All Draggers\n", Signature()));
1195 
1196 			if (fDesktop->LockSingleWindow()) {
1197 				DesktopSettings settings(fDesktop);
1198 
1199 				fLink.StartMessage(B_OK);
1200 				fLink.Attach<bool>(settings.ShowAllDraggers());
1201 
1202 				fDesktop->UnlockSingleWindow();
1203 			} else
1204 				fLink.StartMessage(B_ERROR);
1205 
1206 			fLink.Flush();
1207 			break;
1208 		}
1209 
1210 		case AS_SET_SHOW_ALL_DRAGGERS:
1211 		{
1212 			STRACE(("ServerApp %s: Set Show All Draggers\n", Signature()));
1213 
1214 			bool changed = false;
1215 			bool show;
1216 			if (link.Read<bool>(&show) == B_OK) {
1217 				LockedDesktopSettings settings(fDesktop);
1218 				if (show != settings.ShowAllDraggers()) {
1219 					settings.SetShowAllDraggers(show);
1220 					changed = true;
1221 				}
1222 			}
1223 
1224 			if (changed)
1225 				fDesktop->BroadcastToAllApps(kMsgUpdateShowAllDraggers);
1226 			break;
1227 		}
1228 
1229 		case kMsgUpdateShowAllDraggers:
1230 		{
1231 			bool show = false;
1232 			if (fDesktop->LockSingleWindow()) {
1233 				DesktopSettings settings(fDesktop);
1234 				show = settings.ShowAllDraggers();
1235 				fDesktop->UnlockSingleWindow();
1236 			}
1237 			BMessage update(_SHOW_DRAG_HANDLES_);
1238 			update.AddBool("show", show);
1239 
1240 			SendMessageToClient(&update);
1241 			break;
1242 		}
1243 
1244 		/* font messages */
1245 
1246 		case AS_SET_SYSTEM_FONT:
1247 		{
1248 			FTRACE(("ServerApp %s: AS_SET_SYSTEM_FONT\n", Signature()));
1249 			// gets:
1250 			//	1) string - font type ("plain", ...)
1251 			//	2) string - family
1252 			//	3) string - style
1253 			//	4) float - size
1254 
1255 			char type[B_OS_NAME_LENGTH];
1256 			font_family familyName;
1257 			font_style styleName;
1258 			float size;
1259 
1260 			if (link.ReadString(type, sizeof(type)) == B_OK
1261 				&& link.ReadString(familyName, sizeof(familyName)) == B_OK
1262 				&& link.ReadString(styleName, sizeof(styleName)) == B_OK
1263 				&& link.Read<float>(&size) == B_OK) {
1264 				gFontManager->Lock();
1265 
1266 				FontStyle* style
1267 					= gFontManager->GetStyle(familyName, styleName);
1268 				if (style != NULL) {
1269 					ServerFont font(*style, size);
1270 					gFontManager->Unlock();
1271 						// We must not have locked the font manager when
1272 						// locking the desktop (through LockedDesktopSettings
1273 						// below)
1274 
1275 					LockedDesktopSettings settings(fDesktop);
1276 
1277 					// TODO: Should we also update our internal copies now?
1278 					if (!strcmp(type, "plain"))
1279 						settings.SetDefaultPlainFont(font);
1280 					else if (!strcmp(type, "bold"))
1281 						settings.SetDefaultBoldFont(font);
1282 					else if (!strcmp(type, "fixed"))
1283 						settings.SetDefaultFixedFont(font);
1284 				} else
1285 					gFontManager->Unlock();
1286 			}
1287 			break;
1288 		}
1289 		case AS_GET_SYSTEM_DEFAULT_FONT:
1290 		{
1291 			// input:
1292 			//	1) string - font type ("plain", ...)
1293 
1294 			ServerFont font;
1295 
1296 			char type[B_OS_NAME_LENGTH];
1297 			status_t status = link.ReadString(type, sizeof(type));
1298 			if (status == B_OK) {
1299 				if (!strcmp(type, "plain")) {
1300 					font = *gFontManager->DefaultPlainFont();
1301 				} else if (!strcmp(type, "bold")) {
1302 					font = *gFontManager->DefaultBoldFont();
1303 				} else if (!strcmp(type, "fixed")) {
1304 					font = *gFontManager->DefaultFixedFont();
1305 				} else
1306 					status = B_BAD_VALUE;
1307 			}
1308 
1309 			if (status == B_OK) {
1310 				// returns:
1311 				//	1) string - family
1312 				//	2) string - style
1313 				//	3) float - size
1314 
1315 				fLink.StartMessage(B_OK);
1316 				fLink.AttachString(font.Family());
1317 				fLink.AttachString(font.Style());
1318 				fLink.Attach<float>(font.Size());
1319 			} else
1320 				fLink.StartMessage(status);
1321 
1322 			fLink.Flush();
1323 			break;
1324 		}
1325 		case AS_GET_SYSTEM_FONTS:
1326 		{
1327 			FTRACE(("ServerApp %s: AS_GET_SYSTEM_FONTS\n", Signature()));
1328 			// Returns:
1329 			// 1) uint16 - family ID
1330 			// 2) uint16 - style ID
1331 			// 3) float - size in points
1332 			// 4) uint16 - face flags
1333 			// 5) uint32 - font flags
1334 
1335 			if (!fDesktop->LockSingleWindow()) {
1336 				fLink.StartMessage(B_OK);
1337 				fLink.Flush();
1338 				break;
1339 			}
1340 
1341 			// The client is requesting the system fonts, this
1342 			// could happend either at application start up, or
1343 			// because the client is resyncing with the global
1344 			// fonts. So we record the current system wide fonts
1345 			// into our own copies at this point.
1346 			DesktopSettings settings(fDesktop);
1347 
1348 			settings.GetDefaultPlainFont(fPlainFont);
1349 			settings.GetDefaultBoldFont(fBoldFont);
1350 			settings.GetDefaultFixedFont(fFixedFont);
1351 
1352 			fLink.StartMessage(B_OK);
1353 
1354 			for (int32 i = 0; i < 3; i++) {
1355 				ServerFont* font = NULL;
1356 				switch (i) {
1357 					case 0:
1358 						font = &fPlainFont;
1359 						fLink.AttachString("plain");
1360 						break;
1361 					case 1:
1362 						font = &fBoldFont;
1363 						fLink.AttachString("bold");
1364 						break;
1365 					case 2:
1366 						font = &fFixedFont;
1367 						fLink.AttachString("fixed");
1368 						break;
1369 				}
1370 
1371 				fLink.Attach<uint16>(font->FamilyID());
1372 				fLink.Attach<uint16>(font->StyleID());
1373 				fLink.Attach<float>(font->Size());
1374 				fLink.Attach<uint16>(font->Face());
1375 				fLink.Attach<uint32>(font->Flags());
1376 			}
1377 
1378 			fDesktop->UnlockSingleWindow();
1379 			fLink.Flush();
1380 			break;
1381 		}
1382 		case AS_GET_FONT_LIST_REVISION:
1383 		{
1384 			STRACE(("ServerApp %s: AS_GET_FONT_LIST_REVISION\n", Signature()));
1385 
1386 			fLink.StartMessage(B_OK);
1387 			fLink.Attach<int32>(
1388 				gFontManager->CheckRevision(fDesktop->UserID()));
1389 			fLink.Flush();
1390 			break;
1391 		}
1392 		case AS_GET_FAMILY_AND_STYLES:
1393 		{
1394 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLES\n", Signature()));
1395 			// Attached Data:
1396 			// 1) int32 the index of the font family to get
1397 
1398 			// Returns:
1399 			// 1) string - name of family
1400 			// 2) uint32 - flags of font family (B_IS_FIXED || B_HAS_TUNED_FONT)
1401 			// 3) count of styles in that family
1402 			// For each style:
1403 			//		1) string - name of style
1404 			//		2) uint16 - face of style
1405 			//		3) uint32 - flags of style
1406 
1407 			int32 index;
1408 			link.Read<int32>(&index);
1409 
1410 			gFontManager->Lock();
1411 
1412 			FontFamily* family = gFontManager->FamilyAt(index);
1413 			if (family) {
1414 				fLink.StartMessage(B_OK);
1415 				fLink.AttachString(family->Name());
1416 				fLink.Attach<uint32>(family->Flags());
1417 
1418 				int32 count = family->CountStyles();
1419 				fLink.Attach<int32>(count);
1420 
1421 				for (int32 i = 0; i < count; i++) {
1422 					FontStyle* style = family->StyleAt(i);
1423 
1424 					fLink.AttachString(style->Name());
1425 					fLink.Attach<uint16>(style->Face());
1426 					fLink.Attach<uint32>(style->Flags());
1427 				}
1428 			} else
1429 				fLink.StartMessage(B_BAD_VALUE);
1430 
1431 			gFontManager->Unlock();
1432 			fLink.Flush();
1433 			break;
1434 		}
1435 		case AS_GET_FAMILY_AND_STYLE:
1436 		{
1437 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE\n", Signature()));
1438 			// Attached Data:
1439 			// 1) uint16 - family ID
1440 			// 2) uint16 - style ID
1441 
1442 			// Returns:
1443 			// 1) font_family The name of the font family
1444 			// 2) font_style - name of the style
1445 			uint16 familyID, styleID;
1446 			link.Read<uint16>(&familyID);
1447 			link.Read<uint16>(&styleID);
1448 
1449 			gFontManager->Lock();
1450 
1451 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1452 			if (fontStyle != NULL) {
1453 				fLink.StartMessage(B_OK);
1454 				fLink.AttachString(fontStyle->Family()->Name());
1455 				fLink.AttachString(fontStyle->Name());
1456 			} else
1457 				fLink.StartMessage(B_BAD_VALUE);
1458 
1459 			fLink.Flush();
1460 			gFontManager->Unlock();
1461 			break;
1462 		}
1463 		case AS_GET_FAMILY_AND_STYLE_IDS:
1464 		{
1465 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE_IDS\n",
1466 				Signature()));
1467 
1468 			// Attached Data:
1469 			// 1) font_family - name of font family to use
1470 			// 2) font_style - name of style in family
1471 			// 3) family ID - only used if 1) is empty
1472 			// 4) style ID - only used if 2) is empty
1473 			// 5) face - the font's current face
1474 
1475 			// Returns:
1476 			// 1) uint16 - family ID
1477 			// 2) uint16 - style ID
1478 			// 3) uint16 - face
1479 
1480 			font_family family;
1481 			font_style style;
1482 			uint16 familyID, styleID;
1483 			uint16 face;
1484 			if (link.ReadString(family, sizeof(font_family)) == B_OK
1485 				&& link.ReadString(style, sizeof(font_style)) == B_OK
1486 				&& link.Read<uint16>(&familyID) == B_OK
1487 				&& link.Read<uint16>(&styleID) == B_OK
1488 				&& link.Read<uint16>(&face) == B_OK) {
1489 				// get the font and return IDs and face
1490 				gFontManager->Lock();
1491 
1492 				FontStyle *fontStyle = gFontManager->GetStyle(family, style,
1493 					familyID, styleID, face);
1494 
1495 				if (fontStyle != NULL) {
1496 					fLink.StartMessage(B_OK);
1497 					fLink.Attach<uint16>(fontStyle->Family()->ID());
1498 					fLink.Attach<uint16>(fontStyle->ID());
1499 
1500 					// we try to keep the font face close to what we got
1501 					face = fontStyle->PreservedFace(face);
1502 
1503 					fLink.Attach<uint16>(face);
1504 				} else
1505 					fLink.StartMessage(B_NAME_NOT_FOUND);
1506 
1507 				gFontManager->Unlock();
1508 			} else
1509 				fLink.StartMessage(B_BAD_VALUE);
1510 
1511 			fLink.Flush();
1512 			break;
1513 		}
1514 		case AS_GET_FONT_FILE_FORMAT:
1515 		{
1516 			FTRACE(("ServerApp %s: AS_GET_FONT_FILE_FORMAT\n", Signature()));
1517 			// Attached Data:
1518 			// 1) uint16 - family ID
1519 			// 2) uint16 - style ID
1520 
1521 			// Returns:
1522 			// 1) uint16 font_file_format of font
1523 
1524 			int32 familyID, styleID;
1525 			link.Read<int32>(&familyID);
1526 			link.Read<int32>(&styleID);
1527 
1528 			gFontManager->Lock();
1529 
1530 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1531 			if (fontStyle) {
1532 				fLink.StartMessage(B_OK);
1533 				fLink.Attach<uint16>((uint16)fontStyle->FileFormat());
1534 			} else
1535 				fLink.StartMessage(B_BAD_VALUE);
1536 
1537 			gFontManager->Unlock();
1538 			fLink.Flush();
1539 			break;
1540 		}
1541 		case AS_GET_STRING_WIDTHS:
1542 		{
1543 			FTRACE(("ServerApp %s: AS_GET_STRING_WIDTHS\n", Signature()));
1544 			// Attached Data:
1545 			// 1) uint16 ID of family
1546 			// 2) uint16 ID of style
1547 			// 3) float point size of font
1548 			// 4) uint8 spacing to use
1549 			// 5) int32 numStrings
1550 			// 6) int32 string length to measure (numStrings times)
1551 			// 7) string String to measure (numStrings times)
1552 
1553 			// Returns:
1554 			// 1) float - width of the string in pixels (numStrings times)
1555 
1556 			uint16 family, style;
1557 			float size;
1558 			uint8 spacing;
1559 
1560 			link.Read<uint16>(&family);
1561 			link.Read<uint16>(&style);
1562 			link.Read<float>(&size);
1563 			link.Read<uint8>(&spacing);
1564 			int32 numStrings;
1565 			if (link.Read<int32>(&numStrings) != B_OK) {
1566 				// this results in a B_BAD_VALUE return
1567 				numStrings = 0;
1568 				size = 0.0f;
1569 			}
1570 
1571 			// TODO: don't use the stack for this - numStrings could be large
1572 			float widthArray[numStrings];
1573 			int32 lengthArray[numStrings];
1574 			char *stringArray[numStrings];
1575 			for (int32 i = 0; i < numStrings; i++) {
1576 				// This version of ReadString allocates the strings, we free
1577 				// them below
1578 				link.ReadString(&stringArray[i], (size_t *)&lengthArray[i]);
1579 			}
1580 
1581 			ServerFont font;
1582 
1583 			if (font.SetFamilyAndStyle(family, style) == B_OK && size > 0) {
1584 				font.SetSize(size);
1585 				font.SetSpacing(spacing);
1586 
1587 				for (int32 i = 0; i < numStrings; i++) {
1588 					if (!stringArray[i] || lengthArray[i] <= 0)
1589 						widthArray[i] = 0.0;
1590 					else {
1591 						widthArray[i] = font.StringWidth(stringArray[i],
1592 							lengthArray[i]);
1593 					}
1594 				}
1595 
1596 				fLink.StartMessage(B_OK);
1597 				fLink.Attach(widthArray, sizeof(widthArray));
1598 			} else
1599 				fLink.StartMessage(B_BAD_VALUE);
1600 
1601 			fLink.Flush();
1602 
1603 			for (int32 i = 0; i < numStrings; i++) {
1604 				free(stringArray[i]);
1605 			}
1606 			break;
1607 		}
1608 		case AS_GET_FONT_BOUNDING_BOX:
1609 		{
1610 			FTRACE(("ServerApp %s: AS_GET_BOUNDING_BOX unimplemented\n",
1611 				Signature()));
1612 			// Attached Data:
1613 			// 1) uint16 - family ID
1614 			// 2) uint16 - style ID
1615 
1616 			// Returns:
1617 			// 1) BRect - box holding entire font
1618 
1619 			// ToDo: implement me!
1620 			fLink.StartMessage(B_ERROR);
1621 			fLink.Flush();
1622 			break;
1623 		}
1624 		case AS_GET_TUNED_COUNT:
1625 		{
1626 			FTRACE(("ServerApp %s: AS_GET_TUNED_COUNT\n", Signature()));
1627 			// Attached Data:
1628 			// 1) uint16 - family ID
1629 			// 2) uint16 - style ID
1630 
1631 			// Returns:
1632 			// 1) int32 - number of font strikes available
1633 			uint16 familyID, styleID;
1634 			link.Read<uint16>(&familyID);
1635 			link.Read<uint16>(&styleID);
1636 
1637 			gFontManager->Lock();
1638 
1639 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1640 			if (fontStyle != NULL) {
1641 				fLink.StartMessage(B_OK);
1642 				fLink.Attach<int32>(fontStyle->TunedCount());
1643 			} else
1644 				fLink.StartMessage(B_BAD_VALUE);
1645 
1646 			gFontManager->Unlock();
1647 			fLink.Flush();
1648 			break;
1649 		}
1650 		case AS_GET_TUNED_INFO:
1651 		{
1652 			FTRACE(("ServerApp %s: AS_GET_TUNED_INFO unimplmemented\n",
1653 				Signature()));
1654 			// Attached Data:
1655 			// 1) uint16 - family ID
1656 			// 2) uint16 - style ID
1657 			// 3) uint32 - index of the particular font strike
1658 
1659 			// Returns:
1660 			// 1) tuned_font_info - info on the strike specified
1661 			// ToDo: implement me!
1662 			fLink.StartMessage(B_ERROR);
1663 			fLink.Flush();
1664 			break;
1665 		}
1666 		case AS_GET_EXTRA_FONT_FLAGS:
1667 		{
1668 			FTRACE(("ServerApp %s: AS_GET_EXTRA_FONT_FLAGS\n",
1669 				Signature()));
1670 			// Attached Data:
1671 			// 1) uint16 - family ID
1672 			// 2) uint16 - style ID
1673 
1674 			// Returns:
1675 			// 1) uint32 - extra font flags
1676 			uint16 familyID, styleID;
1677 			link.Read<uint16>(&familyID);
1678 			link.Read<uint16>(&styleID);
1679 
1680 			gFontManager->Lock();
1681 
1682 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1683 			if (fontStyle != NULL) {
1684 				fLink.StartMessage(B_OK);
1685 				fLink.Attach<uint32>(fontStyle->Flags());
1686 			} else
1687 				fLink.StartMessage(B_BAD_VALUE);
1688 
1689 			gFontManager->Unlock();
1690 			fLink.Flush();
1691 			break;
1692 		}
1693 		case AS_GET_FONT_HEIGHT:
1694 		{
1695 			FTRACE(("ServerApp %s: AS_GET_FONT_HEIGHT\n", Signature()));
1696 			// Attached Data:
1697 			// 1) uint16 family ID
1698 			// 2) uint16 style ID
1699 			// 3) float size
1700 			uint16 familyID, styleID;
1701 			float size;
1702 			link.Read<uint16>(&familyID);
1703 			link.Read<uint16>(&styleID);
1704 			link.Read<float>(&size);
1705 
1706 			gFontManager->Lock();
1707 
1708 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1709 			if (fontStyle != NULL) {
1710 				font_height height;
1711 				fontStyle->GetHeight(size, height);
1712 
1713 				fLink.StartMessage(B_OK);
1714 				fLink.Attach<font_height>(height);
1715 			} else
1716 				fLink.StartMessage(B_BAD_VALUE);
1717 
1718 			gFontManager->Unlock();
1719 			fLink.Flush();
1720 			break;
1721 		}
1722 		case AS_GET_GLYPH_SHAPES:
1723 		{
1724 			FTRACE(("ServerApp %s: AS_GET_GLYPH_SHAPES\n", Signature()));
1725 			// Attached Data:
1726 			// 1) uint16 - family ID
1727 			// 2) uint16 - style ID
1728 			// 3) float - point size
1729 			// 4) float - shear
1730 			// 5) float - rotation
1731 			// 6) float - false bold width
1732 			// 6) uint32 - flags
1733 			// 7) int32 - numChars
1734 			// 8) int32 - numBytes
1735 			// 8) char - chars (bytesInBuffer times)
1736 
1737 			// Returns:
1738 			// 1) BShape - glyph shape
1739 			// numChars times
1740 
1741 			uint16 familyID, styleID;
1742 			uint32 flags;
1743 			float size, shear, rotation, falseBoldWidth;
1744 
1745 			link.Read<uint16>(&familyID);
1746 			link.Read<uint16>(&styleID);
1747 			link.Read<float>(&size);
1748 			link.Read<float>(&shear);
1749 			link.Read<float>(&rotation);
1750 			link.Read<float>(&falseBoldWidth);
1751 			link.Read<uint32>(&flags);
1752 
1753 			int32 numChars, numBytes;
1754 			link.Read<int32>(&numChars);
1755 			link.Read<int32>(&numBytes);
1756 
1757 			// TODO: proper error checking
1758 			char* charArray = new (nothrow) char[numBytes];
1759 			link.Read(charArray, numBytes);
1760 
1761 			ServerFont font;
1762 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1763 			if (status == B_OK) {
1764 				font.SetSize(size);
1765 				font.SetShear(shear);
1766 				font.SetRotation(rotation);
1767 				font.SetFalseBoldWidth(falseBoldWidth);
1768 				font.SetFlags(flags);
1769 
1770 				// TODO: proper error checking
1771 				BShape** shapes = new (nothrow) BShape*[numChars];
1772 				status = font.GetGlyphShapes(charArray, numChars, shapes);
1773 				if (status == B_OK) {
1774 					fLink.StartMessage(B_OK);
1775 					for (int32 i = 0; i < numChars; i++) {
1776 						fLink.AttachShape(*shapes[i]);
1777 						delete shapes[i];
1778 					}
1779 				} else
1780 					fLink.StartMessage(status);
1781 
1782 				delete[] shapes;
1783 			} else
1784 				fLink.StartMessage(status);
1785 
1786 			delete[] charArray;
1787 			fLink.Flush();
1788 			break;
1789 		}
1790 		case AS_GET_HAS_GLYPHS:
1791 		{
1792 			FTRACE(("ServerApp %s: AS_GET_HAS_GLYPHS\n", Signature()));
1793 			// Attached Data:
1794 			// 1) uint16 - family ID
1795 			// 2) uint16 - style ID
1796 			// 3) int32 - numChars
1797 			// 4) int32 - numBytes
1798 			// 5) char - the char buffer with size numBytes
1799 
1800 			uint16 familyID, styleID;
1801 			link.Read<uint16>(&familyID);
1802 			link.Read<uint16>(&styleID);
1803 
1804 			int32 numChars, numBytes;
1805 			link.Read<int32>(&numChars);
1806 			link.Read<int32>(&numBytes);
1807 			// TODO: proper error checking
1808 			char* charArray = new (nothrow) char[numBytes];
1809 			link.Read(charArray, numBytes);
1810 
1811 			ServerFont font;
1812 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1813 			if (status == B_OK) {
1814 				bool hasArray[numChars];
1815 				status = font.GetHasGlyphs(charArray, numBytes, hasArray);
1816 				if (status == B_OK) {
1817 					fLink.StartMessage(B_OK);
1818 					fLink.Attach(hasArray, sizeof(hasArray));
1819 				} else
1820 					fLink.StartMessage(status);
1821 			} else
1822 				fLink.StartMessage(status);
1823 
1824 			delete[] charArray;
1825 			fLink.Flush();
1826 			break;
1827 		}
1828 		case AS_GET_EDGES:
1829 		{
1830 			FTRACE(("ServerApp %s: AS_GET_EDGES\n", Signature()));
1831 			// Attached Data:
1832 			// 1) uint16 - family ID
1833 			// 2) uint16 - style ID
1834 			// 3) int32 - numChars
1835 			// 4) int32 - numBytes
1836 			// 5) char - the char buffer with size numBytes
1837 
1838 			uint16 familyID, styleID;
1839 			link.Read<uint16>(&familyID);
1840 			link.Read<uint16>(&styleID);
1841 
1842 			int32 numChars;
1843 			link.Read<int32>(&numChars);
1844 
1845 			uint32 numBytes;
1846 			link.Read<uint32>(&numBytes);
1847 			// TODO: proper error checking
1848 			char* charArray = new (nothrow) char[numBytes];
1849 			link.Read(charArray, numBytes);
1850 
1851 			ServerFont font;
1852 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1853 			if (status == B_OK) {
1854 				edge_info edgeArray[numChars];
1855 				status = font.GetEdges(charArray, numBytes, edgeArray);
1856 				if (status == B_OK) {
1857 					fLink.StartMessage(B_OK);
1858 					fLink.Attach(edgeArray, sizeof(edgeArray));
1859 				} else
1860 					fLink.StartMessage(status);
1861 			} else
1862 				fLink.StartMessage(status);
1863 
1864 			delete[] charArray;
1865 			fLink.Flush();
1866 			break;
1867 		}
1868 		case AS_GET_ESCAPEMENTS:
1869 		{
1870 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS\n", Signature()));
1871 			// Attached Data:
1872 			// 1) uint16 - family ID
1873 			// 2) uint16 - style ID
1874 			// 3) float - point size
1875 			// 4) uint8 - spacing
1876 			// 5) float - rotation
1877 			// 6) uint32 - flags
1878 			// 7) int32 - numChars
1879 			// 8) char - char     -\       both
1880 			// 9) BPoint - offset -/ (numChars times)
1881 
1882 			// Returns:
1883 			// 1) BPoint - escapement
1884 			// numChars times
1885 
1886 			uint16 familyID, styleID;
1887 			uint32 flags;
1888 			float size, rotation;
1889 			uint8 spacing;
1890 
1891 			link.Read<uint16>(&familyID);
1892 			link.Read<uint16>(&styleID);
1893 			link.Read<float>(&size);
1894 			link.Read<uint8>(&spacing);
1895 			link.Read<float>(&rotation);
1896 			link.Read<uint32>(&flags);
1897 
1898 			escapement_delta delta;
1899 			link.Read<float>(&delta.nonspace);
1900 			link.Read<float>(&delta.space);
1901 
1902 			bool wantsOffsets;
1903 			link.Read<bool>(&wantsOffsets);
1904 
1905 			int32 numChars;
1906 			link.Read<int32>(&numChars);
1907 
1908 			uint32 numBytes;
1909 			link.Read<uint32>(&numBytes);
1910 
1911 			char* charArray = new(std::nothrow) char[numBytes];
1912 			BPoint* escapements = new(std::nothrow) BPoint[numChars];
1913 			BPoint* offsets = NULL;
1914 			if (wantsOffsets)
1915 				offsets = new(std::nothrow) BPoint[numChars];
1916 
1917 			if (charArray == NULL || escapements == NULL
1918 				|| (offsets == NULL && wantsOffsets)) {
1919 				delete[] charArray;
1920 				delete[] escapements;
1921 				delete[] offsets;
1922 
1923 				fLink.StartMessage(B_NO_MEMORY);
1924 				fLink.Flush();
1925 				break;
1926 			}
1927 
1928 			link.Read(charArray, numBytes);
1929 
1930 			ServerFont font;
1931 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1932 			if (status == B_OK) {
1933 				font.SetSize(size);
1934 				font.SetSpacing(spacing);
1935 				font.SetRotation(rotation);
1936 				font.SetFlags(flags);
1937 
1938 				status = font.GetEscapements(charArray, numBytes, numChars,
1939 					delta, escapements, offsets);
1940 
1941 				if (status == B_OK) {
1942 					fLink.StartMessage(B_OK);
1943 					for (int32 i = 0; i < numChars; i++)
1944 						fLink.Attach<BPoint>(escapements[i]);
1945 
1946 					if (offsets) {
1947 						for (int32 i = 0; i < numChars; i++)
1948 							fLink.Attach<BPoint>(offsets[i]);
1949 					}
1950 				} else
1951 					fLink.StartMessage(status);
1952 
1953 				delete[] escapements;
1954 				delete[] offsets;
1955 			} else
1956 				fLink.StartMessage(status);
1957 
1958 			delete[] charArray;
1959 			fLink.Flush();
1960 			break;
1961 		}
1962 		case AS_GET_ESCAPEMENTS_AS_FLOATS:
1963 		{
1964 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS_AS_FLOATS\n", Signature()));
1965 			// Attached Data:
1966 			// 1) uint16 - family ID
1967 			// 2) uint16 - style ID
1968 			// 3) float - point size
1969 			// 4) uint8 - spacing
1970 			// 5) float - rotation
1971 			// 6) uint32 - flags
1972 
1973 			// 7) float - additional "nonspace" delta
1974 			// 8) float - additional "space" delta
1975 
1976 			// 9) int32 - numChars
1977 			// 10) int32 - numBytes
1978 			// 11) char - the char buffer with size numBytes
1979 
1980 			// Returns:
1981 			// 1) float - escapement buffer with numChar entries
1982 
1983 			uint16 familyID, styleID;
1984 			uint32 flags;
1985 			float size, rotation;
1986 			uint8 spacing;
1987 
1988 			link.Read<uint16>(&familyID);
1989 			link.Read<uint16>(&styleID);
1990 			link.Read<float>(&size);
1991 			link.Read<uint8>(&spacing);
1992 			link.Read<float>(&rotation);
1993 			link.Read<uint32>(&flags);
1994 
1995 			escapement_delta delta;
1996 			link.Read<float>(&delta.nonspace);
1997 			link.Read<float>(&delta.space);
1998 
1999 			int32 numChars;
2000 			link.Read<int32>(&numChars);
2001 
2002 			uint32 numBytes;
2003 			link.Read<uint32>(&numBytes);
2004 
2005 			char* charArray = new (nothrow) char[numBytes];
2006 			float* escapements = new (nothrow) float[numChars];
2007 			if (charArray == NULL || escapements == NULL) {
2008 				delete[] charArray;
2009 				delete[] escapements;
2010 				fLink.StartMessage(B_NO_MEMORY);
2011 				fLink.Flush();
2012 				break;
2013 			}
2014 
2015 			link.Read(charArray, numBytes);
2016 
2017 			// figure out escapements
2018 
2019 			ServerFont font;
2020 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2021 			if (status == B_OK) {
2022 				font.SetSize(size);
2023 				font.SetSpacing(spacing);
2024 				font.SetRotation(rotation);
2025 				font.SetFlags(flags);
2026 
2027 				status = font.GetEscapements(charArray, numBytes, numChars,
2028 					delta, escapements);
2029 
2030 				if (status == B_OK) {
2031 					fLink.StartMessage(B_OK);
2032 					fLink.Attach(escapements, numChars * sizeof(float));
2033 				}
2034 			}
2035 
2036 			delete[] charArray;
2037 			delete[] escapements;
2038 
2039 			if (status != B_OK)
2040 				fLink.StartMessage(status);
2041 
2042 			fLink.Flush();
2043 			break;
2044 		}
2045 		case AS_GET_BOUNDINGBOXES_CHARS:
2046 		case AS_GET_BOUNDINGBOXES_STRING:
2047 		{
2048 			FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_CHARS\n", Signature()));
2049 			// Attached Data:
2050 			// 1) uint16 - family ID
2051 			// 2) uint16 - style ID
2052 			// 3) float - point size
2053 			// 4) float - rotation
2054 			// 5) float - shear
2055 			// 6) float - false bold width
2056 			// 7) uint8 - spacing
2057 			// 8) uint32 - flags
2058 
2059 			// 9) font_metric_mode - mode
2060 			// 10) bool - string escapement
2061 
2062 			// 11) escapement_delta - additional delta
2063 
2064 			// 12) int32 - numChars
2065 			// 13) int32 - numBytes
2066 			// 14) char - the char buffer with size numBytes
2067 
2068 			// Returns:
2069 			// 1) BRect - rects with numChar entries
2070 
2071 			uint16 familyID, styleID;
2072 			uint32 flags;
2073 			float size, rotation, shear, falseBoldWidth;
2074 			uint8 spacing;
2075 			font_metric_mode mode;
2076 			bool stringEscapement;
2077 
2078 			link.Read<uint16>(&familyID);
2079 			link.Read<uint16>(&styleID);
2080 			link.Read<float>(&size);
2081 			link.Read<float>(&rotation);
2082 			link.Read<float>(&shear);
2083 			link.Read<float>(&falseBoldWidth);
2084 			link.Read<uint8>(&spacing);
2085 			link.Read<uint32>(&flags);
2086 			link.Read<font_metric_mode>(&mode);
2087 			link.Read<bool>(&stringEscapement);
2088 
2089 			escapement_delta delta;
2090 			link.Read<escapement_delta>(&delta);
2091 
2092 			int32 numChars;
2093 			link.Read<int32>(&numChars);
2094 
2095 			uint32 numBytes;
2096 			link.Read<uint32>(&numBytes);
2097 
2098 			bool success = false;
2099 
2100 			char* charArray = new(std::nothrow) char[numBytes];
2101 			BRect* rectArray = new(std::nothrow) BRect[numChars];
2102 			if (charArray != NULL && rectArray != NULL) {
2103 				link.Read(charArray, numBytes);
2104 
2105 				// figure out escapements
2106 
2107 				ServerFont font;
2108 				if (font.SetFamilyAndStyle(familyID, styleID) == B_OK) {
2109 					font.SetSize(size);
2110 					font.SetRotation(rotation);
2111 					font.SetShear(shear);
2112 					font.SetFalseBoldWidth(falseBoldWidth);
2113 					font.SetSpacing(spacing);
2114 					font.SetFlags(flags);
2115 
2116 					// TODO: implement for real
2117 					if (font.GetBoundingBoxes(charArray, numBytes,
2118 							rectArray, stringEscapement, mode, delta,
2119 							code == AS_GET_BOUNDINGBOXES_STRING) == B_OK) {
2120 						fLink.StartMessage(B_OK);
2121 						fLink.Attach(rectArray, sizeof(rectArray));
2122 						success = true;
2123 					}
2124 				}
2125 			}
2126 
2127 			if (!success)
2128 				fLink.StartMessage(B_ERROR);
2129 
2130 			fLink.Flush();
2131 
2132 			delete[] charArray;
2133 			delete[] rectArray;
2134 			break;
2135 		}
2136 		case AS_GET_BOUNDINGBOXES_STRINGS:
2137 		{
2138 			FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_STRINGS\n",
2139 				Signature()));
2140 
2141 			// Attached Data:
2142 			// 1) uint16 - family ID
2143 			// 2) uint16 - style ID
2144 			// 3) float - point size
2145 			// 4) float - rotation
2146 			// 5) float - shear
2147 			// 6) float - false bold width
2148 			// 7) uint8 - spacing
2149 			// 8) uint32 - flags
2150 
2151 			// 9) font_metric_mode - mode
2152 			// 10) int32 numStrings
2153 
2154 			// 11) escapement_delta - additional delta (numStrings times)
2155 			// 12) int32 string length to measure (numStrings times)
2156 			// 13) string - string (numStrings times)
2157 
2158 			// Returns:
2159 			// 1) BRect - rects with numStrings entries
2160 
2161 			uint16 familyID, styleID;
2162 			uint32 flags;
2163 			float ptsize, rotation, shear, falseBoldWidth;
2164 			uint8 spacing;
2165 			font_metric_mode mode;
2166 
2167 			link.Read<uint16>(&familyID);
2168 			link.Read<uint16>(&styleID);
2169 			link.Read<float>(&ptsize);
2170 			link.Read<float>(&rotation);
2171 			link.Read<float>(&shear);
2172 			link.Read<float>(&falseBoldWidth);
2173 			link.Read<uint8>(&spacing);
2174 			link.Read<uint32>(&flags);
2175 			link.Read<font_metric_mode>(&mode);
2176 
2177 			int32 numStrings;
2178 			link.Read<int32>(&numStrings);
2179 
2180 			escapement_delta deltaArray[numStrings];
2181 			char* stringArray[numStrings];
2182 			int32 lengthArray[numStrings];
2183 			for(int32 i = 0; i < numStrings; i++) {
2184 				// This version of ReadString allocates the strings, we free
2185 				// them below
2186 				// TODO: this does not work on 64-bit (size_t != int32)
2187 				link.ReadString(&stringArray[i], (size_t*)&lengthArray[i]);
2188 				link.Read<escapement_delta>(&deltaArray[i]);
2189 			}
2190 
2191 			// TODO: don't do this on the heap! (at least check the size before)
2192 			BRect rectArray[numStrings];
2193 
2194 			ServerFont font;
2195 			bool success = false;
2196 			if (font.SetFamilyAndStyle(familyID, styleID) == B_OK) {
2197 				font.SetSize(ptsize);
2198 				font.SetRotation(rotation);
2199 				font.SetShear(shear);
2200 				font.SetFalseBoldWidth(falseBoldWidth);
2201 				font.SetSpacing(spacing);
2202 				font.SetFlags(flags);
2203 
2204 				if (font.GetBoundingBoxesForStrings(stringArray, lengthArray,
2205 					numStrings, rectArray, mode, deltaArray) == B_OK) {
2206 					fLink.StartMessage(B_OK);
2207 					fLink.Attach(rectArray, sizeof(rectArray));
2208 					success = true;
2209 				}
2210 			}
2211 
2212 			for (int32 i = 0; i < numStrings; i++)
2213 				free(stringArray[i]);
2214 
2215 			if (!success)
2216 				fLink.StartMessage(B_ERROR);
2217 
2218 			fLink.Flush();
2219 			break;
2220 		}
2221 
2222 		// Screen commands
2223 
2224 		case AS_VALID_SCREEN_ID:
2225 		{
2226 			// Attached data
2227 			// 1) int32 screen
2228 			int32 id;
2229 			if (link.Read<int32>(&id) == B_OK
2230 				&& id == B_MAIN_SCREEN_ID.id)
2231 				fLink.StartMessage(B_OK);
2232 			else
2233 				fLink.StartMessage(B_ERROR);
2234 
2235 			fLink.Flush();
2236 			break;
2237 		}
2238 
2239 		case AS_GET_NEXT_SCREEN_ID:
2240 		{
2241 			// Attached data
2242 			// 1) int32 screen
2243 			int32 id;
2244 			link.Read<int32>(&id);
2245 
2246 			// TODO: for now, just say we're the last one
2247 			fLink.StartMessage(B_ENTRY_NOT_FOUND);
2248 			fLink.Flush();
2249 			break;
2250 		}
2251 
2252 		case AS_GET_SCREEN_ID_FROM_WINDOW:
2253 		{
2254 			status_t status = B_BAD_VALUE;
2255 
2256 			// Attached data
2257 			// 1) int32 - window client token
2258 			int32 clientToken;
2259 			if (link.Read<int32>(&clientToken) != B_OK)
2260 				status = B_BAD_DATA;
2261 			else {
2262 				BAutolock locker(fWindowListLock);
2263 
2264 				for (int32 i = fWindowList.CountItems(); i-- > 0;) {
2265 					ServerWindow* serverWindow = fWindowList.ItemAt(i);
2266 
2267 					if (serverWindow->ClientToken() == clientToken) {
2268 						AutoReadLocker _(fDesktop->ScreenLocker());
2269 
2270 						// found it!
2271 						Window* window = serverWindow->Window();
2272 						const Screen* screen = NULL;
2273 						if (window != NULL)
2274 							screen = window->Screen();
2275 
2276 						if (screen == NULL) {
2277 							// The window hasn't been added to the desktop yet,
2278 							// or it's an offscreen window
2279 							break;
2280 						}
2281 
2282 						fLink.StartMessage(B_OK);
2283 						fLink.Attach<int32>(screen->ID());
2284 						status = B_OK;
2285 						break;
2286 					}
2287 				}
2288 			}
2289 
2290 			if (status != B_OK)
2291 				fLink.StartMessage(status);
2292 			fLink.Flush();
2293 			break;
2294 		}
2295 
2296 		case AS_SCREEN_GET_MODE:
2297 		{
2298 			STRACE(("ServerApp %s: AS_SCREEN_GET_MODE\n", Signature()));
2299 			// Attached data
2300 			// 1) int32 screen
2301 			// 2) uint32 workspace index
2302 
2303 			int32 id;
2304 			link.Read<int32>(&id);
2305 			uint32 workspace;
2306 			link.Read<uint32>(&workspace);
2307 
2308 			display_mode mode;
2309 			status_t status = fDesktop->GetScreenMode(workspace, id, mode);
2310 
2311 			fLink.StartMessage(status);
2312 			if (status == B_OK)
2313 				fLink.Attach<display_mode>(mode);
2314 			fLink.Flush();
2315 			break;
2316 		}
2317 		case AS_SCREEN_SET_MODE:
2318 		{
2319 			STRACE(("ServerApp %s: AS_SCREEN_SET_MODE\n", Signature()));
2320 			// Attached data
2321 			// 1) int32 screen
2322 			// 2) workspace index
2323 			// 3) display_mode to set
2324 			// 4) 'makeDefault' boolean
2325 
2326 			int32 id;
2327 			link.Read<int32>(&id);
2328 			uint32 workspace;
2329 			link.Read<uint32>(&workspace);
2330 
2331 			display_mode mode;
2332 			link.Read<display_mode>(&mode);
2333 
2334 			bool makeDefault = false;
2335 			status_t status = link.Read<bool>(&makeDefault);
2336 
2337 			if (status == B_OK) {
2338 				status = fDesktop->SetScreenMode(workspace, id, mode,
2339 					makeDefault);
2340 			}
2341 			if (status == B_OK) {
2342 				if (workspace == (uint32)B_CURRENT_WORKSPACE_INDEX
2343 					&& fDesktop->LockSingleWindow()) {
2344 					workspace = fDesktop->CurrentWorkspace();
2345 					fDesktop->UnlockSingleWindow();
2346 				}
2347 
2348 				if (!makeDefault) {
2349 					// Memorize the screen change, so that it can be reverted
2350 					// later
2351 					fTemporaryDisplayModeChange |= 1 << workspace;
2352 				} else
2353 					fTemporaryDisplayModeChange &= ~(1 << workspace);
2354 			}
2355 
2356 			fLink.StartMessage(status);
2357 			fLink.Flush();
2358 			break;
2359 		}
2360 
2361 		case AS_PROPOSE_MODE:
2362 		{
2363 			STRACE(("ServerApp %s: AS_PROPOSE_MODE\n", Signature()));
2364 			int32 id;
2365 			link.Read<int32>(&id);
2366 
2367 			display_mode target, low, high;
2368 			link.Read<display_mode>(&target);
2369 			link.Read<display_mode>(&low);
2370 			link.Read<display_mode>(&high);
2371 			status_t status = fDesktop->HWInterface()->ProposeMode(&target,
2372 				&low, &high);
2373 
2374 			// ProposeMode() returns B_BAD_VALUE to hint that the candidate is
2375 			// not within the given limits (but is supported)
2376 			if (status == B_OK || status == B_BAD_VALUE) {
2377 				fLink.StartMessage(B_OK);
2378 				fLink.Attach<display_mode>(target);
2379 				fLink.Attach<bool>(status == B_OK);
2380 			} else
2381 				fLink.StartMessage(status);
2382 
2383 			fLink.Flush();
2384 			break;
2385 		}
2386 
2387 		case AS_GET_MODE_LIST:
2388 		{
2389 			int32 id;
2390 			link.Read<int32>(&id);
2391 			// TODO: use this screen id
2392 
2393 			display_mode* modeList;
2394 			uint32 count;
2395 			status_t status = fDesktop->HWInterface()->GetModeList(&modeList,
2396 				&count);
2397 			if (status == B_OK) {
2398 				fLink.StartMessage(B_OK);
2399 				fLink.Attach<uint32>(count);
2400 				fLink.Attach(modeList, sizeof(display_mode) * count);
2401 
2402 				delete[] modeList;
2403 			} else
2404 				fLink.StartMessage(status);
2405 
2406 			fLink.Flush();
2407 			break;
2408 		}
2409 
2410 		case AS_GET_SCREEN_FRAME:
2411 		{
2412 			STRACE(("ServerApp %s: AS_GET_SCREEN_FRAME\n", Signature()));
2413 			// Attached data
2414 			// 1) int32 screen
2415 			// 2) uint32 workspace index
2416 
2417 			int32 id;
2418 			link.Read<int32>(&id);
2419 			uint32 workspace;
2420 			link.Read<uint32>(&workspace);
2421 
2422 			BRect frame;
2423 			status_t status = fDesktop->GetScreenFrame(workspace, id, frame);
2424 
2425 			fLink.StartMessage(status);
2426 			if (status == B_OK)
2427 				fLink.Attach<BRect>(frame);
2428 
2429 			fLink.Flush();
2430 			break;
2431 		}
2432 
2433 		case AS_SCREEN_GET_COLORMAP:
2434 		{
2435 			STRACE(("ServerApp %s: AS_SCREEN_GET_COLORMAP\n", Signature()));
2436 
2437 			int32 id;
2438 			link.Read<int32>(&id);
2439 
2440 			const color_map* colorMap = SystemColorMap();
2441 			if (colorMap != NULL) {
2442 				fLink.StartMessage(B_OK);
2443 				fLink.Attach<color_map>(*colorMap);
2444 			} else
2445 				fLink.StartMessage(B_ERROR);
2446 
2447 			fLink.Flush();
2448 			break;
2449 		}
2450 
2451 		case AS_GET_DESKTOP_COLOR:
2452 		{
2453 			STRACE(("ServerApp %s: get desktop color\n", Signature()));
2454 
2455 			uint32 index;
2456 			link.Read<uint32>(&index);
2457 
2458 			fLink.StartMessage(B_OK);
2459 			fDesktop->Lock();
2460 
2461 			// we're nice to our children (and also take the default case
2462 			// into account which asks for the current workspace)
2463 			if (index >= (uint32)kMaxWorkspaces)
2464 				index = fDesktop->CurrentWorkspace();
2465 
2466 			Workspace workspace(*fDesktop, index);
2467 			fLink.Attach<rgb_color>(workspace.Color());
2468 
2469 			fDesktop->Unlock();
2470 			fLink.Flush();
2471 			break;
2472 		}
2473 
2474 		case AS_SET_DESKTOP_COLOR:
2475 		{
2476 			STRACE(("ServerApp %s: set desktop color\n", Signature()));
2477 
2478 			rgb_color color;
2479 			uint32 index;
2480 			bool makeDefault;
2481 
2482 			link.Read<rgb_color>(&color);
2483 			link.Read<uint32>(&index);
2484 			if (link.Read<bool>(&makeDefault) != B_OK)
2485 				break;
2486 
2487 			fDesktop->Lock();
2488 
2489 			// we're nice to our children (and also take the default case
2490 			// into account which asks for the current workspace)
2491 			if (index >= (uint32)kMaxWorkspaces)
2492 				index = fDesktop->CurrentWorkspace();
2493 
2494 			Workspace workspace(*fDesktop, index);
2495 			workspace.SetColor(color, makeDefault);
2496 
2497 			fDesktop->Unlock();
2498 			break;
2499 		}
2500 
2501 		case AS_SET_UI_COLOR:
2502 		{
2503 			STRACE(("ServerApp %s: Set UI Color\n", Signature()));
2504 			// Attached Data:
2505 			// 1) color_which which
2506 			// 2) rgb_color color
2507 			color_which which;
2508 			rgb_color color;
2509 
2510 			link.Read<color_which>(&which);
2511 			if (link.Read<rgb_color>(&color) == B_OK) {
2512 				LockedDesktopSettings settings(fDesktop);
2513 				settings.SetUIColor(which, color);
2514 			}
2515 			break;
2516 		}
2517 
2518 		case AS_GET_ACCELERANT_INFO:
2519 		{
2520 			STRACE(("ServerApp %s: get accelerant info\n", Signature()));
2521 
2522 			// We aren't using the screen_id for now...
2523 			int32 id;
2524 			link.Read<int32>(&id);
2525 
2526 			accelerant_device_info accelerantInfo;
2527 			// TODO: I wonder if there should be a "desktop" lock...
2528 			status_t status
2529 				= fDesktop->HWInterface()->GetDeviceInfo(&accelerantInfo);
2530 			if (status == B_OK) {
2531 				fLink.StartMessage(B_OK);
2532 				fLink.Attach<accelerant_device_info>(accelerantInfo);
2533 			} else
2534 				fLink.StartMessage(status);
2535 
2536 			fLink.Flush();
2537 			break;
2538 		}
2539 
2540 		case AS_GET_MONITOR_INFO:
2541 		{
2542 			STRACE(("ServerApp %s: get monitor info\n", Signature()));
2543 
2544 			// We aren't using the screen_id for now...
2545 			int32 id;
2546 			link.Read<int32>(&id);
2547 
2548 			monitor_info info;
2549 			// TODO: I wonder if there should be a "desktop" lock...
2550 			status_t status = fDesktop->HWInterface()->GetMonitorInfo(&info);
2551 			if (status == B_OK) {
2552 				fLink.StartMessage(B_OK);
2553 				fLink.Attach<monitor_info>(info);
2554 			} else
2555 				fLink.StartMessage(status);
2556 
2557 			fLink.Flush();
2558 			break;
2559 		}
2560 
2561 		case AS_GET_FRAME_BUFFER_CONFIG:
2562 		{
2563 			STRACE(("ServerApp %s: get frame buffer config\n", Signature()));
2564 
2565 			// We aren't using the screen_id for now...
2566 			int32 id;
2567 			link.Read<int32>(&id);
2568 
2569 			frame_buffer_config config;
2570 			// TODO: I wonder if there should be a "desktop" lock...
2571 			status_t status = fDesktop->HWInterface()->GetFrameBufferConfig(config);
2572 			if (status == B_OK) {
2573 				fLink.StartMessage(B_OK);
2574 				fLink.Attach<frame_buffer_config>(config);
2575 			} else
2576 				fLink.StartMessage(status);
2577 
2578 			fLink.Flush();
2579 			break;
2580 		}
2581 
2582 		case AS_GET_RETRACE_SEMAPHORE:
2583 		{
2584 			STRACE(("ServerApp %s: get retrace semaphore\n", Signature()));
2585 
2586 			// We aren't using the screen_id for now...
2587 			int32 id;
2588 			link.Read<int32>(&id);
2589 
2590 			fLink.StartMessage(B_OK);
2591 			fLink.Attach<sem_id>(fDesktop->HWInterface()->RetraceSemaphore());
2592 			fLink.Flush();
2593 			break;
2594 		}
2595 
2596 		case AS_GET_TIMING_CONSTRAINTS:
2597 		{
2598 			STRACE(("ServerApp %s: get timing constraints\n", Signature()));
2599 			// We aren't using the screen_id for now...
2600 			int32 id;
2601 			link.Read<int32>(&id);
2602 
2603 			display_timing_constraints constraints;
2604 			status_t status = fDesktop->HWInterface()->GetTimingConstraints(
2605 				&constraints);
2606 			if (status == B_OK) {
2607 				fLink.StartMessage(B_OK);
2608 				fLink.Attach<display_timing_constraints>(constraints);
2609 			} else
2610 				fLink.StartMessage(status);
2611 
2612 			fLink.Flush();
2613 			break;
2614 		}
2615 
2616 		case AS_GET_PIXEL_CLOCK_LIMITS:
2617 		{
2618 			STRACE(("ServerApp %s: get pixel clock limits\n", Signature()));
2619 			// We aren't using the screen_id for now...
2620 			int32 id;
2621 			link.Read<int32>(&id);
2622 			display_mode mode;
2623 			link.Read<display_mode>(&mode);
2624 
2625 			uint32 low, high;
2626 			status_t status = fDesktop->HWInterface()->GetPixelClockLimits(&mode,
2627 				&low, &high);
2628 			if (status == B_OK) {
2629 				fLink.StartMessage(B_OK);
2630 				fLink.Attach<uint32>(low);
2631 				fLink.Attach<uint32>(high);
2632 			} else
2633 				fLink.StartMessage(status);
2634 
2635 			fLink.Flush();
2636 			break;
2637 		}
2638 
2639 		case AS_SET_DPMS:
2640 		{
2641 			STRACE(("ServerApp %s: AS_SET_DPMS\n", Signature()));
2642 			int32 id;
2643 			link.Read<int32>(&id);
2644 
2645 			uint32 mode;
2646 			link.Read<uint32>(&mode);
2647 
2648 			status_t status = fDesktop->HWInterface()->SetDPMSMode(mode);
2649 			fLink.StartMessage(status);
2650 
2651 			fLink.Flush();
2652 			break;
2653 		}
2654 
2655 		case AS_GET_DPMS_STATE:
2656 		{
2657 			STRACE(("ServerApp %s: AS_GET_DPMS_STATE\n", Signature()));
2658 
2659 			int32 id;
2660 			link.Read<int32>(&id);
2661 
2662 			uint32 state = fDesktop->HWInterface()->DPMSMode();
2663 			fLink.StartMessage(B_OK);
2664 			fLink.Attach<uint32>(state);
2665 			fLink.Flush();
2666 			break;
2667 		}
2668 
2669 		case AS_GET_DPMS_CAPABILITIES:
2670 		{
2671 			STRACE(("ServerApp %s: AS_GET_DPMS_CAPABILITIES\n", Signature()));
2672 			int32 id;
2673 			link.Read<int32>(&id);
2674 
2675 			uint32 capabilities = fDesktop->HWInterface()->DPMSCapabilities();
2676 			fLink.StartMessage(B_OK);
2677 			fLink.Attach<uint32>(capabilities);
2678 			fLink.Flush();
2679 			break;
2680 		}
2681 
2682 		case AS_READ_BITMAP:
2683 		{
2684 			STRACE(("ServerApp %s: AS_READ_BITMAP\n", Signature()));
2685 			int32 bitmapToken;
2686 			link.Read<int32>(&bitmapToken);
2687 
2688 			bool drawCursor = true;
2689 			link.Read<bool>(&drawCursor);
2690 
2691 			BRect bounds;
2692 			link.Read<BRect>(&bounds);
2693 
2694 			ServerBitmap *bitmap = FindBitmap(bitmapToken);
2695 			if (bitmap != NULL) {
2696 				if (fDesktop->GetDrawingEngine()->ReadBitmap(bitmap,
2697 					drawCursor, bounds) == B_OK) {
2698 					fLink.StartMessage(B_OK);
2699 				} else
2700 					fLink.StartMessage(B_BAD_VALUE);
2701 			} else
2702 				fLink.StartMessage(B_BAD_VALUE);
2703 
2704 			fLink.Flush();
2705 			break;
2706 		}
2707 
2708 		case AS_GET_ACCELERANT_PATH:
2709 		{
2710 			int32 id;
2711 			fLink.Read<int32>(&id);
2712 
2713 			BString path;
2714 			status_t status = fDesktop->HWInterface()->GetAccelerantPath(path);
2715 			fLink.StartMessage(status);
2716 			if (status == B_OK)
2717 				fLink.AttachString(path.String());
2718 
2719 			fLink.Flush();
2720 			break;
2721 		}
2722 
2723 		case AS_GET_DRIVER_PATH:
2724 		{
2725 			int32 id;
2726 			fLink.Read<int32>(&id);
2727 
2728 			BString path;
2729 			status_t status = fDesktop->HWInterface()->GetDriverPath(path);
2730 			fLink.StartMessage(status);
2731 			if (status == B_OK)
2732 				fLink.AttachString(path.String());
2733 
2734 			fLink.Flush();
2735 			break;
2736 		}
2737 
2738 		// BWindowScreen communication
2739 
2740 		case AS_DIRECT_SCREEN_LOCK:
2741 		{
2742 			bool lock;
2743 			link.Read<bool>(&lock);
2744 
2745 			status_t status;
2746 			if (lock)
2747 				status = fDesktop->LockDirectScreen(ClientTeam());
2748 			else
2749 				status = fDesktop->UnlockDirectScreen(ClientTeam());
2750 
2751 			fLink.StartMessage(status);
2752 			fLink.Flush();
2753 			break;
2754 		}
2755 
2756 		// Hinting and aliasing
2757 
2758 		case AS_SET_SUBPIXEL_ANTIALIASING:
2759 		{
2760 			bool subpix;
2761 			if (link.Read<bool>(&subpix) == B_OK) {
2762 				LockedDesktopSettings settings(fDesktop);
2763 				settings.SetSubpixelAntialiasing(subpix);
2764 			}
2765 			fDesktop->Redraw();
2766 			break;
2767 		}
2768 
2769 		case AS_GET_SUBPIXEL_ANTIALIASING:
2770 		{
2771 			DesktopSettings settings(fDesktop);
2772 			fLink.StartMessage(B_OK);
2773 			fLink.Attach<bool>(settings.SubpixelAntialiasing());
2774 			fLink.Flush();
2775 			break;
2776 		}
2777 
2778 		case AS_SET_HINTING:
2779 		{
2780 			uint8 hinting;
2781 			if (link.Read<uint8>(&hinting) == B_OK && hinting < 3) {
2782 				LockedDesktopSettings settings(fDesktop);
2783 				if (hinting != settings.Hinting()) {
2784 					settings.SetHinting(hinting);
2785 					fDesktop->Redraw();
2786 				}
2787 			}
2788 			break;
2789 		}
2790 
2791 		case AS_GET_HINTING:
2792 		{
2793 			DesktopSettings settings(fDesktop);
2794 			fLink.StartMessage(B_OK);
2795 			fLink.Attach<uint8>(settings.Hinting());
2796 			fLink.Flush();
2797 			break;
2798 		}
2799 
2800 		case AS_SET_SUBPIXEL_AVERAGE_WEIGHT:
2801 		{
2802 			uint8 averageWeight;
2803 			if (link.Read<uint8>(&averageWeight) == B_OK) {
2804 				LockedDesktopSettings settings(fDesktop);
2805 				settings.SetSubpixelAverageWeight(averageWeight);
2806 			}
2807 			fDesktop->Redraw();
2808 			break;
2809 		}
2810 
2811 		case AS_GET_SUBPIXEL_AVERAGE_WEIGHT:
2812 		{
2813 			DesktopSettings settings(fDesktop);
2814 			fLink.StartMessage(B_OK);
2815 			fLink.Attach<uint8>(settings.SubpixelAverageWeight());
2816 			fLink.Flush();
2817 			break;
2818 		}
2819 
2820 		case AS_SET_SUBPIXEL_ORDERING:
2821 		{
2822 			bool subpixelOrdering;
2823 			if (link.Read<bool>(&subpixelOrdering) == B_OK) {
2824 				LockedDesktopSettings settings(fDesktop);
2825 				settings.SetSubpixelOrderingRegular(subpixelOrdering);
2826 			}
2827 			fDesktop->Redraw();
2828 			break;
2829 		}
2830 
2831 		case AS_GET_SUBPIXEL_ORDERING:
2832 		{
2833 			DesktopSettings settings(fDesktop);
2834 			fLink.StartMessage(B_OK);
2835 			fLink.Attach<bool>(settings.IsSubpixelOrderingRegular());
2836 			fLink.Flush();
2837 			break;
2838 		}
2839 
2840 		default:
2841 			printf("ServerApp %s received unhandled message code %ld\n",
2842 				Signature(), code);
2843 
2844 			if (link.NeedsReply()) {
2845 				// the client is now blocking and waiting for a reply!
2846 				fLink.StartMessage(B_ERROR);
2847 				fLink.Flush();
2848 			} else
2849 				puts("message doesn't need a reply!");
2850 			break;
2851 	}
2852 }
2853 
2854 
2855 status_t
2856 ServerApp::_CreateWindow(int32 code, BPrivate::LinkReceiver& link,
2857 	port_id& clientReplyPort)
2858 {
2859 	// Attached data:
2860 	// 1) int32 bitmap token (only for AS_CREATE_OFFSCREEN_WINDOW)
2861 	// 2) BRect window frame
2862 	// 3) uint32 window look
2863 	// 4) uint32 window feel
2864 	// 5) uint32 window flags
2865 	// 6) uint32 workspace index
2866 	// 7) int32 BHandler token of the window
2867 	// 8) port_id window's reply port
2868 	// 9) port_id window's looper port
2869 	// 10) const char * title
2870 
2871 	BRect frame;
2872 	int32 bitmapToken;
2873 	uint32 look;
2874 	uint32 feel;
2875 	uint32 flags;
2876 	uint32 workspaces;
2877 	int32 token;
2878 	port_id looperPort;
2879 	char* title;
2880 
2881 	if (code == AS_CREATE_OFFSCREEN_WINDOW)
2882 		link.Read<int32>(&bitmapToken);
2883 
2884 	link.Read<BRect>(&frame);
2885 	link.Read<uint32>(&look);
2886 	link.Read<uint32>(&feel);
2887 	link.Read<uint32>(&flags);
2888 	link.Read<uint32>(&workspaces);
2889 	link.Read<int32>(&token);
2890 	link.Read<port_id>(&clientReplyPort);
2891 	link.Read<port_id>(&looperPort);
2892 	if (link.ReadString(&title) != B_OK)
2893 		return B_ERROR;
2894 
2895 	if (!frame.IsValid()) {
2896 		// make sure we pass a valid rectangle to ServerWindow
2897 		frame.right = frame.left + 1;
2898 		frame.bottom = frame.top + 1;
2899 	}
2900 
2901 	status_t status = B_NO_MEMORY;
2902 	ServerWindow *window = NULL;
2903 
2904 	if (code == AS_CREATE_OFFSCREEN_WINDOW) {
2905 		ServerBitmap* bitmap = FindBitmap(bitmapToken);
2906 
2907 		if (bitmap != NULL) {
2908 			window = new (nothrow) OffscreenServerWindow(title, this,
2909 				clientReplyPort, looperPort, token, bitmap);
2910 		} else
2911 			status = B_ERROR;
2912 	} else {
2913 		window = new (nothrow) ServerWindow(title, this, clientReplyPort,
2914 			looperPort, token);
2915 		STRACE(("\nServerApp %s: New Window %s (%g:%g, %g:%g)\n",
2916 			Signature(), title, frame.left, frame.top,
2917 			frame.right, frame.bottom));
2918 	}
2919 
2920 	free(title);
2921 
2922 	// NOTE: the reply to the client is handled in ServerWindow::Run()
2923 	if (window != NULL) {
2924 		status = window->Init(frame, (window_look)look, (window_feel)feel,
2925 			flags, workspaces);
2926 		if (status == B_OK && !window->Run()) {
2927 			syslog(LOG_ERR, "ServerApp::_CreateWindow() - failed to run the "
2928 				"window thread\n");
2929 			status = B_ERROR;
2930 		}
2931 
2932 		if (status != B_OK)
2933 			delete window;
2934 	}
2935 
2936 	return status;
2937 }
2938 
2939 
2940 bool
2941 ServerApp::AddWindow(ServerWindow* window)
2942 {
2943 	BAutolock locker(fWindowListLock);
2944 
2945 	return fWindowList.AddItem(window);
2946 }
2947 
2948 
2949 void
2950 ServerApp::RemoveWindow(ServerWindow* window)
2951 {
2952 	BAutolock locker(fWindowListLock);
2953 
2954 	fWindowList.RemoveItem(window);
2955 }
2956 
2957 
2958 bool
2959 ServerApp::InWorkspace(int32 index) const
2960 {
2961 	BAutolock locker(fWindowListLock);
2962 
2963 	// we could cache this, but then we'd have to recompute the cached
2964 	// value everytime a window has closed or changed workspaces
2965 
2966 	// TODO: support initial application workspace!
2967 
2968 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
2969 		ServerWindow* serverWindow = fWindowList.ItemAt(i);
2970 
2971 		const Window* window = serverWindow->Window();
2972 		if (window == NULL || window->IsOffscreenWindow())
2973 			continue;
2974 
2975 		// only normal and unhidden windows count
2976 
2977 		if (window->IsNormal() && !window->IsHidden()
2978 			&& window->InWorkspace(index))
2979 			return true;
2980 	}
2981 
2982 	return false;
2983 }
2984 
2985 
2986 uint32
2987 ServerApp::Workspaces() const
2988 {
2989 	uint32 workspaces = 0;
2990 
2991 	BAutolock locker(fWindowListLock);
2992 
2993 	// we could cache this, but then we'd have to recompute the cached
2994 	// value everytime a window has closed or changed workspaces
2995 
2996 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
2997 		ServerWindow* serverWindow = fWindowList.ItemAt(i);
2998 
2999 		const Window* window = serverWindow->Window();
3000 		if (window == NULL || window->IsOffscreenWindow())
3001 			continue;
3002 
3003 		// only normal and unhidden windows count
3004 
3005 		if (window->IsNormal() && !window->IsHidden())
3006 			workspaces |= window->Workspaces();
3007 	}
3008 
3009 	// TODO: add initial application workspace!
3010 	return workspaces;
3011 }
3012 
3013 
3014 int32
3015 ServerApp::CountBitmaps() const
3016 {
3017 	return fBitmapList.CountItems();
3018 }
3019 
3020 
3021 /*!	\brief Looks up a ServerApp's ServerBitmap in its list
3022 	\param token ID token of the bitmap to find
3023 	\return The bitmap having that ID or NULL if not found
3024 */
3025 ServerBitmap*
3026 ServerApp::FindBitmap(int32 token) const
3027 {
3028 	// TODO: we need to make sure the bitmap is ours?!
3029 	ServerBitmap* bitmap;
3030 	if (gTokenSpace.GetToken(token, kBitmapToken, (void**)&bitmap) == B_OK)
3031 		return bitmap;
3032 
3033 	return NULL;
3034 }
3035 
3036 
3037 int32
3038 ServerApp::CountPictures() const
3039 {
3040 	return fPictureList.CountItems();
3041 }
3042 
3043 
3044 ServerPicture*
3045 ServerApp::CreatePicture(const ServerPicture* original)
3046 {
3047 	ServerPicture* picture;
3048 	if (original != NULL)
3049 		picture = new (std::nothrow) ServerPicture(*original);
3050 	else
3051 		picture = new (std::nothrow) ServerPicture();
3052 
3053 	if (picture != NULL)
3054 		fPictureList.AddItem(picture);
3055 
3056 	return picture;
3057 }
3058 
3059 
3060 ServerPicture*
3061 ServerApp::FindPicture(int32 token) const
3062 {
3063 	// TODO: we need to make sure the picture is ours?!
3064 	ServerPicture* picture;
3065 	if (gTokenSpace.GetToken(token, kPictureToken, (void**)&picture) == B_OK)
3066 		return picture;
3067 
3068 	return NULL;
3069 }
3070 
3071 
3072 bool
3073 ServerApp::DeletePicture(int32 token)
3074 {
3075 	ServerPicture* picture = FindPicture(token);
3076 	if (picture == NULL)
3077 		return false;
3078 
3079 	if (!fPictureList.RemoveItem(picture))
3080 		return false;
3081 
3082 	delete picture;
3083 
3084 	return true;
3085 }
3086 
3087 
3088 team_id
3089 ServerApp::ClientTeam() const
3090 {
3091 	return fClientTeam;
3092 }
3093