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