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