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