xref: /haiku/src/servers/app/ServerApp.cpp (revision 1d9d47fc72028bb71b5f232a877231e59cfe2438)
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 			DesktopSettings settings(fDesktop);
761 
762 			fLink.StartMessage(B_OK);
763 			fLink.Attach<int32>(settings.WorkspacesCount());
764 			fLink.Flush();
765 			break;
766 		}
767 
768 		case AS_SET_WORKSPACE_COUNT:
769 		{
770 			DesktopSettings settings(fDesktop);
771 
772 			int32 newCount;
773 			if (link.Read<int32>(&newCount) == B_OK) {
774 				settings.SetWorkspacesCount(newCount);
775 
776 				// either update the workspaces window, or switch to
777 				// the last available workspace - which will update
778 				// the workspaces window automatically
779 				if (fDesktop->CurrentWorkspace() >= newCount)
780 					fDesktop->SetWorkspace(newCount - 1);
781 				else
782 					fDesktop->UpdateWorkspaces();
783 			}
784 			break;
785 		}
786 
787 		case AS_CURRENT_WORKSPACE:
788 			STRACE(("ServerApp %s: get current workspace\n", Signature()));
789 
790 			fLink.StartMessage(B_OK);
791 			fLink.Attach<int32>(fDesktop->CurrentWorkspace());
792 			fLink.Flush();
793 			break;
794 
795 		case AS_ACTIVATE_WORKSPACE:
796 		{
797 			STRACE(("ServerApp %s: activate workspace\n", Signature()));
798 
799 			// TODO: See above
800 			int32 index;
801 			link.Read<int32>(&index);
802 
803 			fDesktop->SetWorkspace(index);
804 			break;
805 		}
806 
807 		case AS_SHOW_CURSOR:
808 		{
809 			STRACE(("ServerApp %s: Show Cursor\n", Signature()));
810 			fCursorHideLevel--;
811 			if (fCursorHideLevel < 0)
812 				fCursorHideLevel = 0;
813 			fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0);
814 			break;
815 		}
816 		case AS_HIDE_CURSOR:
817 		{
818 			STRACE(("ServerApp %s: Hide Cursor\n", Signature()));
819 			fCursorHideLevel++;
820 			fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0);
821 			break;
822 		}
823 		case AS_OBSCURE_CURSOR:
824 		{
825 			STRACE(("ServerApp %s: Obscure Cursor\n", Signature()));
826 			fDesktop->HWInterface()->ObscureCursor();
827 			break;
828 		}
829 		case AS_QUERY_CURSOR_HIDDEN:
830 		{
831 			STRACE(("ServerApp %s: Received IsCursorHidden request\n", Signature()));
832 			fLink.StartMessage(fCursorHideLevel > 0 ? B_OK : B_ERROR);
833 			fLink.Flush();
834 			break;
835 		}
836 		case AS_SET_CURSOR:
837 		{
838 			STRACE(("ServerApp %s: SetCursor\n", Signature()));
839 
840 			// Attached data:
841 			// 1) bool flag to send a reply
842 			// 2) int32 token ID of the cursor to set
843 			// 3) port_id port to receive a reply. Only exists if the sync flag is true.
844 			bool sync;
845 			int32 token;
846 
847 			link.Read<bool>(&sync);
848 			if (link.Read<int32>(&token) != B_OK)
849 				break;
850 
851 			if (!fDesktop->GetCursorManager().Lock())
852 				break;
853 
854 			ServerCursor* oldCursor = fAppCursor;
855 			fAppCursor = fDesktop->GetCursorManager().FindCursor(token);
856 			if (fAppCursor != NULL)
857 				fAppCursor->Acquire();
858 
859 			if (_HasWindowUnderMouse())
860 				fDesktop->SetCursor(CurrentCursor());
861 
862 			if (oldCursor != NULL)
863 				oldCursor->Release();
864 
865 			fDesktop->GetCursorManager().Unlock();
866 
867 			if (sync) {
868 				// The application is expecting a reply
869 				fLink.StartMessage(B_OK);
870 				fLink.Flush();
871 			}
872 			break;
873 		}
874 		case AS_CREATE_CURSOR:
875 		{
876 			STRACE(("ServerApp %s: Create Cursor\n", Signature()));
877 			// Attached data:
878 			// 1) 68 bytes of fAppCursor data
879 			// 2) port_id reply port
880 
881 			status_t status = B_ERROR;
882 			uint8 cursorData[68];
883 			ServerCursor* cursor = NULL;
884 
885 //			if (link.Read(cursorData, sizeof(cursorData)) >= B_OK) {
886 //				cursor = new (nothrow) ServerCursor(cursorData);
887 //				if (cursor == NULL)
888 //					status = B_NO_MEMORY;
889 //			}
890 //
891 //			if (cursor != NULL) {
892 //				cursor->SetOwningTeam(fClientTeam);
893 //				fDesktop->GetCursorManager().AddCursor(cursor);
894 //
895 //				// Synchronous message - BApplication is waiting on the cursor's ID
896 //				fLink.StartMessage(B_OK);
897 //				fLink.Attach<int32>(cursor->Token());
898 //			} else
899 //				fLink.StartMessage(status);
900 
901 			if (link.Read(cursorData, sizeof(cursorData)) >= B_OK) {
902 				cursor = fDesktop->GetCursorManager().CreateCursor(fClientTeam,
903 																   cursorData);
904 				if (cursor == NULL)
905 					status = B_NO_MEMORY;
906 			}
907 
908 			if (cursor != NULL) {
909 				// Synchronous message - BApplication is waiting on the cursor's ID
910 				fLink.StartMessage(B_OK);
911 				fLink.Attach<int32>(cursor->Token());
912 			} else
913 				fLink.StartMessage(status);
914 
915 			fLink.Flush();
916 			break;
917 		}
918 		case AS_DELETE_CURSOR:
919 		{
920 			STRACE(("ServerApp %s: Delete BCursor\n", Signature()));
921 			// Attached data:
922 			// 1) int32 token ID of the cursor to delete
923 			int32 token;
924 			bool pendingViewCursor;
925 			link.Read<int32>(&token);
926 			if (link.Read<bool>(&pendingViewCursor) != B_OK)
927 				break;
928 
929 			if (!fDesktop->GetCursorManager().Lock())
930 				break;
931 
932 			ServerCursor* cursor = fDesktop->GetCursorManager().FindCursor(token);
933 			if (cursor) {
934 				if (pendingViewCursor)
935 					cursor->SetPendingViewCursor(true);
936 
937 				cursor->Release();
938 			}
939 			fDesktop->GetCursorManager().Unlock();
940 
941 			break;
942 		}
943 
944 		case AS_GET_SCROLLBAR_INFO:
945 		{
946 			STRACE(("ServerApp %s: Get ScrollBar info\n", Signature()));
947 			scroll_bar_info info;
948 			DesktopSettings settings(fDesktop);
949 			settings.GetScrollBarInfo(info);
950 
951 			fLink.StartMessage(B_OK);
952 			fLink.Attach<scroll_bar_info>(info);
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 				DesktopSettings 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 			menu_info info;
976 			DesktopSettings settings(fDesktop);
977 			settings.GetMenuInfo(info);
978 
979 			fLink.StartMessage(B_OK);
980 			fLink.Attach<menu_info>(info);
981 			fLink.Flush();
982 			break;
983 		}
984 		case AS_SET_MENU_INFO:
985 		{
986 			STRACE(("ServerApp %s: Set menu info\n", Signature()));
987 			menu_info info;
988 			if (link.Read<menu_info>(&info) == B_OK) {
989 				DesktopSettings settings(fDesktop);
990 				settings.SetMenuInfo(info);
991 					// TODO: SetMenuInfo() should do some validity check, so
992 					//	that the answer we're giving can actually be useful
993 			}
994 
995 			fLink.StartMessage(B_OK);
996 			fLink.Flush();
997 			break;
998 		}
999 
1000 		case AS_SET_MOUSE_MODE:
1001 		{
1002 			STRACE(("ServerApp %s: Set Focus Follows Mouse mode\n", Signature()));
1003 			// Attached Data:
1004 			// 1) enum mode_mouse FFM mouse mode
1005 			mode_mouse mouseMode;
1006 			if (link.Read<mode_mouse>(&mouseMode) == B_OK) {
1007 				DesktopSettings settings(fDesktop);
1008 				settings.SetMouseMode(mouseMode);
1009 			}
1010 			break;
1011 		}
1012 		case AS_GET_MOUSE_MODE:
1013 		{
1014 			STRACE(("ServerApp %s: Get Focus Follows Mouse mode\n", Signature()));
1015 			DesktopSettings settings(fDesktop);
1016 
1017 			fLink.StartMessage(B_OK);
1018 			fLink.Attach<mode_mouse>(settings.MouseMode());
1019 			fLink.Flush();
1020 			break;
1021 		}
1022 
1023 		/* font messages */
1024 
1025 		case AS_SET_SYSTEM_FONT:
1026 		{
1027 			// gets:
1028 			//	1) string - font type ("plain", ...)
1029 			//	2) string - family
1030 			//	3) string - style
1031 			//	4) float - size
1032 
1033 			char type[B_OS_NAME_LENGTH];
1034 			font_family familyName;
1035 			font_style styleName;
1036 			float size;
1037 
1038 			if (link.ReadString(type, sizeof(type)) == B_OK
1039 				&& link.ReadString(familyName, sizeof(familyName)) == B_OK
1040 				&& link.ReadString(styleName, sizeof(styleName)) == B_OK
1041 				&& link.Read<float>(&size) == B_OK) {
1042 				BAutolock locker(gFontManager);
1043 
1044 				FontStyle* style = gFontManager->GetStyle(familyName, styleName);
1045 				if (style != NULL) {
1046 					ServerFont font(*style, size);
1047 					DesktopSettings settings(fDesktop);
1048 
1049 					if (!strcmp(type, "plain"))
1050 						settings.SetDefaultPlainFont(font);
1051 					else if (!strcmp(type, "bold"))
1052 						settings.SetDefaultBoldFont(font);
1053 					else if (!strcmp(type, "fixed"))
1054 						settings.SetDefaultFixedFont(font);
1055 				}
1056 			}
1057 			break;
1058 		}
1059 		case AS_GET_SYSTEM_DEFAULT_FONT:
1060 		{
1061 			// input:
1062 			//	1) string - font type ("plain", ...)
1063 
1064 			ServerFont font;
1065 
1066 			char type[B_OS_NAME_LENGTH];
1067 			status_t status = link.ReadString(type, sizeof(type));
1068 			if (status == B_OK) {
1069 				if (!strcmp(type, "plain")) {
1070 					font = *gFontManager->DefaultPlainFont();
1071 				} else if (!strcmp(type, "bold")) {
1072 					font = *gFontManager->DefaultBoldFont();
1073 				} else if (!strcmp(type, "fixed")) {
1074 					font = *gFontManager->DefaultFixedFont();
1075 				} else
1076 					status = B_BAD_VALUE;
1077 			}
1078 
1079 			if (status == B_OK) {
1080 				// returns:
1081 				//	1) string - family
1082 				//	2) string - style
1083 				//	3) float - size
1084 
1085 				fLink.StartMessage(B_OK);
1086 				fLink.AttachString(font.Family());
1087 				fLink.AttachString(font.Style());
1088 				fLink.Attach<float>(font.Size());
1089 			} else
1090 				fLink.StartMessage(status);
1091 
1092 			fLink.Flush();
1093 			break;
1094 		}
1095 		case AS_GET_SYSTEM_FONTS:
1096 		{
1097 			FTRACE(("ServerApp %s: AS_GET_SYSTEM_FONTS\n", Signature()));
1098 			// Returns:
1099 			// 1) uint16 - family ID
1100 			// 2) uint16 - style ID
1101 			// 3) float - size in points
1102 			// 4) uint16 - face flags
1103 			// 5) uint32 - font flags
1104 
1105 			DesktopSettings settings(fDesktop);
1106 			fLink.StartMessage(B_OK);
1107 
1108 			for (int32 i = 0; i < 3; i++) {
1109 				ServerFont font;
1110 				switch (i) {
1111 					case 0:
1112 						settings.GetDefaultPlainFont(font);
1113 						fLink.AttachString("plain");
1114 						break;
1115 					case 1:
1116 						settings.GetDefaultBoldFont(font);
1117 						fLink.AttachString("bold");
1118 						break;
1119 					case 2:
1120 						settings.GetDefaultFixedFont(font);
1121 						fLink.AttachString("fixed");
1122 						break;
1123 				}
1124 
1125 				fLink.Attach<uint16>(font.FamilyID());
1126 				fLink.Attach<uint16>(font.StyleID());
1127 				fLink.Attach<float>(font.Size());
1128 				fLink.Attach<uint16>(font.Face());
1129 				fLink.Attach<uint32>(font.Flags());
1130 			}
1131 
1132 			fLink.Flush();
1133 			break;
1134 		}
1135 		case AS_GET_FONT_LIST_REVISION:
1136 		{
1137 			STRACE(("ServerApp %s: AS_GET_FONT_LIST_REVISION\n", Signature()));
1138 
1139 			fLink.StartMessage(B_OK);
1140 			fLink.Attach<int32>(gFontManager->CheckRevision(fDesktop->UserID()));
1141 			fLink.Flush();
1142 			break;
1143 		}
1144 		case AS_GET_FAMILY_AND_STYLES:
1145 		{
1146 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLES\n", Signature()));
1147 			// Attached Data:
1148 			// 1) int32 the index of the font family to get
1149 
1150 			// Returns:
1151 			// 1) string - name of family
1152 			// 2) uint32 - flags of font family (B_IS_FIXED || B_HAS_TUNED_FONT)
1153 			// 3) count of styles in that family
1154 			// For each style:
1155 			//		1) string - name of style
1156 			//		2) uint16 - face of style
1157 			//		3) uint32 - flags of style
1158 
1159 			int32 index;
1160 			link.Read<int32>(&index);
1161 
1162 			gFontManager->Lock();
1163 
1164 			FontFamily* family = gFontManager->FamilyAt(index);
1165 			if (family) {
1166 				fLink.StartMessage(B_OK);
1167 				fLink.AttachString(family->Name());
1168 				fLink.Attach<uint32>(family->Flags());
1169 
1170 				int32 count = family->CountStyles();
1171 				fLink.Attach<int32>(count);
1172 
1173 				for (int32 i = 0; i < count; i++) {
1174 					FontStyle* style = family->StyleAt(i);
1175 
1176 					fLink.AttachString(style->Name());
1177 					fLink.Attach<uint16>(style->Face());
1178 					fLink.Attach<uint32>(style->Flags());
1179 				}
1180 			} else
1181 				fLink.StartMessage(B_BAD_VALUE);
1182 
1183 			gFontManager->Unlock();
1184 			fLink.Flush();
1185 			break;
1186 		}
1187 		case AS_GET_FAMILY_AND_STYLE:
1188 		{
1189 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE\n", Signature()));
1190 			// Attached Data:
1191 			// 1) uint16 - family ID
1192 			// 2) uint16 - style ID
1193 
1194 			// Returns:
1195 			// 1) font_family The name of the font family
1196 			// 2) font_style - name of the style
1197 			uint16 familyID, styleID;
1198 			link.Read<uint16>(&familyID);
1199 			link.Read<uint16>(&styleID);
1200 
1201 			gFontManager->Lock();
1202 
1203 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1204 			if (fontStyle != NULL) {
1205 				fLink.StartMessage(B_OK);
1206 				fLink.AttachString(fontStyle->Family()->Name());
1207 				fLink.AttachString(fontStyle->Name());
1208 			} else
1209 				fLink.StartMessage(B_BAD_VALUE);
1210 
1211 			fLink.Flush();
1212 			gFontManager->Unlock();
1213 			break;
1214 		}
1215 		case AS_GET_FAMILY_AND_STYLE_IDS:
1216 		{
1217 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE_IDS\n", Signature()));
1218 			// Attached Data:
1219 			// 1) font_family - name of font family to use
1220 			// 2) font_style - name of style in family
1221 			// 3) family ID - only used if 1) is empty
1222 			// 4) style ID - only used if 2) is empty
1223 			// 5) face - the font's current face
1224 
1225 			// Returns:
1226 			// 1) uint16 - family ID
1227 			// 2) uint16 - style ID
1228 			// 3) uint16 - face
1229 
1230 			font_family family;
1231 			font_style style;
1232 			uint16 familyID, styleID;
1233 			uint16 face;
1234 			if (link.ReadString(family, sizeof(font_family)) == B_OK
1235 				&& link.ReadString(style, sizeof(font_style)) == B_OK
1236 				&& link.Read<uint16>(&familyID) == B_OK
1237 				&& link.Read<uint16>(&styleID) == B_OK
1238 				&& link.Read<uint16>(&face) == B_OK) {
1239 				// get the font and return IDs and face
1240 				gFontManager->Lock();
1241 
1242 				FontStyle *fontStyle = gFontManager->GetStyle(family, style,
1243 					familyID, styleID, face);
1244 
1245 				if (fontStyle != NULL) {
1246 					fLink.StartMessage(B_OK);
1247 					fLink.Attach<uint16>(fontStyle->Family()->ID());
1248 					fLink.Attach<uint16>(fontStyle->ID());
1249 
1250 					// we try to keep the font face close to what we got
1251 					face = fontStyle->PreservedFace(face);
1252 
1253 					fLink.Attach<uint16>(face);
1254 				} else
1255 					fLink.StartMessage(B_NAME_NOT_FOUND);
1256 
1257 				gFontManager->Unlock();
1258 			} else
1259 				fLink.StartMessage(B_BAD_VALUE);
1260 
1261 			fLink.Flush();
1262 			break;
1263 		}
1264 		case AS_GET_FONT_FILE_FORMAT:
1265 		{
1266 			FTRACE(("ServerApp %s: AS_GET_FONT_FILE_FORMAT\n", Signature()));
1267 			// Attached Data:
1268 			// 1) uint16 - family ID
1269 			// 2) uint16 - style ID
1270 
1271 			// Returns:
1272 			// 1) uint16 font_file_format of font
1273 
1274 			int32 familyID, styleID;
1275 			link.Read<int32>(&familyID);
1276 			link.Read<int32>(&styleID);
1277 
1278 			gFontManager->Lock();
1279 
1280 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1281 			if (fontStyle) {
1282 				fLink.StartMessage(B_OK);
1283 				fLink.Attach<uint16>((uint16)fontStyle->FileFormat());
1284 			} else
1285 				fLink.StartMessage(B_BAD_VALUE);
1286 
1287 			gFontManager->Unlock();
1288 			fLink.Flush();
1289 			break;
1290 		}
1291 		case AS_GET_STRING_WIDTHS:
1292 		{
1293 			FTRACE(("ServerApp %s: AS_GET_STRING_WIDTHS\n", Signature()));
1294 			// Attached Data:
1295 			// 1) uint16 ID of family
1296 			// 2) uint16 ID of style
1297 			// 3) float point size of font
1298 			// 4) uint8 spacing to use
1299 			// 5) int32 numStrings
1300 			// 6) int32 string length to measure (numStrings times)
1301 			// 7) string String to measure (numStrings times)
1302 
1303 			// Returns:
1304 			// 1) float - width of the string in pixels (numStrings times)
1305 
1306 			uint16 family, style;
1307 			float size;
1308 			uint8 spacing;
1309 
1310 			link.Read<uint16>(&family);
1311 			link.Read<uint16>(&style);
1312 			link.Read<float>(&size);
1313 			link.Read<uint8>(&spacing);
1314 			int32 numStrings;
1315 			if (link.Read<int32>(&numStrings) != B_OK) {
1316 				// this results in a B_BAD_VALUE return
1317 				numStrings = 0;
1318 				size = 0.0f;
1319 			}
1320 
1321 			float widthArray[numStrings];
1322 			int32 lengthArray[numStrings];
1323 			char *stringArray[numStrings];
1324 			for (int32 i = 0; i < numStrings; i++) {
1325 				link.ReadString(&stringArray[i], (size_t *)&lengthArray[i]);
1326 			}
1327 
1328 			ServerFont font;
1329 
1330 			if (font.SetFamilyAndStyle(family, style) == B_OK && size > 0) {
1331 				font.SetSize(size);
1332 				font.SetSpacing(spacing);
1333 
1334 				for (int32 i = 0; i < numStrings; i++) {
1335 					if (!stringArray[i] || lengthArray[i] <= 0)
1336 						widthArray[i] = 0.0;
1337 					else {
1338 						widthArray[i] = fDesktop->GetDrawingEngine()->StringWidth(stringArray[i], lengthArray[i], font);
1339 						// NOTE: The line below will return the exact same thing. However,
1340 						// the line above uses the AGG rendering backend, for which glyph caching
1341 						// actually works. It is about 20 times faster!
1342 						// TODO: I've disabled the AGG version for now, as it produces a dead lock
1343 						//	(font use), that I am currently too lazy to investigate...
1344 //						widthArray[i] = font.StringWidth(stringArray[i], lengthArray[i]);
1345 					}
1346 				}
1347 
1348 				fLink.StartMessage(B_OK);
1349 				fLink.Attach(widthArray, sizeof(widthArray));
1350 			} else
1351 				fLink.StartMessage(B_BAD_VALUE);
1352 
1353 			fLink.Flush();
1354 
1355 			for (int32 i = 0; i < numStrings; i++) {
1356 				free(stringArray[i]);
1357 			}
1358 			break;
1359 		}
1360 		case AS_GET_FONT_BOUNDING_BOX:
1361 		{
1362 			FTRACE(("ServerApp %s: AS_GET_BOUNDING_BOX unimplemented\n",
1363 				Signature()));
1364 			// Attached Data:
1365 			// 1) uint16 - family ID
1366 			// 2) uint16 - style ID
1367 
1368 			// Returns:
1369 			// 1) BRect - box holding entire font
1370 
1371 			// ToDo: implement me!
1372 			fLink.StartMessage(B_ERROR);
1373 			fLink.Flush();
1374 			break;
1375 		}
1376 		case AS_GET_TUNED_COUNT:
1377 		{
1378 			FTRACE(("ServerApp %s: AS_GET_TUNED_COUNT\n", Signature()));
1379 			// Attached Data:
1380 			// 1) uint16 - family ID
1381 			// 2) uint16 - style ID
1382 
1383 			// Returns:
1384 			// 1) int32 - number of font strikes available
1385 			uint16 familyID, styleID;
1386 			link.Read<uint16>(&familyID);
1387 			link.Read<uint16>(&styleID);
1388 
1389 			gFontManager->Lock();
1390 
1391 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1392 			if (fontStyle != NULL) {
1393 				fLink.StartMessage(B_OK);
1394 				fLink.Attach<int32>(fontStyle->TunedCount());
1395 			} else
1396 				fLink.StartMessage(B_BAD_VALUE);
1397 
1398 			gFontManager->Unlock();
1399 			fLink.Flush();
1400 			break;
1401 		}
1402 		case AS_GET_TUNED_INFO:
1403 		{
1404 			FTRACE(("ServerApp %s: AS_GET_TUNED_INFO unimplmemented\n",
1405 				Signature()));
1406 			// Attached Data:
1407 			// 1) uint16 - family ID
1408 			// 2) uint16 - style ID
1409 			// 3) uint32 - index of the particular font strike
1410 
1411 			// Returns:
1412 			// 1) tuned_font_info - info on the strike specified
1413 			// ToDo: implement me!
1414 			fLink.StartMessage(B_ERROR);
1415 			fLink.Flush();
1416 			break;
1417 		}
1418 		case AS_GET_EXTRA_FONT_FLAGS:
1419 		{
1420 			FTRACE(("ServerApp %s: AS_GET_EXTRA_FONT_FLAGS\n",
1421 				Signature()));
1422 			// Attached Data:
1423 			// 1) uint16 - family ID
1424 			// 2) uint16 - style ID
1425 
1426 			// Returns:
1427 			// 1) uint32 - extra font flags
1428 			uint16 familyID, styleID;
1429 			link.Read<uint16>(&familyID);
1430 			link.Read<uint16>(&styleID);
1431 
1432 			gFontManager->Lock();
1433 
1434 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1435 			if (fontStyle != NULL) {
1436 				fLink.StartMessage(B_OK);
1437 				fLink.Attach<uint32>(fontStyle->Flags());
1438 			} else
1439 				fLink.StartMessage(B_BAD_VALUE);
1440 
1441 			gFontManager->Unlock();
1442 			fLink.Flush();
1443 			break;
1444 		}
1445 		case AS_GET_FONT_HEIGHT:
1446 		{
1447 			FTRACE(("ServerApp %s: AS_GET_FONT_HEIGHT\n", Signature()));
1448 			// Attached Data:
1449 			// 1) uint16 family ID
1450 			// 2) uint16 style ID
1451 			// 3) float size
1452 			uint16 familyID, styleID;
1453 			float size;
1454 			link.Read<uint16>(&familyID);
1455 			link.Read<uint16>(&styleID);
1456 			link.Read<float>(&size);
1457 
1458 			gFontManager->Lock();
1459 
1460 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1461 			if (fontStyle != NULL) {
1462 				font_height height;
1463 				fontStyle->GetHeight(size, height);
1464 
1465 				fLink.StartMessage(B_OK);
1466 				fLink.Attach<font_height>(height);
1467 			} else
1468 				fLink.StartMessage(B_BAD_VALUE);
1469 
1470 			gFontManager->Unlock();
1471 			fLink.Flush();
1472 			break;
1473 		}
1474 		case AS_GET_GLYPH_SHAPES:
1475 		{
1476 			FTRACE(("ServerApp %s: AS_GET_GLYPH_SHAPES\n", Signature()));
1477 			// Attached Data:
1478 			// 1) uint16 - family ID
1479 			// 2) uint16 - style ID
1480 			// 3) float - point size
1481 			// 4) float - shear
1482 			// 5) float - rotation
1483 			// 6) uint32 - flags
1484 			// 7) int32 - numChars
1485 			// 8) int32 - numBytes
1486 			// 8) char - chars (bytesInBuffer times)
1487 
1488 			// Returns:
1489 			// 1) BShape - glyph shape
1490 			// numChars times
1491 
1492 			uint16 familyID, styleID;
1493 			uint32 flags;
1494 			float size, shear, rotation;
1495 
1496 			link.Read<uint16>(&familyID);
1497 			link.Read<uint16>(&styleID);
1498 			link.Read<float>(&size);
1499 			link.Read<float>(&shear);
1500 			link.Read<float>(&rotation);
1501 			link.Read<uint32>(&flags);
1502 
1503 			int32 numChars, numBytes;
1504 			link.Read<int32>(&numChars);
1505 			link.Read<int32>(&numBytes);
1506 
1507 			char *charArray = new char[numBytes];
1508 			link.Read(charArray, numBytes);
1509 
1510 			ServerFont font;
1511 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1512 			if (status == B_OK) {
1513 				font.SetSize(size);
1514 				font.SetShear(shear);
1515 				font.SetRotation(rotation);
1516 				font.SetFlags(flags);
1517 
1518 				BShape **shapes = new BShape *[numChars];
1519 				status = font.GetGlyphShapes(charArray, numChars, shapes);
1520 				if (status == B_OK) {
1521 					fLink.StartMessage(B_OK);
1522 					for (int32 i = 0; i < numChars; i++) {
1523 						fLink.AttachShape(*shapes[i]);
1524 						delete shapes[i];
1525 					}
1526 
1527 					delete[] shapes;
1528 				} else
1529 					fLink.StartMessage(status);
1530 			} else
1531 				fLink.StartMessage(status);
1532 
1533 			delete[] charArray;
1534 			fLink.Flush();
1535 			break;
1536 		}
1537 		case AS_GET_HAS_GLYPHS:
1538 		{
1539 			FTRACE(("ServerApp %s: AS_GET_HAS_GLYPHS\n", Signature()));
1540 			// Attached Data:
1541 			// 1) uint16 - family ID
1542 			// 2) uint16 - style ID
1543 			// 3) int32 - numChars
1544 			// 4) int32 - numBytes
1545 			// 5) char - the char buffer with size numBytes
1546 
1547 			uint16 familyID, styleID;
1548 			link.Read<uint16>(&familyID);
1549 			link.Read<uint16>(&styleID);
1550 
1551 			int32 numChars, numBytes;
1552 			link.Read<int32>(&numChars);
1553 			link.Read<int32>(&numBytes);
1554 			char* charArray = new char[numBytes];
1555 			link.Read(charArray, numBytes);
1556 
1557 			ServerFont font;
1558 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1559 			if (status == B_OK) {
1560 				bool hasArray[numChars];
1561 				status = font.GetHasGlyphs(charArray, numChars, hasArray);
1562 				if (status == B_OK) {
1563 					fLink.StartMessage(B_OK);
1564 					fLink.Attach(hasArray, sizeof(hasArray));
1565 				} else
1566 					fLink.StartMessage(status);
1567 			} else
1568 				fLink.StartMessage(status);
1569 
1570 			delete[] charArray;
1571 			fLink.Flush();
1572 			break;
1573 		}
1574 		case AS_GET_EDGES:
1575 		{
1576 			FTRACE(("ServerApp %s: AS_GET_EDGES\n", Signature()));
1577 			// Attached Data:
1578 			// 1) uint16 - family ID
1579 			// 2) uint16 - style ID
1580 			// 3) int32 - numChars
1581 			// 4) int32 - numBytes
1582 			// 5) char - the char buffer with size numBytes
1583 
1584 			uint16 familyID, styleID;
1585 			link.Read<uint16>(&familyID);
1586 			link.Read<uint16>(&styleID);
1587 
1588 			int32 numChars;
1589 			link.Read<int32>(&numChars);
1590 
1591 			uint32 numBytes;
1592 			link.Read<uint32>(&numBytes);
1593 			char* charArray = new char[numBytes];
1594 			link.Read(charArray, numBytes);
1595 
1596 			ServerFont font;
1597 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1598 			if (status == B_OK) {
1599 				edge_info edgeArray[numChars];
1600 				status = font.GetEdges(charArray, numChars, edgeArray);
1601 				if (status == B_OK) {
1602 					fLink.StartMessage(B_OK);
1603 					fLink.Attach(edgeArray, sizeof(edgeArray));
1604 				} else
1605 					fLink.StartMessage(status);
1606 			} else
1607 				fLink.StartMessage(status);
1608 
1609 			delete[] charArray;
1610 			fLink.Flush();
1611 			break;
1612 		}
1613 		case AS_GET_ESCAPEMENTS:
1614 		{
1615 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS\n", Signature()));
1616 			// Attached Data:
1617 			// 1) uint16 - family ID
1618 			// 2) uint16 - style ID
1619 			// 3) float - point size
1620 			// 4) float - rotation
1621 			// 5) uint32 - flags
1622 			// 6) int32 - numChars
1623 			// 7) char - char     -\       both
1624 			// 8) BPoint - offset -/ (numChars times)
1625 
1626 			// Returns:
1627 			// 1) BPoint - escapement
1628 			// numChars times
1629 
1630 			uint16 familyID, styleID;
1631 			uint32 flags;
1632 			float size, rotation;
1633 
1634 			link.Read<uint16>(&familyID);
1635 			link.Read<uint16>(&styleID);
1636 			link.Read<float>(&size);
1637 			link.Read<float>(&rotation);
1638 			link.Read<uint32>(&flags);
1639 
1640 			escapement_delta delta;
1641 			link.Read<float>(&delta.nonspace);
1642 			link.Read<float>(&delta.space);
1643 
1644 			bool wantsOffsets;
1645 			link.Read<bool>(&wantsOffsets);
1646 
1647 			int32 numChars;
1648 			link.Read<int32>(&numChars);
1649 
1650 			uint32 numBytes;
1651 			link.Read<uint32>(&numBytes);
1652 			char *charArray = new char[numBytes];
1653 			link.Read(charArray, numBytes);
1654 
1655 			ServerFont font;
1656 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1657 			if (status == B_OK) {
1658 				font.SetSize(size);
1659 				font.SetRotation(rotation);
1660 				font.SetFlags(flags);
1661 
1662 				BPoint *escapements = new BPoint[numChars];
1663 				BPoint *offsets = NULL;
1664 				if (wantsOffsets)
1665 					offsets = new BPoint[numChars];
1666 
1667 				status = font.GetEscapements(charArray, numChars, delta,
1668 					escapements, offsets);
1669 
1670 				if (status == B_OK) {
1671 					fLink.StartMessage(B_OK);
1672 					for (int32 i = 0; i < numChars; i++)
1673 						fLink.Attach<BPoint>(escapements[i]);
1674 
1675 					delete[] escapements;
1676 
1677 					if (wantsOffsets) {
1678 						for (int32 i = 0; i < numChars; i++)
1679 							fLink.Attach<BPoint>(offsets[i]);
1680 
1681 						delete[] offsets;
1682 					}
1683 				} else
1684 					fLink.StartMessage(status);
1685 			} else
1686 				fLink.StartMessage(status);
1687 
1688 			delete[] charArray;
1689 			fLink.Flush();
1690 			break;
1691 		}
1692 		case AS_GET_ESCAPEMENTS_AS_FLOATS:
1693 		{
1694 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS_AS_FLOATS\n", Signature()));
1695 			// Attached Data:
1696 			// 1) uint16 - family ID
1697 			// 2) uint16 - style ID
1698 			// 3) float - point size
1699 			// 4) float - rotation
1700 			// 5) uint32 - flags
1701 
1702 			// 6) float - additional "nonspace" delta
1703 			// 7) float - additional "space" delta
1704 
1705 			// 8) int32 - numChars
1706 			// 9) int32 - numBytes
1707 			// 10) char - the char buffer with size numBytes
1708 
1709 			// Returns:
1710 			// 1) float - escapement buffer with numChar entries
1711 
1712 			uint16 familyID, styleID;
1713 			uint32 flags;
1714 			float size, rotation;
1715 
1716 			link.Read<uint16>(&familyID);
1717 			link.Read<uint16>(&styleID);
1718 			link.Read<float>(&size);
1719 			link.Read<float>(&rotation);
1720 			link.Read<uint32>(&flags);
1721 
1722 			escapement_delta delta;
1723 			link.Read<float>(&delta.nonspace);
1724 			link.Read<float>(&delta.space);
1725 
1726 			int32 numChars;
1727 			link.Read<int32>(&numChars);
1728 
1729 			uint32 numBytes;
1730 			link.Read<uint32>(&numBytes);
1731 			char* charArray = new char[numBytes];
1732 			link.Read(charArray, numBytes);
1733 
1734 			float* escapements = new float[numChars];
1735 
1736 			// figure out escapements
1737 
1738 			ServerFont font;
1739 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1740 			if (status == B_OK) {
1741 				font.SetSize(size);
1742 				font.SetRotation(rotation);
1743 				font.SetFlags(flags);
1744 
1745 				status = font.GetEscapements(charArray, numChars, delta,
1746 					escapements);
1747 
1748 				if (status == B_OK) {
1749 					fLink.StartMessage(B_OK);
1750 					fLink.Attach(escapements, numChars * sizeof(float));
1751 				}
1752 			}
1753 
1754 			delete[] charArray;
1755 			delete[] escapements;
1756 
1757 			if (status != B_OK)
1758 				fLink.StartMessage(status);
1759 
1760 			fLink.Flush();
1761 			break;
1762 		}
1763 		case AS_GET_BOUNDINGBOXES_CHARS:
1764 		{
1765 			FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_CHARS\n", Signature()));
1766 			// Attached Data:
1767 			// 1) uint16 - family ID
1768 			// 2) uint16 - style ID
1769 			// 3) float - point size
1770 			// 4) float - rotation
1771 			// 5) float - shear
1772 			// 6) uint8 - spacing
1773 			// 7) uint32 - flags
1774 
1775 			// 8) font_metric_mode - mode
1776 			// 9) bool - string escapement
1777 
1778 			// 10) escapement_delta - additional delta
1779 
1780 			// 11) int32 - numChars
1781 			// 12) int32 - numBytes
1782 			// 13) char - the char buffer with size numBytes
1783 
1784 			// Returns:
1785 			// 1) BRect - rects with numChar entries
1786 
1787 			uint16 famid, styid;
1788 			uint32 flags;
1789 			float ptsize, rotation, shear;
1790 			uint8 spacing;
1791 			font_metric_mode mode;
1792 			bool string_escapement;
1793 
1794 			link.Read<uint16>(&famid);
1795 			link.Read<uint16>(&styid);
1796 			link.Read<float>(&ptsize);
1797 			link.Read<float>(&rotation);
1798 			link.Read<float>(&shear);
1799 			link.Read<uint8>(&spacing);
1800 			link.Read<uint32>(&flags);
1801 			link.Read<font_metric_mode>(&mode);
1802 			link.Read<bool>(&string_escapement);
1803 
1804 			escapement_delta delta;
1805 			link.Read<escapement_delta>(&delta);
1806 
1807 			int32 numChars;
1808 			link.Read<int32>(&numChars);
1809 
1810 			uint32 numBytes;
1811 			link.Read<uint32>(&numBytes);
1812 
1813 			char *charArray = new char[numBytes];
1814 			link.Read(charArray, numBytes);
1815 
1816 			BRect rectArray[numChars];
1817 			// figure out escapements
1818 
1819 			ServerFont font;
1820 			bool success = false;
1821 			if (font.SetFamilyAndStyle(famid, styid) == B_OK) {
1822 				font.SetSize(ptsize);
1823 				font.SetRotation(rotation);
1824 				font.SetShear(shear);
1825 				font.SetSpacing(spacing);
1826 				font.SetFlags(flags);
1827 
1828 				// TODO implement for real
1829 				if (font.GetBoundingBoxesAsString(charArray, numChars,
1830 					rectArray, string_escapement, mode, delta) == B_OK) {
1831 					fLink.StartMessage(B_OK);
1832 					fLink.Attach(rectArray, sizeof(rectArray));
1833 					success = true;
1834 				}
1835 			}
1836 
1837 			if (!success)
1838 				fLink.StartMessage(B_ERROR);
1839 
1840 			delete[] charArray;
1841 			fLink.Flush();
1842 			break;
1843 		}
1844 		case AS_GET_BOUNDINGBOXES_STRINGS:
1845 		{
1846 			FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_STRINGS\n", Signature()));
1847 			// Attached Data:
1848 			// 1) uint16 - family ID
1849 			// 2) uint16 - style ID
1850 			// 3) float - point size
1851 			// 4) float - rotation
1852 			// 5) float - shear
1853 			// 6) uint8 - spacing
1854 			// 7) uint32 - flags
1855 
1856 			// 8) font_metric_mode - mode
1857 			// 9) int32 numStrings
1858 
1859 			// 10) escapement_delta - additional delta (numStrings times)
1860 			// 11) int32 string length to measure (numStrings times)
1861 			// 12) string - string (numStrings times)
1862 
1863 			// Returns:
1864 			// 1) BRect - rects with numStrings entries
1865 
1866 			uint16 famid, styid;
1867 			uint32 flags;
1868 			float ptsize, rotation, shear;
1869 			uint8 spacing;
1870 			font_metric_mode mode;
1871 
1872 			link.Read<uint16>(&famid);
1873 			link.Read<uint16>(&styid);
1874 			link.Read<float>(&ptsize);
1875 			link.Read<float>(&rotation);
1876 			link.Read<float>(&shear);
1877 			link.Read<uint8>(&spacing);
1878 			link.Read<uint32>(&flags);
1879 			link.Read<font_metric_mode>(&mode);
1880 
1881 			int32 numStrings;
1882 			link.Read<int32>(&numStrings);
1883 
1884 			escapement_delta deltaArray[numStrings];
1885 			char *stringArray[numStrings];
1886 			int32 lengthArray[numStrings];
1887 			for(int32 i=0; i<numStrings; i++) {
1888 				link.Read<int32>(&lengthArray[i]);
1889 				link.Read<escapement_delta>(&deltaArray[i]);
1890 				link.ReadString(&stringArray[i]);
1891 			}
1892 
1893 			BRect rectArray[numStrings];
1894 
1895 			ServerFont font;
1896 			bool success = false;
1897 			if (font.SetFamilyAndStyle(famid, styid) == B_OK) {
1898 				font.SetSize(ptsize);
1899 				font.SetRotation(rotation);
1900 				font.SetShear(shear);
1901 				font.SetSpacing(spacing);
1902 				font.SetFlags(flags);
1903 
1904 				// TODO implement for real
1905 				if (font.GetBoundingBoxesForStrings(stringArray, lengthArray,
1906 					numStrings, rectArray, mode, deltaArray) == B_OK) {
1907 					fLink.StartMessage(B_OK);
1908 					fLink.Attach(rectArray, sizeof(rectArray));
1909 					success = true;
1910 				}
1911 			}
1912 
1913 			for (int32 i = 0; i < numStrings; i++)
1914 				free(stringArray[i]);
1915 
1916 			if (!success)
1917 				fLink.StartMessage(B_ERROR);
1918 
1919 			fLink.Flush();
1920 			break;
1921 		}
1922 
1923 		/* screen commands */
1924 
1925 		case AS_VALID_SCREEN_ID:
1926 		{
1927 			// Attached data
1928 			// 1) screen_id screen
1929 			screen_id id;
1930 			if (link.Read<screen_id>(&id) == B_OK
1931 				&& id.id == B_MAIN_SCREEN_ID.id)
1932 				fLink.StartMessage(B_OK);
1933 			else
1934 				fLink.StartMessage(B_ERROR);
1935 
1936 			fLink.Flush();
1937 			break;
1938 		}
1939 
1940 		case AS_GET_NEXT_SCREEN_ID:
1941 		{
1942 			// Attached data
1943 			// 1) screen_id screen
1944 			screen_id id;
1945 			link.Read<screen_id>(&id);
1946 
1947 			// TODO: for now, just say we're the last one
1948 			fLink.StartMessage(B_ENTRY_NOT_FOUND);
1949 			fLink.Flush();
1950 			break;
1951 		}
1952 
1953 		case AS_GET_SCREEN_ID_FROM_WINDOW:
1954 		{
1955 			status_t status = B_ENTRY_NOT_FOUND;
1956 
1957 			// Attached data
1958 			// 1) int32 - window client token
1959 			int32 clientToken;
1960 			if (link.Read<int32>(&clientToken) != B_OK)
1961 				status = B_BAD_DATA;
1962 			else {
1963 				BAutolock locker(fWindowListLock);
1964 
1965 				for (int32 i = fWindowList.CountItems(); i-- > 0;) {
1966 					ServerWindow* window = fWindowList.ItemAt(i);
1967 
1968 					if (window->ClientToken() == clientToken) {
1969 						// got it!
1970 						fLink.StartMessage(B_OK);
1971 						fLink.Attach<screen_id>(B_MAIN_SCREEN_ID);
1972 							// TODO: for now...
1973 						status = B_OK;
1974 					}
1975 				}
1976 			}
1977 
1978 			if (status != B_OK)
1979 				fLink.StartMessage(status);
1980 			fLink.Flush();
1981 			break;
1982 		}
1983 
1984 		case AS_SCREEN_GET_MODE:
1985 		{
1986 			STRACE(("ServerApp %s: AS_SCREEN_GET_MODE\n", Signature()));
1987 			// Attached data
1988 			// 1) screen_id screen
1989 			// 2) uint32 workspace index
1990 			screen_id id;
1991 			link.Read<screen_id>(&id);
1992 			uint32 workspace;
1993 			link.Read<uint32>(&workspace);
1994 
1995 			// TODO: the display_mode can be different between
1996 			// the various screens.
1997 			// We have the screen_id and the workspace number, with these
1998 			// we need to find the corresponding "driver", and call getmode on it
1999 			display_mode mode;
2000 			fDesktop->ScreenAt(0)->GetMode(&mode);
2001 			// actually this isn't still enough as different workspaces can
2002 			// have different display_modes
2003 
2004 			fLink.StartMessage(B_OK);
2005 			fLink.Attach<display_mode>(mode);
2006 			fLink.Flush();
2007 			break;
2008 		}
2009 		case AS_SCREEN_SET_MODE:
2010 		{
2011 			STRACE(("ServerApp %s: AS_SCREEN_SET_MODE\n", Signature()));
2012 			// Attached data
2013 			// 1) screen_id
2014 			// 2) workspace index
2015 			// 3) display_mode to set
2016 			// 4) 'makedefault' boolean
2017 			// TODO: See above: workspaces support, etc.
2018 
2019 			screen_id id;
2020 			link.Read<screen_id>(&id);
2021 
2022 			uint32 workspace;
2023 			link.Read<uint32>(&workspace);
2024 
2025 			display_mode mode;
2026 			link.Read<display_mode>(&mode);
2027 
2028 			bool makeDefault = false;
2029 			status_t status = link.Read<bool>(&makeDefault);
2030 
2031 			if (status == B_OK && fDesktop->LockAllWindows()) {
2032 				status = fDesktop->ScreenAt(0)->SetMode(mode, makeDefault);
2033 				if (status == B_OK) {
2034 					gInputManager->UpdateScreenBounds(fDesktop->ScreenAt(0)->Frame());
2035 					fDesktop->ScreenChanged(fDesktop->ScreenAt(0), makeDefault);
2036 				}
2037 				fDesktop->UnlockAllWindows();
2038 			} else
2039 				status = B_ERROR;
2040 
2041 			fLink.StartMessage(status);
2042 			fLink.Flush();
2043 			break;
2044 		}
2045 
2046 		case AS_PROPOSE_MODE:
2047 		{
2048 			STRACE(("ServerApp %s: AS_PROPOSE_MODE\n", Signature()));
2049 			screen_id id;
2050 			link.Read<screen_id>(&id);
2051 
2052 			display_mode target, low, high;
2053 			link.Read<display_mode>(&target);
2054 			link.Read<display_mode>(&low);
2055 			link.Read<display_mode>(&high);
2056 			status_t status = fDesktop->HWInterface()->ProposeMode(&target, &low, &high);
2057 
2058 			// ProposeMode() returns B_BAD_VALUE to hint that the candidate is
2059 			// not within the given limits (but is supported)
2060 			if (status == B_OK || status == B_BAD_VALUE) {
2061 				fLink.StartMessage(B_OK);
2062 				fLink.Attach<display_mode>(target);
2063 				fLink.Attach<bool>(status == B_OK);
2064 			} else
2065 				fLink.StartMessage(status);
2066 
2067 			fLink.Flush();
2068 			break;
2069 		}
2070 
2071 		case AS_GET_MODE_LIST:
2072 		{
2073 			screen_id id;
2074 			link.Read<screen_id>(&id);
2075 			// TODO: use this screen id
2076 
2077 			display_mode* modeList;
2078 			uint32 count;
2079 			status_t status = fDesktop->HWInterface()->GetModeList(&modeList, &count);
2080 			if (status == B_OK) {
2081 				fLink.StartMessage(B_OK);
2082 				fLink.Attach<uint32>(count);
2083 				fLink.Attach(modeList, sizeof(display_mode) * count);
2084 
2085 				delete[] modeList;
2086 			} else
2087 				fLink.StartMessage(status);
2088 
2089 			fLink.Flush();
2090 			break;
2091 		}
2092 
2093 		case AS_SCREEN_GET_COLORMAP:
2094 		{
2095 			STRACE(("ServerApp %s: AS_SCREEN_GET_COLORMAP\n", Signature()));
2096 
2097 			screen_id id;
2098 			link.Read<screen_id>(&id);
2099 
2100 			const color_map *colorMap = SystemColorMap();
2101 			if (colorMap != NULL) {
2102 				fLink.StartMessage(B_OK);
2103 				fLink.Attach<color_map>(*colorMap);
2104 			} else
2105 				fLink.StartMessage(B_ERROR);
2106 
2107 			fLink.Flush();
2108 			break;
2109 		}
2110 
2111 		case AS_GET_DESKTOP_COLOR:
2112 		{
2113 			STRACE(("ServerApp %s: get desktop color\n", Signature()));
2114 
2115 			uint32 index;
2116 			link.Read<uint32>(&index);
2117 
2118 			fLink.StartMessage(B_OK);
2119 			fDesktop->Lock();
2120 
2121 			// we're nice to our children (and also take the default case
2122 			// into account which asks for the current workspace)
2123 			if (index >= (uint32)kMaxWorkspaces)
2124 				index = fDesktop->CurrentWorkspace();
2125 
2126 			Workspace workspace(*fDesktop, index);
2127 			fLink.Attach<rgb_color>(workspace.Color().GetColor32());
2128 
2129 			fDesktop->Unlock();
2130 			fLink.Flush();
2131 			break;
2132 		}
2133 
2134 		case AS_SET_DESKTOP_COLOR:
2135 		{
2136 			STRACE(("ServerApp %s: set desktop color\n", Signature()));
2137 
2138 			rgb_color color;
2139 			uint32 index;
2140 			bool makeDefault;
2141 
2142 			link.Read<rgb_color>(&color);
2143 			link.Read<uint32>(&index);
2144 			if (link.Read<bool>(&makeDefault) != B_OK)
2145 				break;
2146 
2147 			fDesktop->Lock();
2148 
2149 			// we're nice to our children (and also take the default case
2150 			// into account which asks for the current workspace)
2151 			if (index >= (uint32)kMaxWorkspaces)
2152 				index = fDesktop->CurrentWorkspace();
2153 
2154 			Workspace workspace(*fDesktop, index);
2155 			workspace.SetColor(color, makeDefault);
2156 
2157 			fDesktop->Unlock();
2158 			break;
2159 		}
2160 
2161 		case AS_GET_ACCELERANT_INFO:
2162 		{
2163 			STRACE(("ServerApp %s: get accelerant info\n", Signature()));
2164 
2165 			// We aren't using the screen_id for now...
2166 			screen_id id;
2167 			link.Read<screen_id>(&id);
2168 
2169 			accelerant_device_info accelerantInfo;
2170 			// TODO: I wonder if there should be a "desktop" lock...
2171 			status_t status = fDesktop->HWInterface()->GetDeviceInfo(&accelerantInfo);
2172 			if (status == B_OK) {
2173 				fLink.StartMessage(B_OK);
2174 				fLink.Attach<accelerant_device_info>(accelerantInfo);
2175 			} else
2176 				fLink.StartMessage(status);
2177 
2178 			fLink.Flush();
2179 			break;
2180 		}
2181 
2182 		case AS_GET_FRAME_BUFFER_CONFIG:
2183 		{
2184 			STRACE(("ServerApp %s: get frame buffer config\n", Signature()));
2185 
2186 			// We aren't using the screen_id for now...
2187 			screen_id id;
2188 			link.Read<screen_id>(&id);
2189 
2190 			frame_buffer_config config;
2191 			// TODO: I wonder if there should be a "desktop" lock...
2192 			status_t status = fDesktop->HWInterface()->GetFrameBufferConfig(config);
2193 			if (status == B_OK) {
2194 				fLink.StartMessage(B_OK);
2195 				fLink.Attach<frame_buffer_config>(config);
2196 			} else
2197 				fLink.StartMessage(status);
2198 
2199 			fLink.Flush();
2200 			break;
2201 		}
2202 
2203 		case AS_GET_RETRACE_SEMAPHORE:
2204 		{
2205 			STRACE(("ServerApp %s: get retrace semaphore\n", Signature()));
2206 
2207 			// We aren't using the screen_id for now...
2208 			screen_id id;
2209 			link.Read<screen_id>(&id);
2210 
2211 			fLink.StartMessage(B_OK);
2212 			fLink.Attach<sem_id>(fDesktop->HWInterface()->RetraceSemaphore());
2213 			fLink.Flush();
2214 			break;
2215 		}
2216 
2217 		case AS_GET_TIMING_CONSTRAINTS:
2218 		{
2219 			STRACE(("ServerApp %s: get timing constraints\n", Signature()));
2220 			// We aren't using the screen_id for now...
2221 			screen_id id;
2222 			link.Read<screen_id>(&id);
2223 
2224 			display_timing_constraints constraints;
2225 			status_t status = fDesktop->HWInterface()->GetTimingConstraints(
2226 				&constraints);
2227 			if (status == B_OK) {
2228 				fLink.StartMessage(B_OK);
2229 				fLink.Attach<display_timing_constraints>(constraints);
2230 			} else
2231 				fLink.StartMessage(status);
2232 
2233 			fLink.Flush();
2234 			break;
2235 		}
2236 
2237 		case AS_GET_PIXEL_CLOCK_LIMITS:
2238 		{
2239 			STRACE(("ServerApp %s: get pixel clock limits\n", Signature()));
2240 			// We aren't using the screen_id for now...
2241 			screen_id id;
2242 			link.Read<screen_id>(&id);
2243 			display_mode mode;
2244 			link.Read<display_mode>(&mode);
2245 
2246 			uint32 low, high;
2247 			status_t status = fDesktop->HWInterface()->GetPixelClockLimits(&mode,
2248 				&low, &high);
2249 			if (status == B_OK) {
2250 				fLink.StartMessage(B_OK);
2251 				fLink.Attach<uint32>(low);
2252 				fLink.Attach<uint32>(high);
2253 			} else
2254 				fLink.StartMessage(status);
2255 
2256 			fLink.Flush();
2257 			break;
2258 		}
2259 
2260 		case AS_SET_DPMS:
2261 		{
2262 			STRACE(("ServerApp %s: AS_SET_DPMS\n", Signature()));
2263 			screen_id id;
2264 			link.Read<screen_id>(&id);
2265 
2266 			uint32 mode;
2267 			link.Read<uint32>(&mode);
2268 
2269 			status_t status = fDesktop->HWInterface()->SetDPMSMode(mode);
2270 			fLink.StartMessage(status);
2271 
2272 			fLink.Flush();
2273 			break;
2274 		}
2275 
2276 		case AS_GET_DPMS_STATE:
2277 		{
2278 			STRACE(("ServerApp %s: AS_GET_DPMS_STATE\n", Signature()));
2279 
2280 			screen_id id;
2281 			link.Read<screen_id>(&id);
2282 
2283 			uint32 state = fDesktop->HWInterface()->DPMSMode();
2284 			fLink.StartMessage(B_OK);
2285 			fLink.Attach<uint32>(state);
2286 			fLink.Flush();
2287 			break;
2288 		}
2289 
2290 		case AS_GET_DPMS_CAPABILITIES:
2291 		{
2292 			STRACE(("ServerApp %s: AS_GET_DPMS_CAPABILITIES\n", Signature()));
2293 			screen_id id;
2294 			link.Read<screen_id>(&id);
2295 
2296 			uint32 capabilities = fDesktop->HWInterface()->DPMSCapabilities();
2297 			fLink.StartMessage(B_OK);
2298 			fLink.Attach<uint32>(capabilities);
2299 			fLink.Flush();
2300 			break;
2301 		}
2302 
2303 		case AS_READ_BITMAP:
2304 		{
2305 			STRACE(("ServerApp %s: AS_READ_BITMAP\n", Signature()));
2306 			int32 bitmapToken;
2307 			link.Read<int32>(&bitmapToken);
2308 
2309 			bool drawCursor = true;
2310 			link.Read<bool>(&drawCursor);
2311 
2312 			BRect bounds;
2313 			link.Read<BRect>(&bounds);
2314 
2315 			ServerBitmap *bitmap = FindBitmap(bitmapToken);
2316 			if (bitmap != NULL) {
2317 				if (fDesktop->GetDrawingEngine()->ReadBitmap(bitmap,
2318 					drawCursor, bounds) == B_OK) {
2319 					fLink.StartMessage(B_OK);
2320 				} else
2321 					fLink.StartMessage(B_BAD_VALUE);
2322 			} else
2323 				fLink.StartMessage(B_BAD_VALUE);
2324 
2325 			fLink.Flush();
2326 			break;
2327 		}
2328 
2329 		case AS_GET_ACCELERANT_PATH:
2330 		{
2331 			int32 index;
2332 			fLink.Read<int32>(&index);
2333 
2334 			BString path;
2335 			status_t status = fDesktop->HWInterface()->GetAccelerantPath(path);
2336 			fLink.StartMessage(status);
2337 			if (status == B_OK)
2338 				fLink.AttachString(path.String());
2339 
2340 			fLink.Flush();
2341 			break;
2342 		}
2343 
2344 		case AS_GET_DRIVER_PATH:
2345 		{
2346 			int32 index;
2347 			fLink.Read<int32>(&index);
2348 
2349 			BString path;
2350 			status_t status = fDesktop->HWInterface()->GetDriverPath(path);
2351 			fLink.StartMessage(status);
2352 			if (status == B_OK)
2353 				fLink.AttachString(path.String());
2354 
2355 			fLink.Flush();
2356 			break;
2357 		}
2358 
2359 		default:
2360 			printf("ServerApp %s received unhandled message code %ld\n",
2361 				Signature(), code);
2362 
2363 			if (link.NeedsReply()) {
2364 				// the client is now blocking and waiting for a reply!
2365 				fLink.StartMessage(B_ERROR);
2366 				fLink.Flush();
2367 			} else
2368 				puts("message doesn't need a reply!");
2369 			break;
2370 	}
2371 }
2372 
2373 
2374 status_t
2375 ServerApp::_CreateWindow(int32 code, BPrivate::LinkReceiver& link,
2376 	port_id& clientReplyPort)
2377 {
2378 	// Attached data:
2379 	// 1) int32 bitmap token (only for AS_CREATE_OFFSCREEN_WINDOW)
2380 	// 2) BRect window frame
2381 	// 3) uint32 window look
2382 	// 4) uint32 window feel
2383 	// 5) uint32 window flags
2384 	// 6) uint32 workspace index
2385 	// 7) int32 BHandler token of the window
2386 	// 8) port_id window's reply port
2387 	// 9) port_id window's looper port
2388 	// 10) const char * title
2389 
2390 	BRect frame;
2391 	int32 bitmapToken;
2392 	uint32 look;
2393 	uint32 feel;
2394 	uint32 flags;
2395 	uint32 workspaces;
2396 	int32 token;
2397 	port_id looperPort;
2398 	char* title;
2399 
2400 	if (code == AS_CREATE_OFFSCREEN_WINDOW)
2401 		link.Read<int32>(&bitmapToken);
2402 
2403 	link.Read<BRect>(&frame);
2404 	link.Read<uint32>(&look);
2405 	link.Read<uint32>(&feel);
2406 	link.Read<uint32>(&flags);
2407 	link.Read<uint32>(&workspaces);
2408 	link.Read<int32>(&token);
2409 	link.Read<port_id>(&clientReplyPort);
2410 	link.Read<port_id>(&looperPort);
2411 	if (link.ReadString(&title) != B_OK)
2412 		return B_ERROR;
2413 
2414 	if (!frame.IsValid()) {
2415 		// make sure we pass a valid rectangle to ServerWindow
2416 		frame.right = frame.left + 1;
2417 		frame.bottom = frame.top + 1;
2418 	}
2419 
2420 	status_t status = B_ERROR;
2421 	ServerWindow *window = NULL;
2422 
2423 	if (code == AS_CREATE_OFFSCREEN_WINDOW) {
2424 		ServerBitmap* bitmap = FindBitmap(bitmapToken);
2425 
2426 		if (bitmap != NULL) {
2427 			window = new OffscreenServerWindow(title, this, clientReplyPort,
2428 				looperPort, token, bitmap);
2429 		}
2430 	} else {
2431 		window = new ServerWindow(title, this, clientReplyPort, looperPort, token);
2432 		STRACE(("\nServerApp %s: New Window %s (%g:%g, %g:%g)\n",
2433 			Signature(), title, frame.left, frame.top,
2434 			frame.right, frame.bottom));
2435 	}
2436 
2437 	free(title);
2438 
2439 	// NOTE: the reply to the client is handled in ServerWindow::Run()
2440 	if (window != NULL) {
2441 		status = window->Init(frame, (window_look)look, (window_feel)feel,
2442 			flags, workspaces);
2443 		if (status == B_OK && !window->Run()) {
2444 			fprintf(stderr, "ServerApp::_CreateWindow() - failed to run the window thread\n");
2445 			status = B_ERROR;
2446 		}
2447 
2448 		if (status < B_OK)
2449 			delete window;
2450 	}
2451 
2452 	return status;
2453 }
2454 
2455 
2456 bool
2457 ServerApp::AddWindow(ServerWindow* window)
2458 {
2459 	BAutolock locker(fWindowListLock);
2460 
2461 	return fWindowList.AddItem(window);
2462 }
2463 
2464 
2465 void
2466 ServerApp::RemoveWindow(ServerWindow* window)
2467 {
2468 	BAutolock locker(fWindowListLock);
2469 
2470 	fWindowList.RemoveItem(window);
2471 }
2472 
2473 
2474 bool
2475 ServerApp::InWorkspace(int32 index) const
2476 {
2477 	BAutolock locker(fWindowListLock);
2478 
2479 	// we could cache this, but then we'd have to recompute the cached
2480 	// value everytime a window has closed or changed workspaces
2481 
2482 	// TODO: support initial application workspace!
2483 
2484 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
2485 		ServerWindow* serverWindow = fWindowList.ItemAt(i);
2486 
2487 		const WindowLayer* window = serverWindow->Window();
2488 		if (window == NULL || window->IsOffscreenWindow())
2489 			continue;
2490 
2491 		// only normal and unhidden windows count
2492 
2493 		if (window->IsNormal() && !window->IsHidden() && window->InWorkspace(index))
2494 			return true;
2495 	}
2496 
2497 	return false;
2498 }
2499 
2500 
2501 uint32
2502 ServerApp::Workspaces() const
2503 {
2504 	uint32 workspaces = 0;
2505 
2506 	BAutolock locker(fWindowListLock);
2507 
2508 	// we could cache this, but then we'd have to recompute the cached
2509 	// value everytime a window has closed or changed workspaces
2510 
2511 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
2512 		ServerWindow* serverWindow = fWindowList.ItemAt(i);
2513 
2514 		const WindowLayer* window = serverWindow->Window();
2515 		if (window == NULL || window->IsOffscreenWindow())
2516 			continue;
2517 
2518 		// only normal and unhidden windows count
2519 
2520 		if (window->IsNormal() && !window->IsHidden())
2521 			workspaces |= window->Workspaces();
2522 	}
2523 
2524 	// TODO: add initial application workspace!
2525 	return workspaces;
2526 }
2527 
2528 
2529 int32
2530 ServerApp::CountBitmaps() const
2531 {
2532 	return fBitmapList.CountItems();
2533 }
2534 
2535 
2536 /*!
2537 	\brief Looks up a ServerApp's ServerBitmap in its list
2538 	\param token ID token of the bitmap to find
2539 	\return The bitmap having that ID or NULL if not found
2540 */
2541 ServerBitmap*
2542 ServerApp::FindBitmap(int32 token) const
2543 {
2544 	// TODO: we need to make sure the bitmap is ours?!
2545 	ServerBitmap* bitmap;
2546 	if (gTokenSpace.GetToken(token, kBitmapToken, (void**)&bitmap) == B_OK)
2547 		return bitmap;
2548 
2549 	return NULL;
2550 }
2551 
2552 
2553 int32
2554 ServerApp::CountPictures() const
2555 {
2556 	return fPictureList.CountItems();
2557 }
2558 
2559 
2560 ServerPicture *
2561 ServerApp::CreatePicture(const ServerPicture *original)
2562 {
2563 	ServerPicture *picture;
2564 	if (original != NULL)
2565 		picture = new (nothrow) ServerPicture(*original);
2566 	else
2567 		picture = new (nothrow) ServerPicture();
2568 
2569 	if (picture != NULL)
2570 		fPictureList.AddItem(picture);
2571 
2572 	return picture;
2573 }
2574 
2575 
2576 ServerPicture *
2577 ServerApp::FindPicture(const int32 &token) const
2578 {
2579 	// TODO: we need to make sure the picture is ours?!
2580 	ServerPicture* picture;
2581 	if (gTokenSpace.GetToken(token, kPictureToken, (void**)&picture) == B_OK)
2582 		return picture;
2583 
2584 	return NULL;
2585 }
2586 
2587 
2588 bool
2589 ServerApp::DeletePicture(const int32 &token)
2590 {
2591 	ServerPicture *picture = FindPicture(token);
2592 	if (picture == NULL)
2593 		return false;
2594 
2595 	if (!fPictureList.RemoveItem(picture))
2596 		return false;
2597 
2598 	delete picture;
2599 
2600 	return true;
2601 }
2602 
2603 
2604 team_id
2605 ServerApp::ClientTeam() const
2606 {
2607 	return fClientTeam;
2608 }
2609 
2610