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