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