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