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