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