xref: /haiku/src/servers/app/ServerApp.cpp (revision 0b2dbe7d46ee888392907c60131b7f7652314175)
1 /*
2  * Copyright 2001-2005, 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  */
12 
13 
14 #include <stdio.h>
15 #include <string.h>
16 
17 #include <AppDefs.h>
18 #include <Autolock.h>
19 #include <ColorSet.h>
20 #include <List.h>
21 #include <ScrollBar.h>
22 #include <ServerProtocol.h>
23 #include <Shape.h>
24 #include <String.h>
25 
26 #include "AppServer.h"
27 #include "BGet++.h"
28 #include "BitmapManager.h"
29 #include "CursorManager.h"
30 #include "Desktop.h"
31 #include "DecorManager.h"
32 #include "DisplayDriver.h"
33 #include "FontServer.h"
34 #include "HWInterface.h"
35 #include "LayerData.h"
36 #include "RAMLinkMsgReader.h"
37 //#include "RGBColor.h"
38 #include "RootLayer.h"
39 #include "ServerBitmap.h"
40 #include "ServerConfig.h"
41 #include "ServerCursor.h"
42 #include "ServerPicture.h"
43 #include "ServerScreen.h"
44 #include "ServerWindow.h"
45 #include "SysCursor.h"
46 #include "SystemPalette.h"
47 #include "Utils.h"
48 #include "WinBorder.h"
49 
50 #include "ServerApp.h"
51 #include <syslog.h>
52 
53 //#define DEBUG_SERVERAPP
54 
55 #ifdef DEBUG_SERVERAPP
56 #	define STRACE(x) printf x
57 #else
58 #	define STRACE(x) ;
59 #endif
60 
61 //#define DEBUG_SERVERAPP_FONT
62 
63 #ifdef DEBUG_SERVERAPP_FONT
64 #	define FTRACE(x) printf x
65 #else
66 #	define FTRACE(x) ;
67 #endif
68 
69 
70 static const uint32 kMsgAppQuit = 'appQ';
71 
72 
73 /*!
74 	\brief Constructor
75 	\param sendport port ID for the BApplication which will receive the ServerApp's messages
76 	\param rcvport port by which the ServerApp will receive messages from its BApplication.
77 	\param fSignature NULL-terminated string which contains the BApplication's
78 	MIME fSignature.
79 */
80 ServerApp::ServerApp(port_id clientReplyPort, port_id clientLooperPort,
81 	team_id clientTeam, int32 handlerID, const char* signature)
82 	:
83 	fClientReplyPort(clientReplyPort),
84 	fMessagePort(-1),
85 	fClientLooperPort(clientLooperPort),
86 	fSignature(signature),
87 	fThread(-1),
88 	fClientTeam(clientTeam),
89 	fWindowListLock("window list"),
90 	fAppCursor(NULL),
91 	fCursorHidden(false),
92 	fIsActive(false),
93 	//fHandlerToken(handlerID),
94 	fSharedMem("shared memory"),
95 	fQuitting(false)
96 {
97 	if (fSignature == "")
98 		fSignature = "application/no-signature";
99 
100 	char name[B_OS_NAME_LENGTH];
101 	snprintf(name, sizeof(name), "a<%s", Signature());
102 
103 	fMessagePort = create_port(DEFAULT_MONITOR_PORT_SIZE, name);
104 	if (fMessagePort < B_OK)
105 		return;
106 
107 	fLink.SetSenderPort(fClientReplyPort);
108 	fLink.SetReceiverPort(fMessagePort);
109 
110 	// we let the application own the port, so that we get aware when it's gone
111 	if (set_port_owner(fMessagePort, clientTeam) < B_OK) {
112 		delete_port(fMessagePort);
113 		fMessagePort = -1;
114 		return;
115 	}
116 
117 	// although this isn't pretty, ATM we have only one RootLayer.
118 	// there should be a way that this ServerApp be attached to a particular
119 	// RootLayer to know which RootLayer's cursor to modify.
120 	ServerCursor *defaultCursor =
121 		gDesktop->ActiveRootLayer()->GetCursorManager().GetCursor(B_CURSOR_DEFAULT);
122 
123 	if (defaultCursor) {
124 		fAppCursor = new ServerCursor(defaultCursor);
125 		fAppCursor->SetOwningTeam(fClientTeam);
126 	}
127 
128 	STRACE(("ServerApp %s:\n", fSignature.String()));
129 	STRACE(("\tBApp port: %ld\n", fClientReplyPort));
130 	STRACE(("\tReceiver port: %ld\n", fMessagePort));
131 }
132 
133 
134 //! Does all necessary teardown for application
135 ServerApp::~ServerApp(void)
136 {
137 	STRACE(("*ServerApp %s:~ServerApp()\n",fSignature.String()));
138 
139 	if (!fQuitting)
140 		CRITICAL("ServerApp: destructor called after Run()!\n");
141 
142 	fWindowListLock.Lock();
143 
144 	// quit all server windows
145 
146 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
147 		ServerWindow* window = (ServerWindow*)fWindowList.ItemAt(i);
148 		window->Quit();
149 	}
150 	int32 tries = fWindowList.CountItems() + 1;
151 
152 	fWindowListLock.Unlock();
153 
154 	// wait for the windows to quit
155 	while (tries-- > 0) {
156 		fWindowListLock.Lock();
157 		if (fWindowList.CountItems() == 0) {
158 			// we leave the list locked, doesn't matter anymore
159 			break;
160 		}
161 
162 		fWindowListLock.Unlock();
163 		snooze(10000);
164 	}
165 
166 	if (tries < 0) {
167 		// This really shouldn't happen, as it shows we're buggy
168 		syslog(LOG_ERR, "ServerApp %s needs to kill some server windows...\n", Signature());
169 
170 		// there still seem to be some windows left - kill them!
171 		fWindowListLock.Lock();
172 
173 		for (int32 i = 0; i < fWindowList.CountItems(); i++) {
174 			ServerWindow* window = (ServerWindow*)fWindowList.ItemAt(i);
175 
176 			kill_thread(window->Thread());
177 			window->Hide();
178 			delete window;
179 		}
180 
181 		fWindowListLock.Unlock();
182 	}
183 
184 	// first, make sure our monitor thread doesn't
185 	for (int32 i = 0; i < fBitmapList.CountItems(); i++) {
186 		delete static_cast<ServerBitmap *>(fBitmapList.ItemAt(i));
187 	}
188 
189 	for (int32 i = 0; i < fPictureList.CountItems(); i++) {
190 		delete static_cast<ServerPicture *>(fPictureList.ItemAt(i));
191 	}
192 
193 	// This shouldn't be necessary -- all cursors owned by the app
194 	// should be cleaned up by RemoveAppCursors
195 //	delete fAppCursor;
196 
197 	// although this isn't pretty, ATM we have only one RootLayer.
198 	// there should be a way that this ServerApp be attached to a particular
199 	// RootLayer to know which RootLayer's cursor to modify.
200 	gDesktop->ActiveRootLayer()->GetCursorManager().RemoveAppCursors(fClientTeam);
201 
202 	STRACE(("ServerApp %s::~ServerApp(): Exiting\n", Signature()));
203 }
204 
205 
206 /*!
207 	\brief Checks if the application was initialized correctly
208 */
209 status_t
210 ServerApp::InitCheck()
211 {
212 	if (fMessagePort < B_OK)
213 		return fMessagePort;
214 
215 	if (fClientReplyPort < B_OK)
216 		return fClientReplyPort;
217 
218 	if (fWindowListLock.Sem() < B_OK)
219 		return fWindowListLock.Sem();
220 
221 	return B_OK;
222 }
223 
224 
225 /*!
226 	\brief Starts the ServerApp monitoring for messages
227 	\return false if the application couldn't start, true if everything went OK.
228 */
229 bool
230 ServerApp::Run()
231 {
232 	fQuitting = false;
233 
234 	// Unlike a BApplication, a ServerApp is *supposed* to return immediately
235 	// when its Run() function is called.
236 	fThread = spawn_thread(_message_thread, Signature(), B_NORMAL_PRIORITY, this);
237 	if (fThread < B_OK)
238 		return false;
239 
240 	if (resume_thread(fThread) != B_OK) {
241 		fQuitting = true;
242 		kill_thread(fThread);
243 		fThread = -1;
244 		return false;
245 	}
246 
247 	// Let's tell the client how to talk with us
248 	fLink.StartMessage(SERVER_TRUE);
249 	fLink.Attach<int32>(fMessagePort);
250 	fLink.Flush();
251 
252 	return true;
253 }
254 
255 
256 /*!
257 	\brief This quits the application and deletes it. You're not supposed
258 		to call its destructor directly.
259 
260 	At the point you're calling this method, the application should already
261 	be removed from the application list.
262 */
263 void
264 ServerApp::Quit()
265 {
266 	if (fThread < B_OK) {
267 		delete this;
268 		return;
269 	}
270 
271 	// execute application deletion in the message looper thread
272 
273 	fQuitting = true;
274 	PostMessage(kMsgAppQuit);
275 
276 	send_data(fThread, 'QUIT', NULL, 0);
277 }
278 
279 
280 /*!
281 	\brief Pings the target app to make sure it's still working
282 	\return true if target is still "alive" and false if "He's dead, Jim."
283 	"But that's impossible..."
284 
285 	This function is called by the app_server thread to ensure that
286 	the target app still exists. We do this not by sending a message
287 	but by calling get_port_info. We don't want to send ping messages
288 	just because the app might simply be hung. If this is the case, it
289 	should be up to the user to kill it. If the app has been killed, its
290 	ports will be invalid. Thus, if get_port_info returns an error, we
291 	tell the app_server to delete the respective ServerApp.
292 */
293 bool
294 ServerApp::PingTarget()
295 {
296 	team_info info;
297 	if (get_team_info(fClientTeam, &info) != B_OK) {
298 		BPrivate::LinkSender link(gAppServerPort);
299 		link.StartMessage(AS_DELETE_APP);
300 		link.Attach(&fThread, sizeof(thread_id));
301 		link.Flush();
302 		return false;
303 	}
304 	return true;
305 }
306 
307 /*!
308 	\brief Send a message to the ServerApp with no attachments
309 	\param code ID code of the message to post
310 */
311 void
312 ServerApp::PostMessage(int32 code)
313 {
314 	BPrivate::LinkSender link(fMessagePort);
315 	link.StartMessage(code);
316 	link.Flush();
317 }
318 
319 /*!
320 	\brief Send a message to the ServerApp's BApplication
321 	\param msg The message to send
322 */
323 void
324 ServerApp::SendMessageToClient(const BMessage *msg) const
325 {
326 	ssize_t size = msg->FlattenedSize();
327 	char *buffer = new char[size];
328 
329 	if (msg->Flatten(buffer, size) == B_OK)
330 		write_port(fClientLooperPort, msg->what, buffer, size);
331 	else
332 		printf("PANIC: ServerApp: '%s': can't flatten message in 'SendMessageToClient()'\n", fSignature.String());
333 
334 	delete [] buffer;
335 }
336 
337 /*!
338 	\brief Sets the ServerApp's active status
339 	\param value The new status of the ServerApp.
340 
341 	This changes an internal flag and also sets the current cursor to the one specified by
342 	the application
343 */
344 void
345 ServerApp::Activate(bool value)
346 {
347 	fIsActive = value;
348 	SetAppCursor();
349 }
350 
351 
352 //! Sets the cursor to the application cursor, if any.
353 void
354 ServerApp::SetAppCursor(void)
355 {
356 	// although this isn't pretty, ATM we have only one RootLayer.
357 	// there should be a way that this ServerApp be attached to a particular
358 	// RootLayer to know which RootLayer's cursor to modify.
359 	if (fAppCursor)
360 		gDesktop->GetHWInterface()->SetCursor(fAppCursor);
361 }
362 
363 
364 /*!
365 	\brief The thread function ServerApps use to monitor messages
366 	\param data Pointer to the thread's ServerApp object
367 */
368 int32
369 ServerApp::_message_thread(void *_app)
370 {
371 	ServerApp *app = (ServerApp *)_app;
372 
373 	app->_MessageLooper();
374 	return 0;
375 }
376 
377 
378 /*!
379 	\brief The thread function ServerApps use to monitor messages
380 */
381 void
382 ServerApp::_MessageLooper()
383 {
384 	// Message-dispatching loop for the ServerApp
385 
386 	BPrivate::LinkReceiver &receiver = fLink.Receiver();
387 
388 	int32 code;
389 	status_t err = B_OK;
390 
391 	while (!fQuitting) {
392 		STRACE(("info: ServerApp::_MessageLooper() listening on port %ld.\n", fMessagePort));
393 		err = receiver.GetNextMessage(code, B_INFINITE_TIMEOUT);
394 		if (err < B_OK || code == B_QUIT_REQUESTED) {
395 			STRACE(("ServerApp: application seems to be gone...\n"));
396 
397 			// Tell the app_server to quit us
398 			BPrivate::LinkSender link(gAppServerPort);
399 			link.StartMessage(AS_DELETE_APP);
400 			link.Attach<thread_id>(Thread());
401 			link.Flush();
402 			break;
403 		}
404 
405 		switch (code) {
406 			case kMsgAppQuit:
407 				// we receive this from our destructor on quit
408 				fQuitting = true;
409 				break;
410 
411 			case AS_CREATE_WINDOW:
412 			{
413 				// Create the ServerWindow to node monitor a new OBWindow
414 
415 				// Attached data:
416 				// 2) BRect window frame
417 				// 3) uint32 window look
418 				// 4) uint32 window feel
419 				// 5) uint32 window flags
420 				// 6) uint32 workspace index
421 				// 7) int32 BHandler token of the window
422 				// 8) port_id window's message port
423 				// 9) const char * title
424 
425 				BRect frame;
426 				uint32 look;
427 				uint32 feel;
428 				uint32 flags;
429 				uint32 workspaces;
430 				int32 token = B_NULL_TOKEN;
431 				port_id	clientReplyPort = -1;
432 				port_id looperPort = -1;
433 				char *title = NULL;
434 
435 				receiver.Read<BRect>(&frame);
436 				receiver.Read<uint32>(&look);
437 				receiver.Read<uint32>(&feel);
438 				receiver.Read<uint32>(&flags);
439 				receiver.Read<uint32>(&workspaces);
440 				receiver.Read<int32>(&token);
441 				receiver.Read<port_id>(&clientReplyPort);
442 				receiver.Read<port_id>(&looperPort);
443 				if (receiver.ReadString(&title) != B_OK)
444 					break;
445 
446 				if (!frame.IsValid()) {
447 					// make sure we pass a valid rectangle to ServerWindow
448 					frame.right = frame.left + 1;
449 					frame.bottom = frame.top + 1;
450 				}
451 
452 				// ServerWindow constructor will reply with port_id of a newly created port
453 				ServerWindow *window = new ServerWindow(title, this, clientReplyPort,
454 					looperPort, token, frame, look, feel, flags, workspaces);
455 
456 				STRACE(("\nServerApp %s: New Window %s (%.1f,%.1f,%.1f,%.1f)\n",
457 					fSignature(), title, frame.left, frame.top, frame.right, frame.bottom));
458 
459 				if (window->InitCheck() == B_OK && window->Run()) {
460 					// add the window to the list
461 					if (fWindowListLock.Lock()) {
462 						fWindowList.AddItem(window);
463 						fWindowListLock.Unlock();
464 					}
465 				} else {
466 					delete window;
467 
468 					// window creation failed, we need to notify the client
469 					BPrivate::LinkSender reply(clientReplyPort);
470 					reply.StartMessage(SERVER_FALSE);
471 					reply.Flush();
472 				}
473 
474 				// We don't have to free the title, as it's owned by the ServerWindow now
475 				break;
476 			}
477 
478 			case AS_QUIT_APP:
479 			{
480 				// This message is received only when the app_server is asked to shut down in
481 				// test/debug mode. Of course, if we are testing while using AccelerantDriver, we do
482 				// NOT want to shut down client applications. The server can be quit o in this fashion
483 				// through the driver's interface, such as closing the ViewDriver's window.
484 
485 				STRACE(("ServerApp %s:Server shutdown notification received\n", Signature()));
486 
487 				// If we are using the real, accelerated version of the
488 				// DisplayDriver, we do NOT want the user to be able shut down
489 				// the server. The results would NOT be pretty
490 #if TEST_MODE
491 				BMessage pleaseQuit(B_QUIT_REQUESTED);
492 				SendMessageToClient(&pleaseQuit);
493 #endif
494 				break;
495 			}
496 
497 			default:
498 				STRACE(("ServerApp %s: Got a Message to dispatch\n", Signature()));
499 				_DispatchMessage(code, receiver);
500 				break;
501 		}
502 	}
503 
504 	// Quit() will send us a message; we're handling the exiting procedure
505 	thread_id sender;
506 	receive_data(&sender, NULL, 0);
507 
508 	delete this;
509 }
510 
511 
512 /*!
513 	\brief Handler function for BApplication API messages
514 	\param code Identifier code for the message. Equivalent to BMessage::what
515 	\param buffer Any attachments
516 
517 	Note that the buffer's exact format is determined by the particular message.
518 	All attachments are placed in the buffer via a PortLink, so it will be a
519 	matter of casting and incrementing an index variable to access them.
520 */
521 void
522 ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
523 {
524 //	LayerData ld;
525 
526 	switch (code) {
527 		case AS_UPDATE_COLORS:
528 		{
529 			// NOTE: R2: Eventually we will have windows which will notify their children of changes in
530 			// system colors
531 
532 /*			STRACE(("ServerApp %s: Received global UI color update notification\n",fSignature.String()));
533 			ServerWindow *win;
534 			BMessage msg(_COLORS_UPDATED);
535 
536 			for(int32 i = 0; i < fWindowList.CountItems(); i++) {
537 				win=(ServerWindow*)fWindowList.ItemAt(i);
538 				win->GetWinBorder()->UpdateColors();
539 				win->SendMessageToClient(AS_UPDATE_COLORS, msg);
540 			}
541 */			break;
542 		}
543 		case AS_UPDATE_FONTS:
544 		{
545 			// NOTE: R2: Eventually we will have windows which will notify their children of changes in
546 			// system fonts
547 
548 /*			STRACE(("ServerApp %s: Received global font update notification\n",fSignature.String()));
549 			ServerWindow *win;
550 			BMessage msg(_FONTS_UPDATED);
551 
552 			for(int32 i=0; i<fSWindowList->CountItems(); i++)
553 			{
554 				win=(ServerWindow*)fSWindowList->ItemAt(i);
555 				win->GetWinBorder()->UpdateFont();
556 				win->SendMessageToClient(AS_UPDATE_FONTS, msg);
557 			}
558 */			break;
559 		}
560 		case AS_AREA_MESSAGE:
561 		{
562 			// This occurs in only one kind of case: a message is too big to send over a port. This
563 			// is really an edge case, so this shouldn't happen *too* often
564 
565 			// Attached Data:
566 			// 1) area_id id of an area already owned by the server containing the message
567 			// 2) size_t offset of the pointer in the area
568 			// 3) size_t size of the message
569 
570 			area_id area;
571 			size_t offset;
572 			size_t msgsize;
573 			area_info ai;
574 			int8 *msgpointer;
575 
576 			link.Read<area_id>(&area);
577 			link.Read<size_t>(&offset);
578 			link.Read<size_t>(&msgsize);
579 
580 			// Part sanity check, part get base pointer :)
581 			if (get_area_info(area, &ai) < B_OK)
582 				break;
583 
584 			msgpointer = (int8*)ai.address + offset;
585 
586 			RAMLinkMsgReader mlink(msgpointer);
587 			_DispatchMessage(mlink.Code(), mlink);
588 
589 			// This is a very special case in the sense that when ServerMemIO is used for this
590 			// purpose, it will be set to NOT automatically free the memory which it had
591 			// requested. This is the server's job once the message has been dispatched.
592 			fSharedMem.ReleaseBuffer(msgpointer);
593 			break;
594 		}
595 		case AS_ACQUIRE_SERVERMEM:
596 		{
597 			// This particular call is more than a bit of a pain in the neck. We are given a
598 			// size of a chunk of memory needed. We need to (1) allocate it, (2) get the area for
599 			// this particular chunk, (3) find the offset in the area for this chunk, and (4)
600 			// tell the client about it. Good thing this particular call isn't used much
601 
602 			// Received from a ServerMemIO object requesting operating memory
603 			// Attached Data:
604 			// 1) size_t requested size
605 			// 2) port_id reply_port
606 
607 			size_t memsize;
608 			link.Read<size_t>(&memsize);
609 
610 			// TODO: I wonder if ACQUIRE_SERVERMEM should have a minimum size requirement?
611 
612 			void *sharedmem = fSharedMem.GetBuffer(memsize);
613 
614 			if (memsize < 1 || sharedmem == NULL) {
615 				fLink.StartMessage(SERVER_FALSE);
616 				fLink.Flush();
617 				break;
618 			}
619 
620 			area_id owningArea = area_for(sharedmem);
621 			area_info info;
622 
623 			if (owningArea == B_ERROR || get_area_info(owningArea, &info) < B_OK) {
624 				fLink.StartMessage(SERVER_FALSE);
625 				fLink.Flush();
626 				break;
627 			}
628 
629 			int32 areaoffset = (addr_t)sharedmem - (addr_t)info.address;
630 			STRACE(("Successfully allocated shared memory of size %ld\n",memsize));
631 
632 			fLink.StartMessage(SERVER_TRUE);
633 			fLink.Attach<area_id>(owningArea);
634 			fLink.Attach<int32>(areaoffset);
635 			fLink.Flush();
636 			break;
637 		}
638 		case AS_RELEASE_SERVERMEM:
639 		{
640 			// Received when a ServerMemIO object on destruction
641 			// Attached Data:
642 			// 1) area_id owning area
643 			// 2) int32 area offset
644 
645 			area_id owningArea;
646 			int32 areaoffset;
647 
648 			link.Read<area_id>(&owningArea);
649 			link.Read<int32>(&areaoffset);
650 
651 			area_info areaInfo;
652 			if (owningArea < 0 || get_area_info(owningArea, &areaInfo) != B_OK)
653 				break;
654 
655 			STRACE(("Successfully freed shared memory\n"));
656 			void *sharedmem = ((int32*)areaInfo.address) + areaoffset;
657 
658 			fSharedMem.ReleaseBuffer(sharedmem);
659 
660 			break;
661 		}
662 		case AS_UPDATE_DECORATOR:
663 		{
664 			STRACE(("ServerApp %s: Received decorator update notification\n",fSignature.String()));
665 
666 			for (int32 i = 0; i < fWindowList.CountItems(); i++) {
667 				ServerWindow *window = (ServerWindow*)fWindowList.ItemAt(i);
668 				window->Lock();
669 				const_cast<WinBorder *>(window->GetWinBorder())->UpdateDecorator();
670 				window->Unlock();
671 			}
672 			break;
673 		}
674 		case AS_SET_DECORATOR:
675 		{
676 			// Received from an application when the user wants to set the window
677 			// decorator to a new one
678 
679 			// Attached Data:
680 			// int32 the index of the decorator to use
681 
682 			int32 index;
683 			link.Read<int32>(&index);
684 			if(gDecorManager.SetDecorator(index))
685 				BroadcastToAllApps(AS_UPDATE_DECORATOR);
686 
687 			break;
688 		}
689 		case AS_COUNT_DECORATORS:
690 		{
691 			fLink.StartMessage(SERVER_TRUE);
692 			fLink.Attach<int32>(gDecorManager.CountDecorators());
693 			fLink.Flush();
694 			break;
695 		}
696 		case AS_GET_DECORATOR:
697 		{
698 			fLink.StartMessage(SERVER_TRUE);
699 			fLink.Attach<int32>(gDecorManager.GetDecorator());
700 			fLink.Flush();
701 			break;
702 		}
703 		case AS_GET_DECORATOR_NAME:
704 		{
705 			int32 index;
706 			link.Read<int32>(&index);
707 
708 			BString str(gDecorManager.GetDecoratorName(index));
709 			if(str.CountChars() > 0)
710 			{
711 				fLink.StartMessage(SERVER_TRUE);
712 				fLink.AttachString(str.String());
713 			}
714 			else
715 				fLink.StartMessage(SERVER_FALSE);
716 
717 			fLink.Flush();
718 			break;
719 		}
720 		case AS_R5_SET_DECORATOR:
721 		{
722 			// Sort of supports Tracker's nifty Easter Egg. It was easy to do and
723 			// it's kind of neat, so why not?
724 
725 			// Attached Data:
726 			// int32 value of the decorator to use
727 			// 0: BeOS
728 			// 1: Amiga
729 			// 2: Windows
730 			// 3: MacOS
731 
732 			int32 decindex = 0;
733 			link.Read<int32>(&decindex);
734 
735 			if(gDecorManager.SetR5Decorator(decindex))
736 				BroadcastToAllApps(AS_UPDATE_DECORATOR);
737 
738 			break;
739 		}
740 		case AS_CREATE_BITMAP:
741 		{
742 			STRACE(("ServerApp %s: Received BBitmap creation request\n",fSignature.String()));
743 			// Allocate a bitmap for an application
744 
745 			// Attached Data:
746 			// 1) BRect bounds
747 			// 2) color_space space
748 			// 3) int32 bitmap_flags
749 			// 4) int32 bytes_per_row
750 			// 5) int32 screen_id::id
751 			// 6) port_id reply port
752 
753 			// Reply Code: SERVER_TRUE
754 			// Reply Data:
755 			//	1) int32 server token
756 			//	2) area_id id of the area in which the bitmap data resides
757 			//	3) int32 area pointer offset used to calculate fBasePtr
758 
759 			// First, let's attempt to allocate the bitmap
760 			ServerBitmap *bitmap = NULL;
761 			BRect frame;
762 			color_space colorSpace;
763 			int32 flags, bytesPerRow;
764 			screen_id screenID;
765 
766 			link.Read<BRect>(&frame);
767 			link.Read<color_space>(&colorSpace);
768 			link.Read<int32>(&flags);
769 			link.Read<int32>(&bytesPerRow);
770 			if (link.Read<screen_id>(&screenID) == B_OK) {
771 				bitmap = gBitmapManager->CreateBitmap(frame, colorSpace, flags,
772 					bytesPerRow, screenID);
773 			}
774 
775 			STRACE(("ServerApp %s: Create Bitmap (%.1fx%.1f)\n",
776 						fSignature.String(), frame.Width(), frame.Height()));
777 
778 			if (bitmap) {
779 				fBitmapList.AddItem(bitmap);
780 				fLink.StartMessage(SERVER_TRUE);
781 				fLink.Attach<int32>(bitmap->Token());
782 				fLink.Attach<int32>(bitmap->Area());
783 				fLink.Attach<int32>(bitmap->AreaOffset());
784 			} else {
785 				// alternatively, if something went wrong, we reply with SERVER_FALSE
786 				fLink.StartMessage(SERVER_FALSE);
787 			}
788 
789 			fLink.Flush();
790 			break;
791 		}
792 		case AS_DELETE_BITMAP:
793 		{
794 			STRACE(("ServerApp %s: received BBitmap delete request\n",fSignature.String()));
795 			// Delete a bitmap's allocated memory
796 
797 			// Attached Data:
798 			// 1) int32 token
799 			// 2) int32 reply port
800 
801 			// Reply Code: SERVER_TRUE if successful,
802 			//				SERVER_FALSE if the buffer was already deleted or was not found
803 			int32 id;
804 			link.Read<int32>(&id);
805 
806 			ServerBitmap *bitmap = FindBitmap(id);
807 			if (bitmap) {
808 				STRACE(("ServerApp %s: Deleting Bitmap %ld\n", fSignature.String(), id));
809 
810 				fBitmapList.RemoveItem(bitmap);
811 				gBitmapManager->DeleteBitmap(bitmap);
812 				fLink.StartMessage(SERVER_TRUE);
813 			} else
814 				fLink.StartMessage(SERVER_FALSE);
815 
816 			fLink.Flush();
817 			break;
818 		}
819 		case AS_CREATE_PICTURE:
820 		{
821 			// TODO: Implement AS_CREATE_PICTURE
822 			STRACE(("ServerApp %s: Create Picture unimplemented\n", fSignature.String()));
823 
824 			break;
825 		}
826 		case AS_DELETE_PICTURE:
827 		{
828 			// TODO: Implement AS_DELETE_PICTURE
829 			STRACE(("ServerApp %s: Delete Picture unimplemented\n", fSignature.String()));
830 
831 			break;
832 		}
833 		case AS_CLONE_PICTURE:
834 		{
835 			// TODO: Implement AS_CLONE_PICTURE
836 			STRACE(("ServerApp %s: Clone Picture unimplemented\n",fSignature.String()));
837 
838 			break;
839 		}
840 		case AS_DOWNLOAD_PICTURE:
841 		{
842 			// TODO; Implement AS_DOWNLOAD_PICTURE
843 			STRACE(("ServerApp %s: Download Picture unimplemented\n", fSignature.String()));
844 
845 			// What is this particular function call for, anyway?
846 
847 			// DW: I think originally it might have been to support
848 			// the undocumented Flatten function.
849 
850 			break;
851 		}
852 
853 		case AS_CURRENT_WORKSPACE:
854 		{
855 			STRACE(("ServerApp %s: get current workspace\n", fSignature.String()));
856 
857 			// TODO: Locking this way is not nice
858 			RootLayer *root = gDesktop->ActiveRootLayer();
859 			root->Lock();
860 
861 			fLink.StartMessage(SERVER_TRUE);
862 			fLink.Attach<int32>(root->ActiveWorkspaceIndex());
863 			fLink.Flush();
864 
865 			root->Unlock();
866 			break;
867 		}
868 
869 		case AS_ACTIVATE_WORKSPACE:
870 		{
871 			STRACE(("ServerApp %s: activate workspace\n", fSignature.String()));
872 
873 			// TODO: See above
874 			int32 index;
875 			link.Read<int32>(&index);
876 			RootLayer *root = gDesktop->ActiveRootLayer();
877 			root->Lock();
878 			root->SetActiveWorkspace(index);
879 			root->Unlock();
880 			// no reply
881 
882 			break;
883 		}
884 
885 		// Theoretically, we could just call the driver directly, but we will
886 		// call the CursorManager's version to allow for future expansion
887 		case AS_SHOW_CURSOR:
888 		{
889 			STRACE(("ServerApp %s: Show Cursor\n",fSignature.String()));
890 			// although this isn't pretty, ATM we have only one RootLayer.
891 			// there should be a way that this ServerApp be attached to a particular
892 			// RootLayer to know which RootLayer's cursor to modify.
893 // TODO: support nested showing/hiding
894 			gDesktop->GetHWInterface()->SetCursorVisible(true);
895 			fCursorHidden = false;
896 			break;
897 		}
898 		case AS_HIDE_CURSOR:
899 		{
900 			STRACE(("ServerApp %s: Hide Cursor\n",fSignature.String()));
901 			// although this isn't pretty, ATM we have only one RootLayer.
902 			// there should be a way that this ServerApp be attached to a particular
903 			// RootLayer to know which RootLayer's cursor to modify.
904 // TODO: support nested showing/hiding
905 			gDesktop->GetHWInterface()->SetCursorVisible(false);
906 			fCursorHidden = true;
907 			break;
908 		}
909 		case AS_OBSCURE_CURSOR:
910 		{
911 			STRACE(("ServerApp %s: Obscure Cursor\n",fSignature.String()));
912 			// although this isn't pretty, ATM we have only one RootLayer.
913 			// there should be a way that this ServerApp be attached to a particular
914 			// RootLayer to know which RootLayer's cursor to modify.
915 //			gDesktop->GetHWInterface()->ObscureCursor();
916 			break;
917 		}
918 		case AS_QUERY_CURSOR_HIDDEN:
919 		{
920 			STRACE(("ServerApp %s: Received IsCursorHidden request\n", fSignature.String()));
921 			// Attached data
922 			// 1) int32 port to reply to
923 			fLink.StartMessage(fCursorHidden ? SERVER_TRUE : SERVER_FALSE);
924 			fLink.Flush();
925 			break;
926 		}
927 		case AS_SET_CURSOR_DATA:
928 		{
929 			STRACE(("ServerApp %s: SetCursor via cursor data\n",fSignature.String()));
930 			// Attached data: 68 bytes of fAppCursor data
931 
932 			int8 cdata[68];
933 			link.Read(cdata,68);
934 
935 			// Because we don't want an overaccumulation of these particular
936 			// cursors, we will delete them if there is an existing one. It would
937 			// otherwise be easy to crash the server by calling SetCursor a
938 			// sufficient number of times
939 			if(fAppCursor)
940 				gDesktop->ActiveRootLayer()->GetCursorManager().DeleteCursor(fAppCursor->ID());
941 
942 			fAppCursor = new ServerCursor(cdata);
943 			fAppCursor->SetOwningTeam(fClientTeam);
944 			fAppCursor->SetAppSignature(fSignature.String());
945 			gDesktop->ActiveRootLayer()->GetCursorManager().AddCursor(fAppCursor);
946 			// although this isn't pretty, ATM we have only one RootLayer.
947 			// there should be a way that this ServerApp be attached to a particular
948 			// RootLayer to know which RootLayer's cursor to modify.
949 			gDesktop->GetHWInterface()->SetCursor(fAppCursor);
950 			break;
951 		}
952 		case AS_SET_CURSOR_BCURSOR:
953 		{
954 			STRACE(("ServerApp %s: SetCursor via BCursor\n",fSignature.String()));
955 			// Attached data:
956 			// 1) bool flag to send a reply
957 			// 2) int32 token ID of the cursor to set
958 			// 3) port_id port to receive a reply. Only exists if the sync flag is true.
959 			bool sync;
960 			int32 ctoken = B_NULL_TOKEN;
961 
962 			link.Read<bool>(&sync);
963 			link.Read<int32>(&ctoken);
964 
965 			// although this isn't pretty, ATM we have only one RootLayer.
966 			// there should be a way that this ServerApp be attached to a particular
967 			// RootLayer to know which RootLayer's cursor to modify.
968 			ServerCursor	*cursor;
969 			if ((cursor = gDesktop->ActiveRootLayer()->GetCursorManager().FindCursor(ctoken)))
970 				gDesktop->GetHWInterface()->SetCursor(cursor);
971 
972 			if (sync) {
973 				// the application is expecting a reply, but plans to do literally nothing
974 				// with the data, so we'll just reuse the cursor token variable
975 				fLink.StartMessage(SERVER_TRUE);
976 				fLink.Flush();
977 			}
978 			break;
979 		}
980 		case AS_CREATE_BCURSOR:
981 		{
982 			STRACE(("ServerApp %s: Create BCursor\n",fSignature.String()));
983 			// Attached data:
984 			// 1) 68 bytes of fAppCursor data
985 			// 2) port_id reply port
986 
987 			int8 cursorData[68];
988 			link.Read(cursorData, sizeof(cursorData));
989 
990 			fAppCursor = new ServerCursor(cursorData);
991 			fAppCursor->SetOwningTeam(fClientTeam);
992 			fAppCursor->SetAppSignature(fSignature.String());
993 			// although this isn't pretty, ATM we have only one RootLayer.
994 			// there should be a way that this ServerApp be attached to a particular
995 			// RootLayer to know which RootLayer's cursor to modify.
996 			gDesktop->ActiveRootLayer()->GetCursorManager().AddCursor(fAppCursor);
997 
998 			// Synchronous message - BApplication is waiting on the cursor's ID
999 			fLink.StartMessage(SERVER_TRUE);
1000 			fLink.Attach<int32>(fAppCursor->ID());
1001 			fLink.Flush();
1002 			break;
1003 		}
1004 		case AS_DELETE_BCURSOR:
1005 		{
1006 			STRACE(("ServerApp %s: Delete BCursor\n", fSignature.String()));
1007 			// Attached data:
1008 			// 1) int32 token ID of the cursor to delete
1009 			int32 ctoken = B_NULL_TOKEN;
1010 			link.Read<int32>(&ctoken);
1011 
1012 			if (fAppCursor && fAppCursor->ID() == ctoken)
1013 				fAppCursor = NULL;
1014 
1015 			// although this isn't pretty, ATM we have only one RootLayer.
1016 			// there should be a way that this ServerApp be attached to a particular
1017 			// RootLayer to know which RootLayer's cursor to modify.
1018 			gDesktop->ActiveRootLayer()->GetCursorManager().DeleteCursor(ctoken);
1019 			break;
1020 		}
1021 		case AS_GET_SCROLLBAR_INFO:
1022 		{
1023 			STRACE(("ServerApp %s: Get ScrollBar info\n", fSignature.String()));
1024 			scroll_bar_info info = gDesktop->ScrollBarInfo();
1025 
1026 			fLink.StartMessage(SERVER_TRUE);
1027 			fLink.Attach<scroll_bar_info>(info);
1028 			fLink.Flush();
1029 			break;
1030 		}
1031 		case AS_SET_SCROLLBAR_INFO:
1032 		{
1033 			STRACE(("ServerApp %s: Set ScrollBar info\n", fSignature.String()));
1034 			// Attached Data:
1035 			// 1) scroll_bar_info scroll bar info structure
1036 			scroll_bar_info info;
1037 			if (link.Read<scroll_bar_info>(&info) == B_OK)
1038 				gDesktop->SetScrollBarInfo(info);
1039 			break;
1040 		}
1041 		case AS_FOCUS_FOLLOWS_MOUSE:
1042 		{
1043 			STRACE(("ServerApp %s: query Focus Follow Mouse in use\n", fSignature.String()));
1044 
1045 			fLink.StartMessage(SERVER_TRUE);
1046 			fLink.Attach<bool>(gDesktop->FFMouseInUse());
1047 			fLink.Flush();
1048 			break;
1049 		}
1050 		case AS_SET_FOCUS_FOLLOWS_MOUSE:
1051 		{
1052 			STRACE(("ServerApp %s: Set Focus Follows Mouse in use\n", fSignature.String()));
1053 			// ToDo: implement me!
1054 			break;
1055 		}
1056 		case AS_SET_MOUSE_MODE:
1057 		{
1058 			STRACE(("ServerApp %s: Set Focus Follows Mouse mode\n", fSignature.String()));
1059 			// Attached Data:
1060 			// 1) enum mode_mouse FFM mouse mode
1061 			mode_mouse mmode;
1062 			if (link.Read<mode_mouse>(&mmode) == B_OK)
1063 				gDesktop->SetFFMouseMode(mmode);
1064 			break;
1065 		}
1066 		case AS_GET_MOUSE_MODE:
1067 		{
1068 			STRACE(("ServerApp %s: Get Focus Follows Mouse mode\n", fSignature.String()));
1069 			mode_mouse mmode = gDesktop->FFMouseMode();
1070 
1071 			fLink.StartMessage(SERVER_TRUE);
1072 			fLink.Attach<mode_mouse>(mmode);
1073 			fLink.Flush();
1074 			break;
1075 		}
1076 		case AS_GET_UI_COLORS:
1077 		{
1078 			// Client application is asking for all the system colors at once
1079 			// using a ColorSet object
1080 
1081 
1082 			gGUIColorSet.Lock();
1083 
1084 			fLink.StartMessage(SERVER_TRUE);
1085 			fLink.Attach<ColorSet>(gGUIColorSet);
1086 			fLink.Flush();
1087 
1088 			gGUIColorSet.Unlock();
1089 
1090 			break;
1091 		}
1092 		case AS_SET_UI_COLORS:
1093 		{
1094 			// Client application is asking to set all the system colors at once
1095 			// using a ColorSet object
1096 
1097 			// Attached data:
1098 			// 1) ColorSet new colors to use
1099 
1100 			gGUIColorSet.Lock();
1101 			link.Read<ColorSet>(&gGUIColorSet);
1102 			gGUIColorSet.Unlock();
1103 
1104 			BroadcastToAllApps(AS_UPDATE_COLORS);
1105 			break;
1106 		}
1107 		case AS_GET_UI_COLOR:
1108 		{
1109 			STRACE(("ServerApp %s: Get UI color\n", fSignature.String()));
1110 
1111 			RGBColor color;
1112 			int32 whichColor;
1113 			link.Read<int32>(&whichColor);
1114 
1115 			gGUIColorSet.Lock();
1116 			color = gGUIColorSet.AttributeToColor(whichColor);
1117 			gGUIColorSet.Unlock();
1118 
1119 			fLink.StartMessage(SERVER_TRUE);
1120 			fLink.Attach<rgb_color>(color.GetColor32());
1121 			fLink.Flush();
1122 			break;
1123 		}
1124 
1125 		case AS_UPDATED_CLIENT_FONTLIST:
1126 		{
1127 			STRACE(("ServerApp %s: Acknowledged update of client-side font list\n",
1128 				fSignature.String()));
1129 
1130 			// received when the client-side global font list has been
1131 			// refreshed
1132 			gFontServer->Lock();
1133 			gFontServer->FontsUpdated();
1134 			gFontServer->Unlock();
1135 			break;
1136 		}
1137 		case AS_QUERY_FONTS_CHANGED:
1138 		{
1139 			FTRACE(("ServerApp %s: AS_QUERY_FONTS_CHANGED unimplemented\n",
1140 				fSignature.String()));
1141 			// Attached Data:
1142 			// 1) bool check flag
1143 
1144 			// if just checking, just give an answer,
1145 			// if not and needs updated,
1146 			// sync the font list and return true else return false
1147 			fLink.StartMessage(SERVER_FALSE);
1148 			fLink.Flush();
1149 			break;
1150 		}
1151 		case AS_GET_FAMILY_NAME:
1152 		{
1153 			FTRACE(("ServerApp %s: AS_GET_FAMILY_NAME\n", fSignature.String()));
1154 			// Attached Data:
1155 			// 1) int32 the ID of the font family to get
1156 
1157 			// Returns:
1158 			// 1) font_family - name of family
1159 			// 2) uint32 - flags of font family (B_IS_FIXED || B_HAS_TUNED_FONT)
1160 			int32 id;
1161 			link.Read<int32>(&id);
1162 
1163 			gFontServer->Lock();
1164 			FontFamily *ffamily = gFontServer->GetFamily(id);
1165 			if (ffamily) {
1166 				font_family fam;
1167 				strcpy(fam, ffamily->Name());
1168 				fLink.Attach(fam, sizeof(font_family));
1169 				fLink.Attach<int32>(ffamily->GetFlags());
1170 			} else
1171 				fLink.StartMessage(SERVER_FALSE);
1172 
1173 			fLink.Flush();
1174 			gFontServer->Unlock();
1175 			break;
1176 		}
1177 		case AS_GET_STYLE_NAME:
1178 		{
1179 			FTRACE(("ServerApp %s: AS_GET_STYLE_NAME\n", fSignature.String()));
1180 			// Attached Data:
1181 			// 1) font_family The name of the font family
1182 			// 2) int32 ID of the style to get
1183 
1184 			// Returns:
1185 			// 1) font_style - name of the style
1186 			// 2) uint16 - appropriate face values
1187 			// 3) uint32 - flags of font style (B_IS_FIXED || B_HAS_TUNED_FONT)
1188 
1189 			int32 styid;
1190 			font_family fam;
1191 
1192 			link.Read(fam,sizeof(font_family));
1193 			link.Read<int32>(&styid);
1194 
1195 			gFontServer->Lock();
1196 			FontStyle *fstyle = gFontServer->GetStyle(fam, styid);
1197 			if (fstyle) {
1198 				font_family sty;
1199 				strcpy(sty, fstyle->Name());
1200 				fLink.StartMessage(SERVER_TRUE);
1201 				fLink.Attach(sty,sizeof(font_style));
1202 				fLink.Attach<int32>(fstyle->GetFace());
1203 				fLink.Attach<int32>(fstyle->GetFlags());
1204 			} else
1205 				fLink.StartMessage(SERVER_FALSE);
1206 
1207 			fLink.Flush();
1208 			gFontServer->Unlock();
1209 			break;
1210 		}
1211 		case AS_GET_FAMILY_AND_STYLE:
1212 		{
1213 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE\n",fSignature.String()));
1214 			// Attached Data:
1215 			// 1) uint16 - family ID
1216 			// 2) uint16 - style ID
1217 
1218 			// Returns:
1219 			// 1) font_family The name of the font family
1220 			// 2) font_style - name of the style
1221 			uint16 famid, styid;
1222 			font_family fam;
1223 			font_style sty;
1224 
1225 			link.Read<uint16>(&famid);
1226 			link.Read<uint16>(&styid);
1227 
1228 			gFontServer->Lock();
1229 			FontStyle *fstyle = gFontServer->GetStyle(famid, styid);
1230 			if (fstyle) {
1231 				strcpy(fam, fstyle->Family()->Name());
1232 				strcpy(sty, fstyle->Name());
1233 
1234 				fLink.StartMessage(SERVER_TRUE);
1235 				fLink.Attach(fam, sizeof(font_family));
1236 				fLink.Attach(sty, sizeof(font_style));
1237 			} else
1238 				fLink.StartMessage(SERVER_FALSE);
1239 
1240 			fLink.Flush();
1241 			gFontServer->Unlock();
1242 			break;
1243 		}
1244 		case AS_GET_FONT_DIRECTION:
1245 		{
1246 			FTRACE(("ServerApp %s: AS_GET_FONT_DIRECTION unimplemented\n",
1247 				fSignature.String()));
1248 			// Attached Data:
1249 			// 1) uint16 - family ID
1250 			// 2) uint16 - style ID
1251 
1252 			// Returns:
1253 			// 1) font_direction direction of font
1254 
1255 			// NOTE: While this may be unimplemented, we can safely return
1256 			// SERVER_FALSE. This will force the BFont code to default to
1257 			// B_LEFT_TO_RIGHT, which is what the vast majority of fonts will be.
1258 			// This will be fixed later.
1259 			int32 famid, styid;
1260 			link.Read<int32>(&famid);
1261 			link.Read<int32>(&styid);
1262 
1263 /*			gFontServer->Lock();
1264 			FontStyle *fstyle=gFontServer->GetStyle(famid,styid);
1265 			if(fstyle)
1266 			{
1267 				font_direction dir=fstyle->GetDirection();
1268 
1269 				fLink.StartMessage(SERVER_TRUE);
1270 				fLink.Attach<font_direction>(dir);
1271 				fLink.Flush();
1272 			}
1273 			else
1274 			{
1275 */				fLink.StartMessage(SERVER_FALSE);
1276 				fLink.Flush();
1277 //			}
1278 
1279 //			gFontServer->Unlock();
1280 			break;
1281 		}
1282 		case AS_GET_STRING_WIDTH:
1283 		{
1284 			FTRACE(("ServerApp %s: AS_GET_STRING_WIDTH\n", fSignature.String()));
1285 			// Attached Data:
1286 			// 1) string String to measure
1287 			// 2) int32 string length to measure
1288 			// 3) uint16 ID of family
1289 			// 4) uint16 ID of style
1290 			// 5) float point size of font
1291 			// 6) uint8 spacing to use
1292 
1293 			// Returns:
1294 			// 1) float - width of the string in pixels
1295 			char *string = NULL;
1296 			int32 length;
1297 			uint16 family, style;
1298 			float size, width = 0;
1299 			uint8 spacing;
1300 
1301 			link.ReadString(&string);
1302 			link.Read<int32>(&length);
1303 			link.Read<uint16>(&family);
1304 			link.Read<uint16>(&style);
1305 			link.Read<float>(&size);
1306 			link.Read<uint8>(&spacing);
1307 
1308 			ServerFont font;
1309 
1310 			if (length > 0 && font.SetFamilyAndStyle(family, style) == B_OK
1311 				&& size > 0 && string) {
1312 
1313 				font.SetSize(size);
1314 				font.SetSpacing(spacing);
1315 
1316 				width = gDesktop->GetDisplayDriver()->StringWidth(string, length, font);
1317 				// NOTE: The line below will return the exact same thing. However,
1318 				// the line above uses the AGG rendering backend, for which glyph caching
1319 				// actually works. It is about 20 times faster!
1320 				//width = font.StringWidth(string, length);
1321 
1322 				fLink.StartMessage(SERVER_TRUE);
1323 				fLink.Attach<float>(width);
1324 			} else
1325 				fLink.StartMessage(SERVER_FALSE);
1326 
1327 			fLink.Flush();
1328 			free(string);
1329 			break;
1330 		}
1331 		case AS_GET_FONT_BOUNDING_BOX:
1332 		{
1333 			FTRACE(("ServerApp %s: AS_GET_BOUNDING_BOX unimplemented\n",
1334 				fSignature.String()));
1335 			// Attached Data:
1336 			// 1) uint16 - family ID
1337 			// 2) uint16 - style ID
1338 
1339 			// Returns:
1340 			// 1) BRect - box holding entire font
1341 
1342 			// ToDo: implement me!
1343 			fLink.StartMessage(SERVER_FALSE);
1344 			fLink.Flush();
1345 			break;
1346 		}
1347 		case AS_GET_TUNED_COUNT:
1348 		{
1349 			FTRACE(("ServerApp %s: AS_GET_TUNED_COUNT\n", fSignature.String()));
1350 			// Attached Data:
1351 			// 1) uint16 - family ID
1352 			// 2) uint16 - style ID
1353 
1354 			// Returns:
1355 			// 1) int32 - number of font strikes available
1356 			uint16 famid, styid;
1357 			link.Read<uint16>(&famid);
1358 			link.Read<uint16>(&styid);
1359 
1360 			gFontServer->Lock();
1361 			FontStyle *fstyle = gFontServer->GetStyle(famid, styid);
1362 			if (fstyle) {
1363 				fLink.StartMessage(SERVER_TRUE);
1364 				fLink.Attach<int32>(fstyle->TunedCount());
1365 			} else
1366 				fLink.StartMessage(SERVER_FALSE);
1367 
1368 			fLink.Flush();
1369 			gFontServer->Unlock();
1370 			break;
1371 		}
1372 		case AS_GET_TUNED_INFO:
1373 		{
1374 			FTRACE(("ServerApp %s: AS_GET_TUNED_INFO unimplmemented\n",
1375 				fSignature.String()));
1376 			// Attached Data:
1377 			// 1) uint16 - family ID
1378 			// 2) uint16 - style ID
1379 			// 3) uint32 - index of the particular font strike
1380 
1381 			// Returns:
1382 			// 1) tuned_font_info - info on the strike specified
1383 			// ToDo: implement me!
1384 			fLink.StartMessage(SERVER_FALSE);
1385 			fLink.Flush();
1386 			break;
1387 		}
1388 		case AS_QUERY_FONT_FIXED:
1389 		{
1390 			FTRACE(("ServerApp %s: AS_QUERY_FONT_FIXED unimplmemented\n",
1391 				fSignature.String()));
1392 			// Attached Data:
1393 			// 1) uint16 - family ID
1394 			// 2) uint16 - style ID
1395 
1396 			// Returns:
1397 			// 1) bool - font is/is not fixed
1398 			uint16 famid, styid;
1399 			link.Read<uint16>(&famid);
1400 			link.Read<uint16>(&styid);
1401 
1402 			gFontServer->Lock();
1403 			FontStyle *fstyle = gFontServer->GetStyle(famid, styid);
1404 			if (fstyle) {
1405 				fLink.StartMessage(SERVER_TRUE);
1406 				fLink.Attach<bool>(fstyle->IsFixedWidth());
1407 			} else
1408 				fLink.StartMessage(SERVER_FALSE);
1409 
1410 			fLink.Flush();
1411 			gFontServer->Unlock();
1412 			break;
1413 		}
1414 		case AS_SET_FAMILY_NAME:
1415 		{
1416 			FTRACE(("ServerApp %s: AS_SET_FAMILY_NAME\n", fSignature.String()));
1417 			// Attached Data:
1418 			// 1) font_family - name of font family to use
1419 
1420 			// Returns:
1421 			// 1) uint16 - family ID
1422 
1423 			font_family fam;
1424 			link.Read(fam, sizeof(font_family));
1425 
1426 			gFontServer->Lock();
1427 			FontFamily *ffam = gFontServer->GetFamily(fam);
1428 			if (ffam) {
1429 				fLink.StartMessage(SERVER_TRUE);
1430 				fLink.Attach<uint16>(ffam->GetID());
1431 			} else
1432 				fLink.StartMessage(SERVER_FALSE);
1433 
1434 			fLink.Flush();
1435 			gFontServer->Unlock();
1436 			break;
1437 		}
1438 		case AS_SET_FAMILY_AND_STYLE:
1439 		{
1440 			FTRACE(("ServerApp %s: AS_SET_FAMILY_AND_STYLE\n",
1441 				fSignature.String()));
1442 			// Attached Data:
1443 			// 1) font_family - name of font family to use
1444 			// 2) font_style - name of style in family
1445 
1446 			// Returns:
1447 			// 1) uint16 - family ID
1448 			// 2) uint16 - style ID
1449 
1450 			font_family fam;
1451 			font_style sty;
1452 			link.Read(fam, sizeof(font_family));
1453 			link.Read(sty, sizeof(font_style));
1454 
1455 			gFontServer->Lock();
1456 			FontStyle *fstyle = gFontServer->GetStyle(fam, sty);
1457 			if (fstyle) {
1458 				fLink.StartMessage(SERVER_TRUE);
1459 				fLink.Attach<uint16>(fstyle->Family()->GetID());
1460 				fLink.Attach<uint16>(fstyle->GetID());
1461 			} else
1462 				fLink.StartMessage(SERVER_FALSE);
1463 
1464 			fLink.Flush();
1465 			gFontServer->Unlock();
1466 			break;
1467 		}
1468 		case AS_SET_FAMILY_AND_STYLE_FROM_ID:
1469 		{
1470 			FTRACE(("ServerApp %s: AS_SET_FAMILY_AND_STYLE_FROM_ID\n",
1471 				fSignature.String()));
1472 			// Attached Data:
1473 			// 1) uint16 - ID of font family to use
1474 			// 2) uint16 - ID of style in family
1475 
1476 			// Returns:
1477 			// 1) uint16 - face of the font
1478 
1479 			uint16 fam, sty;
1480 			link.Read<uint16>(&fam);
1481 			link.Read<uint16>(&sty);
1482 
1483 			ServerFont font;
1484 			if (font.SetFamilyAndStyle(fam, sty) == B_OK) {
1485 				fLink.StartMessage(SERVER_TRUE);
1486 				fLink.Attach<uint16>(font.Face());
1487 			} else
1488 				fLink.StartMessage(SERVER_FALSE);
1489 
1490 			fLink.Flush();
1491 			break;
1492 		}
1493 		case AS_SET_FAMILY_AND_FACE:
1494 		{
1495 			FTRACE(("ServerApp %s: AS_SET_FAMILY_AND_FACE unimplmemented\n",
1496 				fSignature.String()));
1497 			// Attached Data:
1498 			// 1) font_family - name of font family to use
1499 			// 2) uint16 - font face
1500 
1501 			// Returns:
1502 			// 1) uint16 - family ID
1503 			// 2) uint16 - style ID
1504 
1505 			// TODO: Check R5 for error condition behavior in SET_FAMILY_AND_FACE
1506 			// ToDo: implement me!
1507 			fLink.StartMessage(SERVER_FALSE);
1508 			fLink.Flush();
1509 			break;
1510 		}
1511 		case AS_COUNT_FONT_FAMILIES:
1512 		{
1513 			FTRACE(("ServerApp %s: AS_COUNT_FONT_FAMILIES\n", fSignature.String()));
1514 			// Returns:
1515 			// 1) int32 - # of font families
1516 
1517 			gFontServer->Lock();
1518 
1519 			fLink.StartMessage(SERVER_TRUE);
1520 			fLink.Attach<int32>(gFontServer->CountFamilies());
1521 			fLink.Flush();
1522 
1523 			gFontServer->Unlock();
1524 			break;
1525 		}
1526 		case AS_COUNT_FONT_STYLES:
1527 		{
1528 			FTRACE(("ServerApp %s: AS_COUNT_FONT_STYLES\n", fSignature.String()));
1529 			// Attached Data:
1530 			// 1) font_family - name of font family
1531 
1532 			// Returns:
1533 			// 1) int32 - # of font styles
1534 			font_family fam;
1535 			link.Read(fam,sizeof(font_family));
1536 
1537 			gFontServer->Lock();
1538 			FontFamily *ffam = gFontServer->GetFamily(fam);
1539 			if (ffam) {
1540 				fLink.StartMessage(SERVER_TRUE);
1541 				fLink.Attach<int32>(ffam->CountStyles());
1542 			} else
1543 				fLink.StartMessage(SERVER_FALSE);
1544 
1545 			fLink.Flush();
1546 			gFontServer->Unlock();
1547 			break;
1548 		}
1549 		case AS_SET_SYSFONT_PLAIN:
1550 		{
1551 			FTRACE(("ServerApp %s: AS_SET_SYSFONT_PLAIN\n", fSignature.String()));
1552 			// Returns:
1553 			// 1) uint16 - family ID
1554 			// 2) uint16 - style ID
1555 			// 3) float - size in points
1556 			// 4) uint16 - face flags
1557 			// 5) uint32 - font flags
1558 
1559 			gFontServer->Lock();
1560 			ServerFont *sf = gFontServer->GetSystemPlain();
1561 			if (sf) {
1562 				fLink.StartMessage(SERVER_TRUE);
1563 				fLink.Attach<uint16>(sf->FamilyID());
1564 				fLink.Attach<uint16>(sf->StyleID());
1565 				fLink.Attach<float>(sf->Size());
1566 				fLink.Attach<uint16>(sf->Face());
1567 				fLink.Attach<uint32>(sf->Flags());
1568 			} else
1569 				fLink.StartMessage(SERVER_FALSE);
1570 
1571 			fLink.Flush();
1572 			gFontServer->Unlock();
1573 			break;
1574 		}
1575 		case AS_GET_FONT_HEIGHT:
1576 		{
1577 			FTRACE(("ServerApp %s: AS_GET_FONT_HEIGHT\n", fSignature.String()));
1578 			// Attached Data:
1579 			// 1) uint16 family ID
1580 			// 2) uint16 style ID
1581 			// 3) float size
1582 			uint16 famid,styid;
1583 			float ptsize;
1584 			link.Read<uint16>(&famid);
1585 			link.Read<uint16>(&styid);
1586 			link.Read<float>(&ptsize);
1587 
1588 			gFontServer->Lock();
1589 			FontStyle *fstyle = gFontServer->GetStyle(famid, styid);
1590 			if (fstyle) {
1591 				fLink.StartMessage(SERVER_TRUE);
1592 				fLink.Attach<font_height>(fstyle->GetHeight(ptsize));
1593 			} else
1594 				fLink.StartMessage(SERVER_FALSE);
1595 
1596 			fLink.Flush();
1597 			gFontServer->Unlock();
1598 			break;
1599 		}
1600 		case AS_SET_SYSFONT_BOLD:
1601 		{
1602 			FTRACE(("ServerApp %s: AS_SET_SYSFONT_BOLD\n", fSignature.String()));
1603 			// Returns:
1604 			// 1) uint16 - family ID
1605 			// 2) uint16 - style ID
1606 			// 3) float - size in points
1607 			// 4) uint16 - face flags
1608 			// 5) uint32 - font flags
1609 
1610 			gFontServer->Lock();
1611 			ServerFont *sf = gFontServer->GetSystemBold();
1612 			if (sf) {
1613 				fLink.StartMessage(SERVER_TRUE);
1614 				fLink.Attach<uint16>(sf->FamilyID());
1615 				fLink.Attach<uint16>(sf->StyleID());
1616 				fLink.Attach<float>(sf->Size());
1617 				fLink.Attach<uint16>(sf->Face());
1618 				fLink.Attach<uint32>(sf->Flags());
1619 			} else
1620 				fLink.StartMessage(SERVER_FALSE);
1621 
1622 			fLink.Flush();
1623 			gFontServer->Unlock();
1624 			break;
1625 		}
1626 		case AS_SET_SYSFONT_FIXED:
1627 		{
1628 			FTRACE(("ServerApp %s: AS_SET_SYSFONT_FIXED\n", fSignature.String()));
1629 			// Returns:
1630 			// 1) uint16 - family ID
1631 			// 2) uint16 - style ID
1632 			// 3) float - size in points
1633 			// 4) uint16 - face flags
1634 			// 5) uint32 - font flags
1635 
1636 			gFontServer->Lock();
1637 			ServerFont *sf = gFontServer->GetSystemFixed();
1638 			if (sf) {
1639 				fLink.StartMessage(SERVER_TRUE);
1640 				fLink.Attach<uint16>(sf->FamilyID());
1641 				fLink.Attach<uint16>(sf->StyleID());
1642 				fLink.Attach<float>(sf->Size());
1643 				fLink.Attach<uint16>(sf->Face());
1644 				fLink.Attach<uint32>(sf->Flags());
1645 			} else
1646 				fLink.StartMessage(SERVER_FALSE);
1647 
1648 			fLink.Flush();
1649 			gFontServer->Unlock();
1650 			break;
1651 		}
1652 		case AS_GET_GLYPH_SHAPES:
1653 		{
1654 			FTRACE(("ServerApp %s: AS_GET_GLYPH_SHAPES\n", fSignature.String()));
1655 			// Attached Data:
1656 			// 1) uint16 - family ID
1657 			// 2) uint16 - style ID
1658 			// 3) float - point size
1659 			// 4) float - shear
1660 			// 5) float - rotation
1661 			// 6) uint32 - flags
1662 			// 7) int32 - numChars
1663 			// 8) char - chars (numChars times)
1664 
1665 			// Returns:
1666 			// 1) BShape - glyph shape
1667 			// numChars times
1668 
1669 			uint16 famid, styid;
1670 			uint32 flags;
1671 			float ptsize, shear, rotation;
1672 
1673 			link.Read<uint16>(&famid);
1674 			link.Read<uint16>(&styid);
1675 			link.Read<float>(&ptsize);
1676 			link.Read<float>(&shear);
1677 			link.Read<float>(&rotation);
1678 			link.Read<uint32>(&flags);
1679 
1680 			int32 numChars;
1681 			link.Read<int32>(&numChars);
1682 
1683 			char charArray[numChars];
1684 			for (int32 i = 0; i < numChars; i++)
1685 				link.Read<char>(&charArray[i]);
1686 
1687 			ServerFont font;
1688 			if (font.SetFamilyAndStyle(famid, styid) == B_OK) {
1689 				font.SetSize(ptsize);
1690 				font.SetShear(shear);
1691 				font.SetRotation(rotation);
1692 				font.SetFlags(flags);
1693 
1694 				BShape **shapes = font.GetGlyphShapes(charArray, numChars);
1695 				if (shapes) {
1696 					fLink.StartMessage(SERVER_TRUE);
1697 					for (int32 i = 0; i < numChars; i++) {
1698 						fLink.AttachShape(*shapes[i]);
1699 						delete shapes[i];
1700 					}
1701 
1702 					delete shapes;
1703 				} else
1704 					fLink.StartMessage(SERVER_FALSE);
1705 			} else
1706 				fLink.StartMessage(SERVER_FALSE);
1707 
1708 			fLink.Flush();
1709 			break;
1710 		}
1711 		case AS_GET_ESCAPEMENTS:
1712 		{
1713 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS\n", fSignature.String()));
1714 			// Attached Data:
1715 			// 1) uint16 - family ID
1716 			// 2) uint16 - style ID
1717 			// 3) float - point size
1718 			// 4) float - rotation
1719 			// 5) uint32 - flags
1720 			// 6) int32 - numChars
1721 			// 7) char - char     -\       both
1722 			// 8) BPoint - offset -/ (numChars times)
1723 
1724 			// Returns:
1725 			// 1) BPoint - escapement
1726 			// numChars times
1727 
1728 			uint16 famid, styid;
1729 			uint32 flags;
1730 			float ptsize, rotation;
1731 
1732 			link.Read<uint16>(&famid);
1733 			link.Read<uint16>(&styid);
1734 			link.Read<float>(&ptsize);
1735 			link.Read<float>(&rotation);
1736 			link.Read<uint32>(&flags);
1737 
1738 			int32 numChars;
1739 			link.Read<int32>(&numChars);
1740 
1741 			char charArray[numChars];
1742 			BPoint offsetArray[numChars];
1743 			for (int32 i = 0; i < numChars; i++) {
1744 				link.Read<char>(&charArray[i]);
1745 				link.Read<BPoint>(&offsetArray[i]);
1746 			}
1747 
1748 			ServerFont font;
1749 			if (font.SetFamilyAndStyle(famid, styid) == B_OK) {
1750 				font.SetSize(ptsize);
1751 				font.SetRotation(rotation);
1752 				font.SetFlags(flags);
1753 
1754 				BPoint *esc = font.GetEscapements(charArray, numChars, offsetArray);
1755 				if (esc) {
1756 					fLink.StartMessage(SERVER_TRUE);
1757 					for (int32 i = 0; i < numChars; i++) {
1758 						fLink.Attach<BPoint>(esc[i]);
1759 					}
1760 
1761 					delete esc;
1762 				} else
1763 					fLink.StartMessage(SERVER_FALSE);
1764 			} else
1765 				fLink.StartMessage(SERVER_FALSE);
1766 
1767 			fLink.Flush();
1768 			break;
1769 		}
1770 		case AS_GET_ESCAPEMENTS_AS_FLOATS:
1771 		{
1772 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS_AS_FLOATS\n", fSignature.String()));
1773 			// Attached Data:
1774 			// 1) uint16 - family ID
1775 			// 2) uint16 - style ID
1776 			// 3) float - point size
1777 			// 4) float - rotation
1778 			// 5) uint32 - flags
1779 
1780 			// 6) float - additional "nonspace" delta
1781 			// 7) float - additional "space" delta
1782 
1783 			// 8) int32 - numChars
1784 			// 9) int32 - numBytes
1785 			// 10) char - the char buffer with size numBytes
1786 
1787 			// Returns:
1788 			// 1) float - escapement buffer with numChar entries
1789 
1790 			uint16 famid, styid;
1791 			uint32 flags;
1792 			float ptsize, rotation;
1793 
1794 			link.Read<uint16>(&famid);
1795 			link.Read<uint16>(&styid);
1796 			link.Read<float>(&ptsize);
1797 			link.Read<float>(&rotation);
1798 			link.Read<uint32>(&flags);
1799 
1800 			escapement_delta delta;
1801 			link.Read<float>(&delta.nonspace);
1802 			link.Read<float>(&delta.space);
1803 
1804 			int32 numChars;
1805 			link.Read<int32>(&numChars);
1806 
1807 			uint32 numBytes;
1808 			link.Read<uint32>(&numBytes);
1809 
1810 			char* charArray = new char[numBytes];
1811 			link.Read(charArray, numBytes);
1812 
1813 			float* escapements = new float[numChars];
1814 			// figure out escapements
1815 
1816 			ServerFont font;
1817 			bool success = false;
1818 			if (font.SetFamilyAndStyle(famid, styid) == B_OK) {
1819 				font.SetSize(ptsize);
1820 				font.SetRotation(rotation);
1821 				font.SetFlags(flags);
1822 
1823 				if (font.GetEscapements(charArray, numChars, escapements, delta)) {
1824 					fLink.StartMessage(SERVER_TRUE);
1825 					fLink.Attach(escapements, numChars * sizeof(float));
1826 					success = true;
1827 				}
1828 			}
1829 
1830 			delete[] charArray;
1831 			delete[] escapements;
1832 
1833 			if (!success)
1834 				fLink.StartMessage(SERVER_FALSE);
1835 
1836 			fLink.Flush();
1837 			break;
1838 		}
1839 		case AS_SCREEN_GET_MODE:
1840 		{
1841 			STRACE(("ServerApp %s: AS_SCREEN_GET_MODE\n", fSignature.String()));
1842 			// Attached data
1843 			// 1) int32 port to reply to
1844 			// 2) screen_id
1845 			// 3) workspace index
1846 			screen_id id;
1847 			link.Read<screen_id>(&id);
1848 			uint32 workspace;
1849 			link.Read<uint32>(&workspace);
1850 
1851 			// TODO: the display_mode can be different between
1852 			// the various screens.
1853 			// We have the screen_id and the workspace number, with these
1854 			// we need to find the corresponding "driver", and call getmode on it
1855 			display_mode mode;
1856 			gDesktop->ScreenAt(0)->GetMode(&mode);
1857 			// actually this isn't still enough as different workspaces can
1858 			// have different display_modes
1859 
1860 			fLink.StartMessage(SERVER_TRUE);
1861 			fLink.Attach<display_mode>(mode);
1862 			fLink.Attach<status_t>(B_OK);
1863 			fLink.Flush();
1864 			break;
1865 		}
1866 		case AS_SCREEN_SET_MODE:
1867 		{
1868 			STRACE(("ServerApp %s: AS_SCREEN_SET_MODE\n", fSignature.String()));
1869 			// Attached data
1870 			// 1) int32 port to reply to
1871 			// 2) screen_id
1872 			// 3) workspace index
1873 			// 4) display_mode to set
1874 			// 5) 'makedefault' boolean
1875 			// TODO: See above: workspaces support, etc.
1876 
1877 			screen_id id;
1878 			link.Read<screen_id>(&id);
1879 
1880 			uint32 workspace;
1881 			link.Read<uint32>(&workspace);
1882 
1883 			display_mode mode;
1884 			link.Read<display_mode>(&mode);
1885 
1886 			bool makedefault = false;
1887 			link.Read<bool>(&makedefault);
1888 
1889 // TODO: lock RootLayer, set mode and tell it to update it's frame and all clipping
1890 // optionally put this into a message and let the root layer thread handle it.
1891 //			status_t ret = gDesktop->ScreenAt(0)->SetMode(mode);
1892 status_t ret = B_ERROR;
1893 
1894 			fLink.StartMessage(SERVER_TRUE);
1895 			fLink.Attach<status_t>(ret);
1896 			fLink.Flush();
1897 			break;
1898 		}
1899 
1900 		case AS_PROPOSE_MODE:
1901 		{
1902 			STRACE(("ServerApp %s: AS_PROPOSE_MODE\n", fSignature.String()));
1903 			screen_id id;
1904 			link.Read<screen_id>(&id);
1905 
1906 			display_mode target, low, high;
1907 			link.Read<display_mode>(&target);
1908 			link.Read<display_mode>(&low);
1909 			link.Read<display_mode>(&high);
1910 			status_t status = gDesktop->GetHWInterface()->ProposeMode(&target, &low, &high);
1911 			// TODO: We always return SERVER_TRUE and put the real
1912 			// error code in the message. FIX this.
1913 			fLink.StartMessage(SERVER_TRUE);
1914 			fLink.Attach<display_mode>(target);
1915 			fLink.Attach<status_t>(status);
1916 			fLink.Flush();
1917 
1918 			break;
1919 		}
1920 
1921 		case AS_GET_MODE_LIST:
1922 		{
1923 			display_mode* modeList;
1924 			uint32 count;
1925 			if (gDesktop->GetHWInterface()->GetModeList(&modeList, &count) == B_OK) {
1926 				fLink.StartMessage(SERVER_TRUE);
1927 				fLink.Attach<uint32>(count);
1928 				fLink.Attach(modeList, sizeof(display_mode) * count);
1929 
1930 				delete[] modeList;
1931 			} else
1932 				fLink.StartMessage(SERVER_FALSE);
1933 
1934 			fLink.Flush();
1935 			break;
1936 		}
1937 
1938 		case AS_SCREEN_GET_COLORMAP:
1939 		{
1940 			STRACE(("ServerApp %s: AS_SCREEN_GET_COLORMAP\n", fSignature.String()));
1941 
1942 			screen_id id;
1943 			link.Read<screen_id>(&id);
1944 
1945 			const color_map *colorMap = SystemColorMap();
1946 			if (colorMap != NULL) {
1947 				fLink.StartMessage(SERVER_TRUE);
1948 				fLink.Attach<color_map>(*colorMap);
1949 			} else
1950 				fLink.StartMessage(SERVER_FALSE);
1951 
1952 			fLink.Flush();
1953 			break;
1954 		}
1955 
1956 		case AS_GET_DESKTOP_COLOR:
1957 		{
1958 			STRACE(("ServerApp %s: get desktop color\n", fSignature.String()));
1959 
1960 			int32 workspaceIndex = 0;
1961 			link.Read<int32>(&workspaceIndex);
1962 
1963 			// ToDo: for some reason, we currently get "1" as no. of workspace
1964 			workspaceIndex = 0;
1965 
1966 			// ToDo: locking is probably wrong - why the hell is there no (safe)
1967 			//		way to get to the workspace object directly?
1968 			RootLayer *root = gDesktop->ActiveRootLayer();
1969 			root->Lock();
1970 
1971 			Workspace *workspace = root->WorkspaceAt(workspaceIndex);
1972 			if (workspace != NULL) {
1973 				fLink.StartMessage(SERVER_TRUE);
1974 				//rgb_color color;
1975 				fLink.Attach<rgb_color>(workspace->BGColor().GetColor32());
1976 			} else
1977 				fLink.StartMessage(SERVER_FALSE);
1978 
1979 			fLink.Flush();
1980 			root->Unlock();
1981 			break;
1982 		}
1983 
1984 		case AS_GET_ACCELERANT_INFO:
1985 		{
1986 			STRACE(("ServerApp %s: get accelerant info\n", fSignature.String()));
1987 
1988 			// We aren't using the screen_id for now...
1989 			screen_id id;
1990 			link.Read<screen_id>(&id);
1991 
1992 			accelerant_device_info accelerantInfo;
1993 			// TODO: I wonder if there should be a "desktop" lock...
1994 			if (gDesktop->GetHWInterface()->GetDeviceInfo(&accelerantInfo) == B_OK) {
1995 				fLink.StartMessage(SERVER_TRUE);
1996 				fLink.Attach<accelerant_device_info>(accelerantInfo);
1997 			} else
1998 				fLink.StartMessage(SERVER_FALSE);
1999 
2000 			fLink.Flush();
2001 
2002 			break;
2003 		}
2004 
2005 		case AS_GET_RETRACE_SEMAPHORE:
2006 		{
2007 			STRACE(("ServerApp %s: get retrace semaphore\n", fSignature.String()));
2008 
2009 			// We aren't using the screen_id for now...
2010 			screen_id id;
2011 			link.Read<screen_id>(&id);
2012 
2013 			sem_id semaphore = gDesktop->GetHWInterface()->RetraceSemaphore();
2014 			fLink.StartMessage(SERVER_TRUE);
2015 			fLink.Attach<sem_id>(semaphore);
2016 			fLink.Flush();
2017 
2018 			break;
2019 		}
2020 
2021 		case AS_GET_TIMING_CONSTRAINTS:
2022 		{
2023 			STRACE(("ServerApp %s: get timing constraints\n", fSignature.String()));
2024 			// We aren't using the screen_id for now...
2025 			screen_id id;
2026 			link.Read<screen_id>(&id);
2027 			display_timing_constraints constraints;
2028 			if (gDesktop->GetHWInterface()->GetTimingConstraints(&constraints) == B_OK) {
2029 				fLink.StartMessage(SERVER_TRUE);
2030 				fLink.Attach<display_timing_constraints>(constraints);
2031 			} else
2032 				fLink.StartMessage(SERVER_FALSE);
2033 
2034 			fLink.Flush();
2035 
2036 			break;
2037 		}
2038 
2039 		case AS_GET_PIXEL_CLOCK_LIMITS:
2040 		{
2041 			STRACE(("ServerApp %s: get pixel clock limits\n", fSignature.String()));
2042 			// We aren't using the screen_id for now...
2043 			screen_id id;
2044 			link.Read<screen_id>(&id);
2045 			display_mode mode;
2046 			link.Read<display_mode>(&mode);
2047 
2048 			uint32 low, high;
2049 			if (gDesktop->GetHWInterface()->GetPixelClockLimits(&mode, &low, &high) == B_OK) {
2050 				fLink.StartMessage(SERVER_TRUE);
2051 				fLink.Attach<uint32>(low);
2052 				fLink.Attach<uint32>(high);
2053 			} else
2054 				fLink.StartMessage(SERVER_FALSE);
2055 
2056 			fLink.Flush();
2057 
2058 			break;
2059 		}
2060 
2061 		case AS_SET_DPMS:
2062 		{
2063 			STRACE(("ServerApp %s: AS_SET_DPMS\n", fSignature.String()));
2064 			screen_id id;
2065 			link.Read<screen_id>(&id);
2066 
2067 			uint32 mode;
2068 			link.Read<uint32>(&mode);
2069 
2070 			if (gDesktop->GetHWInterface()->SetDPMSMode(mode) == B_OK)
2071 				fLink.StartMessage(SERVER_TRUE);
2072 			else
2073 				fLink.StartMessage(SERVER_FALSE);
2074 
2075 			fLink.Flush();
2076 
2077 			break;
2078 		}
2079 
2080 		case AS_GET_DPMS_STATE:
2081 		{
2082 			STRACE(("ServerApp %s: AS_GET_DPMS_STATE\n", fSignature.String()));
2083 
2084 			screen_id id;
2085 			link.Read<screen_id>(&id);
2086 
2087 			uint32 state = gDesktop->GetHWInterface()->DPMSMode();
2088 			fLink.StartMessage(SERVER_TRUE);
2089 			fLink.Attach<uint32>(state);
2090 			fLink.Flush();
2091 
2092 			break;
2093 		}
2094 
2095 		case AS_GET_DPMS_CAPABILITIES:
2096 		{
2097 			STRACE(("ServerApp %s: AS_GET_DPMS_CAPABILITIES\n", fSignature.String()));
2098 			screen_id id;
2099 			link.Read<screen_id>(&id);
2100 
2101 			uint32 capabilities = gDesktop->GetHWInterface()->DPMSCapabilities();
2102 			fLink.StartMessage(SERVER_TRUE);
2103 			fLink.Attach<uint32>(capabilities);
2104 			fLink.Flush();
2105 			break;
2106 		}
2107 
2108 		default:
2109 			printf("ServerApp %s received unhandled message code offset %s\n",
2110 				fSignature.String(), MsgCodeToBString(code).String());
2111 
2112 			if (link.NeedsReply()) {
2113 				// the client is now blocking and waiting for a reply!
2114 				fLink.StartMessage(SERVER_FALSE);
2115 				fLink.Flush();
2116 			} else
2117 				puts("message doesn't need a reply!");
2118 			break;
2119 	}
2120 }
2121 
2122 
2123 void
2124 ServerApp::RemoveWindow(ServerWindow* window)
2125 {
2126 	BAutolock locker(fWindowListLock);
2127 
2128 	fWindowList.RemoveItem(window);
2129 }
2130 
2131 
2132 int32
2133 ServerApp::CountBitmaps() const
2134 {
2135 	return fBitmapList.CountItems();
2136 }
2137 
2138 
2139 /*!
2140 	\brief Looks up a ServerApp's ServerBitmap in its list
2141 	\param token ID token of the bitmap to find
2142 	\return The bitmap having that ID or NULL if not found
2143 */
2144 ServerBitmap *
2145 ServerApp::FindBitmap(int32 token) const
2146 {
2147 	for (int32 i = 0; i < fBitmapList.CountItems(); i++) {
2148 		ServerBitmap *bitmap = static_cast<ServerBitmap *>(fBitmapList.ItemAt(i));
2149 		if (bitmap && bitmap->Token() == token)
2150 			return bitmap;
2151 	}
2152 
2153 	return NULL;
2154 }
2155 
2156 
2157 int32
2158 ServerApp::CountPictures() const
2159 {
2160 	return fPictureList.CountItems();
2161 }
2162 
2163 
2164 ServerPicture *
2165 ServerApp::FindPicture(int32 token) const
2166 {
2167 	for (int32 i = 0; i < fPictureList.CountItems(); i++) {
2168 		ServerPicture *picture = static_cast<ServerPicture *>(fPictureList.ItemAt(i));
2169 		if (picture && picture->GetToken() == token)
2170 			return picture;
2171 	}
2172 
2173 	return NULL;
2174 }
2175 
2176 
2177 team_id
2178 ServerApp::ClientTeam() const
2179 {
2180 	return fClientTeam;
2181 }
2182 
2183 
2184 thread_id
2185 ServerApp::Thread() const
2186 {
2187 	return fThread;
2188 }
2189 
2190