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