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