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