xref: /haiku/src/servers/app/ServerApp.cpp (revision a72f3582be00f2151800fa7da036d7adc14e3272)
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 					if (ServerPicture* subPicture = _FindPicture(token))
926 						picture->NestPicture(subPicture);
927 				}
928 				status = picture->ImportData(link);
929 			}
930 			if (status == B_OK) {
931 				fLink.StartMessage(B_OK);
932 				fLink.Attach<int32>(picture->Token());
933 			} else
934 				fLink.StartMessage(status);
935 
936 			fLink.Flush();
937 			break;
938 		}
939 
940 		case AS_DELETE_PICTURE:
941 		{
942 			STRACE(("ServerApp %s: Delete Picture\n", Signature()));
943 			int32 token;
944 			if (link.Read<int32>(&token) == B_OK) {
945 				BAutolock _(fMapLocker);
946 
947 				ServerPicture* picture = _FindPicture(token);
948 				if (picture != NULL)
949 					picture->SetOwner(NULL);
950 			}
951 			break;
952 		}
953 
954 		case AS_CLONE_PICTURE:
955 		{
956 			STRACE(("ServerApp %s: Clone Picture\n", Signature()));
957 			int32 token;
958 			ServerPicture* original = NULL;
959 			if (link.Read<int32>(&token) == B_OK)
960 				original = GetPicture(token);
961 
962 			if (original != NULL) {
963 				ServerPicture* cloned = CreatePicture(original);
964 				if (cloned != NULL) {
965 					fLink.StartMessage(B_OK);
966 					fLink.Attach<int32>(cloned->Token());
967 				} else
968 					fLink.StartMessage(B_NO_MEMORY);
969 
970 				original->ReleaseReference();
971 			} else
972 				fLink.StartMessage(B_BAD_VALUE);
973 
974 			fLink.Flush();
975 			break;
976 		}
977 
978 		case AS_DOWNLOAD_PICTURE:
979 		{
980 			STRACE(("ServerApp %s: Download Picture\n", Signature()));
981 			int32 token;
982 			link.Read<int32>(&token);
983 			ServerPicture* picture = GetPicture(token);
984 			if (picture != NULL) {
985 				picture->ExportData(fLink);
986 					// ExportData() calls StartMessage() already
987 				picture->ReleaseReference();
988 			} else
989 				fLink.StartMessage(B_ERROR);
990 
991 			fLink.Flush();
992 			break;
993 		}
994 
995 		case AS_CURRENT_WORKSPACE:
996 			STRACE(("ServerApp %s: get current workspace\n", Signature()));
997 
998 			if (fDesktop->LockSingleWindow()) {
999 				fLink.StartMessage(B_OK);
1000 				fLink.Attach<int32>(fDesktop->CurrentWorkspace());
1001 				fDesktop->UnlockSingleWindow();
1002 			} else
1003 				fLink.StartMessage(B_ERROR);
1004 
1005 			fLink.Flush();
1006 			break;
1007 
1008 		case AS_ACTIVATE_WORKSPACE:
1009 		{
1010 			STRACE(("ServerApp %s: activate workspace\n", Signature()));
1011 
1012 			// TODO: See above
1013 			int32 index;
1014 			link.Read<int32>(&index);
1015 
1016 			bool takeFocusWindowThere;
1017 			link.Read<bool>(&takeFocusWindowThere);
1018 
1019 			fDesktop->SetWorkspace(index, takeFocusWindowThere);
1020 			break;
1021 		}
1022 
1023 		case AS_SET_WORKSPACE_LAYOUT:
1024 		{
1025 			int32 newColumns;
1026 			int32 newRows;
1027 			if (link.Read<int32>(&newColumns) == B_OK
1028 				&& link.Read<int32>(&newRows) == B_OK)
1029 				fDesktop->SetWorkspacesLayout(newColumns, newRows);
1030 			break;
1031 		}
1032 
1033 		case AS_GET_WORKSPACE_LAYOUT:
1034 		{
1035 			if (fDesktop->LockSingleWindow()) {
1036 				DesktopSettings settings(fDesktop);
1037 
1038 				fLink.StartMessage(B_OK);
1039 				fLink.Attach<int32>(settings.WorkspacesColumns());
1040 				fLink.Attach<int32>(settings.WorkspacesRows());
1041 
1042 				fDesktop->UnlockSingleWindow();
1043 			} else
1044 				fLink.StartMessage(B_ERROR);
1045 
1046 			fLink.Flush();
1047 			break;
1048 		}
1049 
1050 		case AS_IDLE_TIME:
1051 			STRACE(("ServerApp %s: idle time\n", Signature()));
1052 
1053 			fLink.StartMessage(B_OK);
1054 			fLink.Attach<bigtime_t>(fDesktop->EventDispatcher().IdleTime());
1055 			fLink.Flush();
1056 			break;
1057 
1058 		case AS_SHOW_CURSOR:
1059 		{
1060 			STRACE(("ServerApp %s: Show Cursor\n", Signature()));
1061 			fCursorHideLevel--;
1062 			if (fCursorHideLevel < 0)
1063 				fCursorHideLevel = 0;
1064 			fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0);
1065 			break;
1066 		}
1067 
1068 		case AS_HIDE_CURSOR:
1069 		{
1070 			STRACE(("ServerApp %s: Hide Cursor\n", Signature()));
1071 			fCursorHideLevel++;
1072 			fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0);
1073 			break;
1074 		}
1075 
1076 		case AS_OBSCURE_CURSOR:
1077 		{
1078 			STRACE(("ServerApp %s: Obscure Cursor\n", Signature()));
1079 			fDesktop->HWInterface()->ObscureCursor();
1080 			break;
1081 		}
1082 
1083 		case AS_QUERY_CURSOR_HIDDEN:
1084 		{
1085 			STRACE(("ServerApp %s: Received IsCursorHidden request\n",
1086 				Signature()));
1087 
1088 			fLink.StartMessage(fCursorHideLevel > 0 ? B_OK : B_ERROR);
1089 			fLink.Flush();
1090 			break;
1091 		}
1092 
1093 		case AS_SET_CURSOR:
1094 		{
1095 			STRACE(("ServerApp %s: SetCursor\n", Signature()));
1096 
1097 			// Attached data:
1098 			// 1) bool flag to send a reply
1099 			// 2) int32 token ID of the cursor to set
1100 			// 3) port_id port to receive a reply. Only exists if the sync flag
1101 			//    is true.
1102 			bool sync;
1103 			int32 token;
1104 
1105 			link.Read<bool>(&sync);
1106 			if (link.Read<int32>(&token) != B_OK)
1107 				break;
1108 
1109 			if (!fDesktop->GetCursorManager().Lock())
1110 				break;
1111 
1112 			ServerCursor* oldCursor = fAppCursor;
1113 			fAppCursor = fDesktop->GetCursorManager().FindCursor(token);
1114 			if (fAppCursor != NULL)
1115 				fAppCursor->AcquireReference();
1116 
1117 			if (_HasWindowUnderMouse())
1118 				fDesktop->SetCursor(CurrentCursor());
1119 
1120 			if (oldCursor != NULL)
1121 				oldCursor->ReleaseReference();
1122 
1123 			fDesktop->GetCursorManager().Unlock();
1124 
1125 			if (sync) {
1126 				// The application is expecting a reply
1127 				fLink.StartMessage(B_OK);
1128 				fLink.Flush();
1129 			}
1130 			break;
1131 		}
1132 
1133 		case AS_SET_VIEW_CURSOR:
1134 		{
1135 			STRACE(("ServerApp %s: AS_SET_VIEW_CURSOR:\n", Signature()));
1136 
1137 			ViewSetViewCursorInfo info;
1138 			if (link.Read<ViewSetViewCursorInfo>(&info) != B_OK)
1139 				break;
1140 
1141 			if (fDesktop->GetCursorManager().Lock()) {
1142 				ServerCursor* cursor = fDesktop->GetCursorManager().FindCursor(
1143 					info.cursorToken);
1144 				// If we found a cursor, make sure it doesn't go away. If we
1145 				// get a NULL cursor, it probably means we are supposed to use
1146 				// the system default cursor.
1147 				if (cursor != NULL)
1148 					cursor->AcquireReference();
1149 
1150 				fDesktop->GetCursorManager().Unlock();
1151 
1152 				// We need to acquire the write lock here, since we cannot
1153 				// afford that the window thread to which the view belongs
1154 				// is running and messing with that same view.
1155 				fDesktop->LockAllWindows();
1156 
1157 				// Find the corresponding view by the given token. It's ok
1158 				// if this view does not exist anymore, since it may have
1159 				// already be deleted in the window thread before this
1160 				// message got here.
1161 				View* view;
1162 				if (fViewTokens.GetToken(info.viewToken, B_HANDLER_TOKEN,
1163 					(void**)&view) == B_OK) {
1164 					// Set the cursor on the view.
1165 					view->SetCursor(cursor);
1166 
1167 					// The cursor might need to be updated now.
1168 					Window* window = view->Window();
1169 					if (window != NULL && window->IsFocus()) {
1170 						if (fDesktop->ViewUnderMouse(window) == view->Token())
1171 							SetCurrentCursor(cursor);
1172 					}
1173 				}
1174 
1175 				fDesktop->UnlockAllWindows();
1176 
1177 				// Release the temporary reference.
1178 				if (cursor != NULL)
1179 					cursor->ReleaseReference();
1180 			}
1181 
1182 			if (info.sync) {
1183 				// sync the client (it can now delete the cursor)
1184 				fLink.StartMessage(B_OK);
1185 				fLink.Flush();
1186 			}
1187 			break;
1188 		}
1189 
1190 		case AS_CREATE_CURSOR:
1191 		{
1192 			STRACE(("ServerApp %s: Create Cursor\n", Signature()));
1193 
1194 			// Attached data:
1195 			// 1) 68 bytes of fAppCursor data
1196 			// 2) port_id reply port
1197 
1198 			status_t status = B_ERROR;
1199 			uint8 cursorData[68];
1200 			ServerCursor* cursor = NULL;
1201 
1202 //			if (link.Read(cursorData, sizeof(cursorData)) >= B_OK) {
1203 //				cursor = new (nothrow) ServerCursor(cursorData);
1204 //				if (cursor == NULL)
1205 //					status = B_NO_MEMORY;
1206 //			}
1207 //
1208 //			if (cursor != NULL) {
1209 //				cursor->SetOwningTeam(fClientTeam);
1210 //				fDesktop->GetCursorManager().AddCursor(cursor);
1211 //
1212 //				// Synchronous message - BApplication is waiting on the cursor's ID
1213 //				fLink.StartMessage(B_OK);
1214 //				fLink.Attach<int32>(cursor->Token());
1215 //			} else
1216 //				fLink.StartMessage(status);
1217 
1218 			if (link.Read(cursorData, sizeof(cursorData)) >= B_OK) {
1219 				cursor = fDesktop->GetCursorManager().CreateCursor(fClientTeam,
1220 					cursorData);
1221 				if (cursor == NULL)
1222 					status = B_NO_MEMORY;
1223 			}
1224 
1225 			if (cursor != NULL) {
1226 				// Synchronous message - BApplication is waiting on the
1227 				// cursor's ID
1228 				fLink.StartMessage(B_OK);
1229 				fLink.Attach<int32>(cursor->Token());
1230 			} else
1231 				fLink.StartMessage(status);
1232 
1233 			fLink.Flush();
1234 			break;
1235 		}
1236 
1237 		case AS_REFERENCE_CURSOR:
1238 		{
1239 			STRACE(("ServerApp %s: Reference BCursor\n", Signature()));
1240 
1241 			// Attached data:
1242 			// 1) int32 token ID of the cursor to reference
1243 
1244 			int32 token;
1245 			if (link.Read<int32>(&token) != B_OK)
1246 				break;
1247 
1248 			if (!fDesktop->GetCursorManager().Lock())
1249 				break;
1250 
1251 			ServerCursor* cursor
1252 				= fDesktop->GetCursorManager().FindCursor(token);
1253 			if (cursor != NULL)
1254 				cursor->AcquireReference();
1255 
1256 			fDesktop->GetCursorManager().Unlock();
1257 
1258 			break;
1259 		}
1260 
1261 		case AS_DELETE_CURSOR:
1262 		{
1263 			STRACE(("ServerApp %s: Delete BCursor\n", Signature()));
1264 
1265 			// Attached data:
1266 			// 1) int32 token ID of the cursor to delete
1267 
1268 			int32 token;
1269 			if (link.Read<int32>(&token) != B_OK)
1270 				break;
1271 
1272 			if (!fDesktop->GetCursorManager().Lock())
1273 				break;
1274 
1275 			ServerCursor* cursor
1276 				= fDesktop->GetCursorManager().FindCursor(token);
1277 			if (cursor != NULL)
1278 				cursor->ReleaseReference();
1279 
1280 			fDesktop->GetCursorManager().Unlock();
1281 
1282 			break;
1283 		}
1284 
1285 		case AS_GET_CURSOR_POSITION:
1286 		{
1287 			STRACE(("ServerApp %s: Get Cursor position\n", Signature()));
1288 
1289 			// Returns
1290 			// 1) BPoint mouse location
1291 			// 2) int32 button state
1292 
1293 			BPoint where;
1294 			int32 buttons;
1295 			fDesktop->GetLastMouseState(&where, &buttons);
1296 			fLink.StartMessage(B_OK);
1297 			fLink.Attach<BPoint>(where);
1298 			fLink.Attach<int32>(buttons);
1299 			fLink.Flush();
1300 			break;
1301 		}
1302 
1303 		case AS_GET_CURSOR_BITMAP:
1304 		{
1305 			STRACE(("ServerApp %s: Get Cursor bitmap\n", Signature()));
1306 
1307 			// Returns
1308 			// 1) uint32 number of data bytes of the bitmap
1309 			// 2) uint32 cursor width in number of pixels
1310 			// 3) uint32 cursor height in number of pixels
1311 			// 4) BPoint cursor hot spot
1312 			// 5) cursor bitmap data
1313 
1314 			ServerCursorReference cursorRef = fDesktop->Cursor();
1315 			ServerCursor* cursor = cursorRef.Get();
1316 			if (cursor != NULL) {
1317 				uint32 size = cursor->BitsLength();
1318 				fLink.StartMessage(B_OK);
1319 				fLink.Attach<uint32>(size);
1320 				fLink.Attach<uint32>(cursor->Width());
1321 				fLink.Attach<uint32>(cursor->Height());
1322 				fLink.Attach<BPoint>(cursor->GetHotSpot());
1323 				fLink.Attach(cursor->Bits(), size);
1324 			} else
1325 				fLink.StartMessage(B_ERROR);
1326 
1327 			fLink.Flush();
1328 
1329 			break;
1330 		}
1331 
1332 		case AS_GET_SCROLLBAR_INFO:
1333 		{
1334 			STRACE(("ServerApp %s: Get ScrollBar info\n", Signature()));
1335 
1336 			if (fDesktop->LockSingleWindow()) {
1337 				scroll_bar_info info;
1338 				DesktopSettings settings(fDesktop);
1339 				settings.GetScrollBarInfo(info);
1340 
1341 				fLink.StartMessage(B_OK);
1342 				fLink.Attach<scroll_bar_info>(info);
1343 				fDesktop->UnlockSingleWindow();
1344 			} else
1345 				fLink.StartMessage(B_ERROR);
1346 
1347 			fLink.Flush();
1348 			break;
1349 		}
1350 
1351 		case AS_SET_SCROLLBAR_INFO:
1352 		{
1353 			STRACE(("ServerApp %s: Set ScrollBar info\n", Signature()));
1354 
1355 			// Attached Data:
1356 			// 1) scroll_bar_info scroll bar info structure
1357 
1358 			scroll_bar_info info;
1359 			if (link.Read<scroll_bar_info>(&info) == B_OK) {
1360 				LockedDesktopSettings settings(fDesktop);
1361 				settings.SetScrollBarInfo(info);
1362 			}
1363 
1364 			fLink.StartMessage(B_OK);
1365 			fLink.Flush();
1366 			break;
1367 		}
1368 
1369 		case AS_GET_MENU_INFO:
1370 		{
1371 			STRACE(("ServerApp %s: Get menu info\n", Signature()));
1372 			if (fDesktop->LockSingleWindow()) {
1373 				menu_info info;
1374 				DesktopSettings settings(fDesktop);
1375 				settings.GetMenuInfo(info);
1376 
1377 				fLink.StartMessage(B_OK);
1378 				fLink.Attach<menu_info>(info);
1379 
1380 				fDesktop->UnlockSingleWindow();
1381 			} else
1382 				fLink.StartMessage(B_ERROR);
1383 
1384 			fLink.Flush();
1385 			break;
1386 		}
1387 
1388 		case AS_SET_MENU_INFO:
1389 		{
1390 			STRACE(("ServerApp %s: Set menu info\n", Signature()));
1391 			menu_info info;
1392 			if (link.Read<menu_info>(&info) == B_OK) {
1393 				LockedDesktopSettings settings(fDesktop);
1394 				settings.SetMenuInfo(info);
1395 					// TODO: SetMenuInfo() should do some validity check, so
1396 					//	that the answer we're giving can actually be useful
1397 			}
1398 
1399 			fLink.StartMessage(B_OK);
1400 			fLink.Flush();
1401 			break;
1402 		}
1403 
1404 		case AS_SET_MOUSE_MODE:
1405 		{
1406 			STRACE(("ServerApp %s: Set Mouse Focus mode\n",
1407 				Signature()));
1408 
1409 			// Attached Data:
1410 			// 1) enum mode_mouse mouse focus mode
1411 
1412 			mode_mouse mouseMode;
1413 			if (link.Read<mode_mouse>(&mouseMode) == B_OK) {
1414 				LockedDesktopSettings settings(fDesktop);
1415 				settings.SetMouseMode(mouseMode);
1416 			}
1417 			break;
1418 		}
1419 
1420 		case AS_GET_MOUSE_MODE:
1421 		{
1422 			STRACE(("ServerApp %s: Get Mouse Focus mode\n",
1423 				Signature()));
1424 
1425 			if (fDesktop->LockSingleWindow()) {
1426 				DesktopSettings settings(fDesktop);
1427 
1428 				fLink.StartMessage(B_OK);
1429 				fLink.Attach<mode_mouse>(settings.MouseMode());
1430 
1431 				fDesktop->UnlockSingleWindow();
1432 			} else
1433 				fLink.StartMessage(B_ERROR);
1434 
1435 			fLink.Flush();
1436 			break;
1437 		}
1438 
1439 		case AS_SET_FOCUS_FOLLOWS_MOUSE_MODE:
1440 		{
1441 			STRACE(("ServerApp %s: Set Focus Follows Mouse mode\n", Signature()));
1442 
1443 			// Attached Data:
1444 			// 1) enum mode_focus_follows_mouse FFM mouse mode
1445 
1446 			mode_focus_follows_mouse focusFollowsMousMode;
1447 			if (link.Read<mode_focus_follows_mouse>(&focusFollowsMousMode) == B_OK) {
1448 				LockedDesktopSettings settings(fDesktop);
1449 				settings.SetFocusFollowsMouseMode(focusFollowsMousMode);
1450 			}
1451 			break;
1452 		}
1453 
1454 		case AS_GET_FOCUS_FOLLOWS_MOUSE_MODE:
1455 		{
1456 			STRACE(("ServerApp %s: Get Focus Follows Mouse mode\n", Signature()));
1457 
1458 			if (fDesktop->LockSingleWindow()) {
1459 				DesktopSettings settings(fDesktop);
1460 
1461 				fLink.StartMessage(B_OK);
1462 				fLink.Attach<mode_focus_follows_mouse>(
1463 					settings.FocusFollowsMouseMode());
1464 
1465 				fDesktop->UnlockSingleWindow();
1466 			} else
1467 				fLink.StartMessage(B_ERROR);
1468 
1469 			fLink.Flush();
1470 			break;
1471 		}
1472 
1473 		case AS_SET_ACCEPT_FIRST_CLICK:
1474 		{
1475 			STRACE(("ServerApp %s: Set Accept First Click\n", Signature()));
1476 
1477 			// Attached Data:
1478 			// 1) bool accept_first_click
1479 
1480 			bool acceptFirstClick;
1481 			if (link.Read<bool>(&acceptFirstClick) == B_OK) {
1482 				LockedDesktopSettings settings(fDesktop);
1483 				settings.SetAcceptFirstClick(acceptFirstClick);
1484 			}
1485 			break;
1486 		}
1487 
1488 		case AS_GET_ACCEPT_FIRST_CLICK:
1489 		{
1490 			STRACE(("ServerApp %s: Get Accept First Click\n", Signature()));
1491 
1492 			if (fDesktop->LockSingleWindow()) {
1493 				DesktopSettings settings(fDesktop);
1494 
1495 				fLink.StartMessage(B_OK);
1496 				fLink.Attach<bool>(settings.AcceptFirstClick());
1497 
1498 				fDesktop->UnlockSingleWindow();
1499 			} else
1500 				fLink.StartMessage(B_ERROR);
1501 
1502 			fLink.Flush();
1503 			break;
1504 		}
1505 
1506 		case AS_GET_SHOW_ALL_DRAGGERS:
1507 		{
1508 			STRACE(("ServerApp %s: Get Show All Draggers\n", Signature()));
1509 
1510 			if (fDesktop->LockSingleWindow()) {
1511 				DesktopSettings settings(fDesktop);
1512 
1513 				fLink.StartMessage(B_OK);
1514 				fLink.Attach<bool>(settings.ShowAllDraggers());
1515 
1516 				fDesktop->UnlockSingleWindow();
1517 			} else
1518 				fLink.StartMessage(B_ERROR);
1519 
1520 			fLink.Flush();
1521 			break;
1522 		}
1523 
1524 		case AS_SET_SHOW_ALL_DRAGGERS:
1525 		{
1526 			STRACE(("ServerApp %s: Set Show All Draggers\n", Signature()));
1527 
1528 			bool changed = false;
1529 			bool show;
1530 			if (link.Read<bool>(&show) == B_OK) {
1531 				LockedDesktopSettings settings(fDesktop);
1532 				if (show != settings.ShowAllDraggers()) {
1533 					settings.SetShowAllDraggers(show);
1534 					changed = true;
1535 				}
1536 			}
1537 
1538 			if (changed)
1539 				fDesktop->BroadcastToAllApps(kMsgUpdateShowAllDraggers);
1540 			break;
1541 		}
1542 
1543 		case kMsgUpdateShowAllDraggers:
1544 		{
1545 			bool show = false;
1546 			if (fDesktop->LockSingleWindow()) {
1547 				DesktopSettings settings(fDesktop);
1548 				show = settings.ShowAllDraggers();
1549 				fDesktop->UnlockSingleWindow();
1550 			}
1551 			BMessage update(_SHOW_DRAG_HANDLES_);
1552 			update.AddBool("show", show);
1553 
1554 			SendMessageToClient(&update);
1555 			break;
1556 		}
1557 
1558 		/* font messages */
1559 
1560 		case AS_SET_SYSTEM_FONT:
1561 		{
1562 			FTRACE(("ServerApp %s: AS_SET_SYSTEM_FONT\n", Signature()));
1563 			// gets:
1564 			//	1) string - font type ("plain", ...)
1565 			//	2) string - family
1566 			//	3) string - style
1567 			//	4) float - size
1568 
1569 			char type[B_OS_NAME_LENGTH];
1570 			font_family familyName;
1571 			font_style styleName;
1572 			float size;
1573 
1574 			if (link.ReadString(type, sizeof(type)) == B_OK
1575 				&& link.ReadString(familyName, sizeof(familyName)) == B_OK
1576 				&& link.ReadString(styleName, sizeof(styleName)) == B_OK
1577 				&& link.Read<float>(&size) == B_OK) {
1578 				gFontManager->Lock();
1579 
1580 				FontStyle* style
1581 					= gFontManager->GetStyle(familyName, styleName);
1582 				if (style != NULL) {
1583 					ServerFont font(*style, size);
1584 					gFontManager->Unlock();
1585 						// We must not have locked the font manager when
1586 						// locking the desktop (through LockedDesktopSettings
1587 						// below)
1588 
1589 					LockedDesktopSettings settings(fDesktop);
1590 
1591 					// TODO: Should we also update our internal copies now?
1592 					if (!strcmp(type, "plain"))
1593 						settings.SetDefaultPlainFont(font);
1594 					else if (!strcmp(type, "bold"))
1595 						settings.SetDefaultBoldFont(font);
1596 					else if (!strcmp(type, "fixed"))
1597 						settings.SetDefaultFixedFont(font);
1598 				} else
1599 					gFontManager->Unlock();
1600 			}
1601 			break;
1602 		}
1603 
1604 		case AS_GET_SYSTEM_DEFAULT_FONT:
1605 		{
1606 			// input:
1607 			//	1) string - font type ("plain", ...)
1608 
1609 			ServerFont font;
1610 
1611 			char type[B_OS_NAME_LENGTH];
1612 			status_t status = link.ReadString(type, sizeof(type));
1613 			if (status == B_OK) {
1614 				if (!strcmp(type, "plain")) {
1615 					font = *gFontManager->DefaultPlainFont();
1616 				} else if (!strcmp(type, "bold")) {
1617 					font = *gFontManager->DefaultBoldFont();
1618 				} else if (!strcmp(type, "fixed")) {
1619 					font = *gFontManager->DefaultFixedFont();
1620 				} else
1621 					status = B_BAD_VALUE;
1622 			}
1623 
1624 			if (status == B_OK) {
1625 				// returns:
1626 				//	1) string - family
1627 				//	2) string - style
1628 				//	3) float - size
1629 
1630 				fLink.StartMessage(B_OK);
1631 				fLink.AttachString(font.Family());
1632 				fLink.AttachString(font.Style());
1633 				fLink.Attach<float>(font.Size());
1634 			} else
1635 				fLink.StartMessage(status);
1636 
1637 			fLink.Flush();
1638 			break;
1639 		}
1640 
1641 		case AS_GET_SYSTEM_FONTS:
1642 		{
1643 			FTRACE(("ServerApp %s: AS_GET_SYSTEM_FONTS\n", Signature()));
1644 			// Returns:
1645 			// 1) uint16 - family ID
1646 			// 2) uint16 - style ID
1647 			// 3) float - size in points
1648 			// 4) uint16 - face flags
1649 			// 5) uint32 - font flags
1650 
1651 			if (!fDesktop->LockSingleWindow()) {
1652 				fLink.StartMessage(B_OK);
1653 				fLink.Flush();
1654 				break;
1655 			}
1656 
1657 			// The client is requesting the system fonts, this
1658 			// could happend either at application start up, or
1659 			// because the client is resyncing with the global
1660 			// fonts. So we record the current system wide fonts
1661 			// into our own copies at this point.
1662 			DesktopSettings settings(fDesktop);
1663 
1664 			settings.GetDefaultPlainFont(fPlainFont);
1665 			settings.GetDefaultBoldFont(fBoldFont);
1666 			settings.GetDefaultFixedFont(fFixedFont);
1667 
1668 			fLink.StartMessage(B_OK);
1669 
1670 			for (int32 i = 0; i < 3; i++) {
1671 				ServerFont* font = NULL;
1672 				switch (i) {
1673 					case 0:
1674 						font = &fPlainFont;
1675 						fLink.AttachString("plain");
1676 						break;
1677 
1678 					case 1:
1679 						font = &fBoldFont;
1680 						fLink.AttachString("bold");
1681 						break;
1682 
1683 					case 2:
1684 						font = &fFixedFont;
1685 						fLink.AttachString("fixed");
1686 						break;
1687 				}
1688 
1689 				fLink.Attach<uint16>(font->FamilyID());
1690 				fLink.Attach<uint16>(font->StyleID());
1691 				fLink.Attach<float>(font->Size());
1692 				fLink.Attach<uint16>(font->Face());
1693 				fLink.Attach<uint32>(font->Flags());
1694 			}
1695 
1696 			fDesktop->UnlockSingleWindow();
1697 			fLink.Flush();
1698 			break;
1699 		}
1700 
1701 		case AS_GET_FONT_LIST_REVISION:
1702 		{
1703 			STRACE(("ServerApp %s: AS_GET_FONT_LIST_REVISION\n", Signature()));
1704 
1705 			fLink.StartMessage(B_OK);
1706 			fLink.Attach<int32>(
1707 				gFontManager->CheckRevision(fDesktop->UserID()));
1708 			fLink.Flush();
1709 			break;
1710 		}
1711 
1712 		case AS_GET_FAMILY_AND_STYLES:
1713 		{
1714 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLES\n", Signature()));
1715 
1716 			// Attached Data:
1717 			// 1) int32 the index of the font family to get
1718 
1719 			// Returns:
1720 			// 1) string - name of family
1721 			// 2) uint32 - flags of font family (B_IS_FIXED || B_HAS_TUNED_FONT)
1722 			// 3) count of styles in that family
1723 			// For each style:
1724 			//		1) string - name of style
1725 			//		2) uint16 - face of style
1726 			//		3) uint32 - flags of style
1727 
1728 			int32 index;
1729 			link.Read<int32>(&index);
1730 
1731 			gFontManager->Lock();
1732 
1733 			FontFamily* family = gFontManager->FamilyAt(index);
1734 			if (family) {
1735 				fLink.StartMessage(B_OK);
1736 				fLink.AttachString(family->Name());
1737 				fLink.Attach<uint32>(family->Flags());
1738 
1739 				int32 count = family->CountStyles();
1740 				fLink.Attach<int32>(count);
1741 
1742 				for (int32 i = 0; i < count; i++) {
1743 					FontStyle* style = family->StyleAt(i);
1744 
1745 					fLink.AttachString(style->Name());
1746 					fLink.Attach<uint16>(style->Face());
1747 					fLink.Attach<uint32>(style->Flags());
1748 				}
1749 			} else
1750 				fLink.StartMessage(B_BAD_VALUE);
1751 
1752 			gFontManager->Unlock();
1753 			fLink.Flush();
1754 			break;
1755 		}
1756 
1757 		case AS_GET_FAMILY_AND_STYLE:
1758 		{
1759 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE\n", Signature()));
1760 
1761 			// Attached Data:
1762 			// 1) uint16 - family ID
1763 			// 2) uint16 - style ID
1764 
1765 			// Returns:
1766 			// 1) font_family The name of the font family
1767 			// 2) font_style - name of the style
1768 
1769 			uint16 familyID, styleID;
1770 			link.Read<uint16>(&familyID);
1771 			link.Read<uint16>(&styleID);
1772 
1773 			gFontManager->Lock();
1774 
1775 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1776 			if (fontStyle != NULL) {
1777 				fLink.StartMessage(B_OK);
1778 				fLink.AttachString(fontStyle->Family()->Name());
1779 				fLink.AttachString(fontStyle->Name());
1780 			} else
1781 				fLink.StartMessage(B_BAD_VALUE);
1782 
1783 			fLink.Flush();
1784 			gFontManager->Unlock();
1785 			break;
1786 		}
1787 
1788 		case AS_GET_FAMILY_AND_STYLE_IDS:
1789 		{
1790 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE_IDS\n",
1791 				Signature()));
1792 
1793 			// Attached Data:
1794 			// 1) font_family - name of font family to use
1795 			// 2) font_style - name of style in family
1796 			// 3) family ID - only used if 1) is empty
1797 			// 4) style ID - only used if 2) is empty
1798 			// 5) face - the font's current face
1799 
1800 			// Returns:
1801 			// 1) uint16 - family ID
1802 			// 2) uint16 - style ID
1803 			// 3) uint16 - face
1804 
1805 			font_family family;
1806 			font_style style;
1807 			uint16 familyID, styleID;
1808 			uint16 face;
1809 			if (link.ReadString(family, sizeof(font_family)) == B_OK
1810 				&& link.ReadString(style, sizeof(font_style)) == B_OK
1811 				&& link.Read<uint16>(&familyID) == B_OK
1812 				&& link.Read<uint16>(&styleID) == B_OK
1813 				&& link.Read<uint16>(&face) == B_OK) {
1814 				// get the font and return IDs and face
1815 				gFontManager->Lock();
1816 
1817 				FontStyle *fontStyle = gFontManager->GetStyle(family, style,
1818 					familyID, styleID, face);
1819 
1820 				if (fontStyle != NULL) {
1821 					fLink.StartMessage(B_OK);
1822 					fLink.Attach<uint16>(fontStyle->Family()->ID());
1823 					fLink.Attach<uint16>(fontStyle->ID());
1824 
1825 					// we try to keep the font face close to what we got
1826 					face = fontStyle->PreservedFace(face);
1827 
1828 					fLink.Attach<uint16>(face);
1829 				} else
1830 					fLink.StartMessage(B_NAME_NOT_FOUND);
1831 
1832 				gFontManager->Unlock();
1833 			} else
1834 				fLink.StartMessage(B_BAD_VALUE);
1835 
1836 			fLink.Flush();
1837 			break;
1838 		}
1839 
1840 		case AS_GET_FONT_FILE_FORMAT:
1841 		{
1842 			FTRACE(("ServerApp %s: AS_GET_FONT_FILE_FORMAT\n", Signature()));
1843 
1844 			// Attached Data:
1845 			// 1) uint16 - family ID
1846 			// 2) uint16 - style ID
1847 
1848 			// Returns:
1849 			// 1) uint16 font_file_format of font
1850 
1851 			int32 familyID, styleID;
1852 			link.Read<int32>(&familyID);
1853 			link.Read<int32>(&styleID);
1854 
1855 			gFontManager->Lock();
1856 
1857 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1858 			if (fontStyle) {
1859 				fLink.StartMessage(B_OK);
1860 				fLink.Attach<uint16>((uint16)fontStyle->FileFormat());
1861 			} else
1862 				fLink.StartMessage(B_BAD_VALUE);
1863 
1864 			gFontManager->Unlock();
1865 			fLink.Flush();
1866 			break;
1867 		}
1868 
1869 		case AS_GET_STRING_WIDTHS:
1870 		{
1871 			FTRACE(("ServerApp %s: AS_GET_STRING_WIDTHS\n", Signature()));
1872 
1873 			// Attached Data:
1874 			// 1) uint16 ID of family
1875 			// 2) uint16 ID of style
1876 			// 3) float point size of font
1877 			// 4) uint8 spacing to use
1878 			// 5) int32 numStrings
1879 			// 6) int32 string length to measure (numStrings times)
1880 			// 7) string String to measure (numStrings times)
1881 
1882 			// Returns:
1883 			// 1) float - width of the string in pixels (numStrings times)
1884 
1885 			uint16 family, style;
1886 			float size;
1887 			uint8 spacing;
1888 
1889 			link.Read<uint16>(&family);
1890 			link.Read<uint16>(&style);
1891 			link.Read<float>(&size);
1892 			link.Read<uint8>(&spacing);
1893 			int32 numStrings;
1894 			if (link.Read<int32>(&numStrings) != B_OK) {
1895 				// this results in a B_BAD_VALUE return
1896 				numStrings = 0;
1897 				size = 0.0f;
1898 			}
1899 
1900 			BStackOrHeapArray<float, 64> widthArray(numStrings);
1901 			BStackOrHeapArray<int32, 64> lengthArray(numStrings);
1902 			BStackOrHeapArray<char*, 64> stringArray(numStrings);
1903 			if (!widthArray.IsValid() || !lengthArray.IsValid()
1904 				|| !stringArray.IsValid()) {
1905 				fLink.StartMessage(B_NO_MEMORY);
1906 				fLink.Flush();
1907 				break;
1908 			}
1909 
1910 			for (int32 i = 0; i < numStrings; i++) {
1911 				// This version of ReadString allocates the strings, we free
1912 				// them below
1913 				link.ReadString(&stringArray[i], (size_t *)&lengthArray[i]);
1914 			}
1915 
1916 			ServerFont font;
1917 
1918 			if (font.SetFamilyAndStyle(family, style) == B_OK && size > 0) {
1919 				font.SetSize(size);
1920 				font.SetSpacing(spacing);
1921 
1922 				for (int32 i = 0; i < numStrings; i++) {
1923 					if (!stringArray[i] || lengthArray[i] <= 0)
1924 						widthArray[i] = 0.0;
1925 					else {
1926 						widthArray[i] = font.StringWidth(stringArray[i],
1927 							lengthArray[i]);
1928 					}
1929 				}
1930 
1931 				fLink.StartMessage(B_OK);
1932 				fLink.Attach(widthArray, numStrings * sizeof(float));
1933 			} else
1934 				fLink.StartMessage(B_BAD_VALUE);
1935 
1936 			fLink.Flush();
1937 
1938 			for (int32 i = 0; i < numStrings; i++)
1939 				free(stringArray[i]);
1940 			break;
1941 		}
1942 
1943 		case AS_GET_FONT_BOUNDING_BOX:
1944 		{
1945 			FTRACE(("ServerApp %s: AS_GET_BOUNDING_BOX unimplemented\n",
1946 				Signature()));
1947 
1948 			// Attached Data:
1949 			// 1) uint16 - family ID
1950 			// 2) uint16 - style ID
1951 
1952 			// Returns:
1953 			// 1) BRect - box holding entire font
1954 
1955 			// ToDo: implement me!
1956 			fLink.StartMessage(B_ERROR);
1957 			fLink.Flush();
1958 			break;
1959 		}
1960 
1961 		case AS_GET_TUNED_COUNT:
1962 		{
1963 			FTRACE(("ServerApp %s: AS_GET_TUNED_COUNT\n", Signature()));
1964 
1965 			// Attached Data:
1966 			// 1) uint16 - family ID
1967 			// 2) uint16 - style ID
1968 
1969 			// Returns:
1970 			// 1) int32 - number of font strikes available
1971 
1972 			uint16 familyID, styleID;
1973 			link.Read<uint16>(&familyID);
1974 			link.Read<uint16>(&styleID);
1975 
1976 			gFontManager->Lock();
1977 
1978 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1979 			if (fontStyle != NULL) {
1980 				fLink.StartMessage(B_OK);
1981 				fLink.Attach<int32>(fontStyle->TunedCount());
1982 			} else
1983 				fLink.StartMessage(B_BAD_VALUE);
1984 
1985 			gFontManager->Unlock();
1986 			fLink.Flush();
1987 			break;
1988 		}
1989 
1990 		case AS_GET_TUNED_INFO:
1991 		{
1992 			FTRACE(("ServerApp %s: AS_GET_TUNED_INFO unimplmemented\n",
1993 				Signature()));
1994 
1995 			// Attached Data:
1996 			// 1) uint16 - family ID
1997 			// 2) uint16 - style ID
1998 			// 3) uint32 - index of the particular font strike
1999 
2000 			// Returns:
2001 			// 1) tuned_font_info - info on the strike specified
2002 			// ToDo: implement me!
2003 
2004 			fLink.StartMessage(B_ERROR);
2005 			fLink.Flush();
2006 			break;
2007 		}
2008 
2009 		case AS_GET_EXTRA_FONT_FLAGS:
2010 		{
2011 			FTRACE(("ServerApp %s: AS_GET_EXTRA_FONT_FLAGS\n",
2012 				Signature()));
2013 
2014 			// Attached Data:
2015 			// 1) uint16 - family ID
2016 			// 2) uint16 - style ID
2017 
2018 			// Returns:
2019 			// 1) uint32 - extra font flags
2020 
2021 			uint16 familyID, styleID;
2022 			link.Read<uint16>(&familyID);
2023 			link.Read<uint16>(&styleID);
2024 
2025 			gFontManager->Lock();
2026 
2027 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
2028 			if (fontStyle != NULL) {
2029 				fLink.StartMessage(B_OK);
2030 				fLink.Attach<uint32>(fontStyle->Flags());
2031 			} else
2032 				fLink.StartMessage(B_BAD_VALUE);
2033 
2034 			gFontManager->Unlock();
2035 			fLink.Flush();
2036 			break;
2037 		}
2038 
2039 		case AS_GET_FONT_HEIGHT:
2040 		{
2041 			FTRACE(("ServerApp %s: AS_GET_FONT_HEIGHT\n", Signature()));
2042 
2043 			// Attached Data:
2044 			// 1) uint16 family ID
2045 			// 2) uint16 style ID
2046 			// 3) float size
2047 
2048 			uint16 familyID, styleID;
2049 			float size;
2050 			link.Read<uint16>(&familyID);
2051 			link.Read<uint16>(&styleID);
2052 			link.Read<float>(&size);
2053 
2054 			gFontManager->Lock();
2055 
2056 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
2057 			if (fontStyle != NULL) {
2058 				font_height height;
2059 				fontStyle->GetHeight(size, height);
2060 
2061 				fLink.StartMessage(B_OK);
2062 				fLink.Attach<font_height>(height);
2063 			} else
2064 				fLink.StartMessage(B_BAD_VALUE);
2065 
2066 			gFontManager->Unlock();
2067 			fLink.Flush();
2068 			break;
2069 		}
2070 
2071 		case AS_GET_UNICODE_BLOCKS:
2072 		{
2073 			FTRACE(("ServerApp %s: AS_GET_UNICODE_BLOCKS\n", Signature()));
2074 
2075 			// Attached Data:
2076 			// 1) uint16 family ID
2077 			// 2) uint16 style ID
2078 
2079 			// Returns:
2080 			// 1) unicode_block - bitfield of Unicode blocks in font
2081 
2082 			uint16 familyID, styleID;
2083 			link.Read<uint16>(&familyID);
2084 			link.Read<uint16>(&styleID);
2085 
2086 			ServerFont font;
2087 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2088 			if (status == B_OK) {
2089 				unicode_block blocksForFont;
2090 				font.GetUnicodeBlocks(blocksForFont);
2091 
2092 				fLink.StartMessage(B_OK);
2093 				fLink.Attach<unicode_block>(blocksForFont);
2094 			} else
2095 				fLink.StartMessage(status);
2096 
2097 			fLink.Flush();
2098 			break;
2099 		}
2100 
2101 		case AS_GET_HAS_UNICODE_BLOCK:
2102 		{
2103 			FTRACE(("ServerApp %s: AS_INCLUDES_UNICODE_BLOCK\n", Signature()));
2104 
2105 			// Attached Data:
2106 			// 1) uint16 family ID
2107 			// 2) uint16 style ID
2108 			// 3) uint32 start of unicode block
2109 			// 4) uint32 end of unicode block
2110 
2111 			// Returns:
2112 			// 1) bool - whether or not font includes specified block range
2113 
2114 			uint16 familyID, styleID;
2115 			uint32 start, end;
2116 			link.Read<uint16>(&familyID);
2117 			link.Read<uint16>(&styleID);
2118 			link.Read<uint32>(&start);
2119 			link.Read<uint32>(&end);
2120 
2121 			ServerFont font;
2122 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2123 			if (status == B_OK) {
2124 				bool hasBlock;
2125 
2126 				status = font.IncludesUnicodeBlock(start, end, hasBlock);
2127 				fLink.StartMessage(status);
2128 				fLink.Attach<bool>(hasBlock);
2129 			} else
2130 				fLink.StartMessage(status);
2131 
2132 			fLink.Flush();
2133 			break;
2134 		}
2135 
2136 		case AS_GET_GLYPH_SHAPES:
2137 		{
2138 			FTRACE(("ServerApp %s: AS_GET_GLYPH_SHAPES\n", Signature()));
2139 
2140 			// Attached Data:
2141 			// 1) uint16 - family ID
2142 			// 2) uint16 - style ID
2143 			// 3) float - point size
2144 			// 4) float - shear
2145 			// 5) float - rotation
2146 			// 6) float - false bold width
2147 			// 6) uint32 - flags
2148 			// 7) int32 - numChars
2149 			// 8) int32 - numBytes
2150 			// 8) char - chars (numBytes times)
2151 
2152 			// Returns:
2153 			// 1) BShape - glyph shape
2154 			// numChars times
2155 
2156 			uint16 familyID, styleID;
2157 			uint32 flags;
2158 			float size, shear, rotation, falseBoldWidth;
2159 
2160 			link.Read<uint16>(&familyID);
2161 			link.Read<uint16>(&styleID);
2162 			link.Read<float>(&size);
2163 			link.Read<float>(&shear);
2164 			link.Read<float>(&rotation);
2165 			link.Read<float>(&falseBoldWidth);
2166 			link.Read<uint32>(&flags);
2167 
2168 			int32 numChars, numBytes;
2169 			link.Read<int32>(&numChars);
2170 			link.Read<int32>(&numBytes);
2171 
2172 			BStackOrHeapArray<char, 256> charArray(numBytes);
2173 			BStackOrHeapArray<BShape*, 64> shapes(numChars);
2174 			if (!charArray.IsValid() || !shapes.IsValid()) {
2175 				fLink.StartMessage(B_NO_MEMORY);
2176 				fLink.Flush();
2177 				break;
2178 			}
2179 
2180 			link.Read(charArray, numBytes);
2181 
2182 			ServerFont font;
2183 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2184 			if (status == B_OK) {
2185 				font.SetSize(size);
2186 				font.SetShear(shear);
2187 				font.SetRotation(rotation);
2188 				font.SetFalseBoldWidth(falseBoldWidth);
2189 				font.SetFlags(flags);
2190 
2191 				status = font.GetGlyphShapes(charArray, numChars, shapes);
2192 				if (status == B_OK) {
2193 					fLink.StartMessage(B_OK);
2194 					for (int32 i = 0; i < numChars; i++) {
2195 						fLink.AttachShape(*shapes[i]);
2196 						delete shapes[i];
2197 					}
2198 				}
2199 			}
2200 
2201 			if (status != B_OK)
2202 				fLink.StartMessage(status);
2203 
2204 			fLink.Flush();
2205 			break;
2206 		}
2207 
2208 		case AS_GET_HAS_GLYPHS:
2209 		{
2210 			FTRACE(("ServerApp %s: AS_GET_HAS_GLYPHS\n", Signature()));
2211 
2212 			// Attached Data:
2213 			// 1) uint16 - family ID
2214 			// 2) uint16 - style ID
2215 			// 3) int32 - numChars
2216 			// 4) int32 - numBytes
2217 			// 5) char - the char buffer with size numBytes
2218 
2219 			uint16 familyID, styleID;
2220 			link.Read<uint16>(&familyID);
2221 			link.Read<uint16>(&styleID);
2222 
2223 			int32 numChars, numBytes;
2224 			link.Read<int32>(&numChars);
2225 			link.Read<int32>(&numBytes);
2226 
2227 			BStackOrHeapArray<char, 256> charArray(numBytes);
2228 			BStackOrHeapArray<bool, 256> hasArray(numChars);
2229 			if (!charArray.IsValid() || !hasArray.IsValid()) {
2230 				fLink.StartMessage(B_NO_MEMORY);
2231 				fLink.Flush();
2232 				break;
2233 			}
2234 
2235 			link.Read(charArray, numBytes);
2236 
2237 			ServerFont font;
2238 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2239 			if (status == B_OK) {
2240 				status = font.GetHasGlyphs(charArray, numBytes, numChars,
2241 					hasArray);
2242 				if (status == B_OK) {
2243 					fLink.StartMessage(B_OK);
2244 					fLink.Attach(hasArray, numChars * sizeof(bool));
2245 				}
2246 			}
2247 
2248 			if (status != B_OK)
2249 				fLink.StartMessage(status);
2250 
2251 			fLink.Flush();
2252 			break;
2253 		}
2254 
2255 		case AS_GET_EDGES:
2256 		{
2257 			FTRACE(("ServerApp %s: AS_GET_EDGES\n", Signature()));
2258 
2259 			// Attached Data:
2260 			// 1) uint16 - family ID
2261 			// 2) uint16 - style ID
2262 			// 3) int32 - numChars
2263 			// 4) int32 - numBytes
2264 			// 5) char - the char buffer with size numBytes
2265 
2266 			uint16 familyID, styleID;
2267 			link.Read<uint16>(&familyID);
2268 			link.Read<uint16>(&styleID);
2269 
2270 			int32 numChars;
2271 			link.Read<int32>(&numChars);
2272 
2273 			uint32 numBytes;
2274 			link.Read<uint32>(&numBytes);
2275 
2276 			BStackOrHeapArray<char, 256> charArray(numBytes);
2277 			BStackOrHeapArray<edge_info, 64> edgeArray(numChars);
2278 			if (!charArray.IsValid() || !edgeArray.IsValid()) {
2279 				fLink.StartMessage(B_NO_MEMORY);
2280 				fLink.Flush();
2281 				break;
2282 			}
2283 
2284 			link.Read(charArray, numBytes);
2285 
2286 			ServerFont font;
2287 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2288 			if (status == B_OK) {
2289 				status = font.GetEdges(charArray, numBytes, numChars,
2290 					edgeArray);
2291 				if (status == B_OK) {
2292 					fLink.StartMessage(B_OK);
2293 					fLink.Attach(edgeArray, numChars * sizeof(edge_info));
2294 				}
2295 			}
2296 
2297 			if (status != B_OK)
2298 				fLink.StartMessage(status);
2299 
2300 			fLink.Flush();
2301 			break;
2302 		}
2303 
2304 		case AS_GET_ESCAPEMENTS:
2305 		{
2306 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS\n", Signature()));
2307 
2308 			// Attached Data:
2309 			// 1) uint16 - family ID
2310 			// 2) uint16 - style ID
2311 			// 3) float - point size
2312 			// 4) uint8 - spacing
2313 			// 5) float - rotation
2314 			// 6) uint32 - flags
2315 			// 7) int32 - numChars
2316 			// 8) char - char     -\       both
2317 			// 9) BPoint - offset -/ (numChars times)
2318 
2319 			// Returns:
2320 			// 1) BPoint - escapement
2321 			// numChars times
2322 
2323 			uint16 familyID, styleID;
2324 			uint32 flags;
2325 			float size, rotation;
2326 			uint8 spacing;
2327 
2328 			link.Read<uint16>(&familyID);
2329 			link.Read<uint16>(&styleID);
2330 			link.Read<float>(&size);
2331 			link.Read<uint8>(&spacing);
2332 			link.Read<float>(&rotation);
2333 			link.Read<uint32>(&flags);
2334 
2335 			escapement_delta delta;
2336 			link.Read<float>(&delta.nonspace);
2337 			link.Read<float>(&delta.space);
2338 
2339 			bool wantsOffsets;
2340 			link.Read<bool>(&wantsOffsets);
2341 
2342 			int32 numChars;
2343 			link.Read<int32>(&numChars);
2344 
2345 			uint32 numBytes;
2346 			link.Read<uint32>(&numBytes);
2347 
2348 			BStackOrHeapArray<char, 256> charArray(numBytes);
2349 			BStackOrHeapArray<BPoint, 64> escapements(numChars);
2350 			BPoint* offsets = NULL;
2351 			if (wantsOffsets)
2352 				offsets = new(std::nothrow) BPoint[numChars];
2353 
2354 			if (!charArray.IsValid() || !escapements.IsValid()
2355 				|| (offsets == NULL && wantsOffsets)) {
2356 				delete[] offsets;
2357 				fLink.StartMessage(B_NO_MEMORY);
2358 				fLink.Flush();
2359 				break;
2360 			}
2361 
2362 			link.Read(charArray, numBytes);
2363 
2364 			ServerFont font;
2365 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2366 			if (status == B_OK) {
2367 				font.SetSize(size);
2368 				font.SetSpacing(spacing);
2369 				font.SetRotation(rotation);
2370 				font.SetFlags(flags);
2371 
2372 				status = font.GetEscapements(charArray, numBytes, numChars,
2373 					delta, escapements, offsets);
2374 
2375 				if (status == B_OK) {
2376 					fLink.StartMessage(B_OK);
2377 					for (int32 i = 0; i < numChars; i++)
2378 						fLink.Attach<BPoint>(escapements[i]);
2379 
2380 					if (wantsOffsets) {
2381 						for (int32 i = 0; i < numChars; i++)
2382 							fLink.Attach<BPoint>(offsets[i]);
2383 					}
2384 				}
2385 			}
2386 
2387 			if (status != B_OK)
2388 				fLink.StartMessage(status);
2389 
2390 			delete[] offsets;
2391 			fLink.Flush();
2392 			break;
2393 		}
2394 
2395 		case AS_GET_ESCAPEMENTS_AS_FLOATS:
2396 		{
2397 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS_AS_FLOATS\n", Signature()));
2398 
2399 			// Attached Data:
2400 			// 1) uint16 - family ID
2401 			// 2) uint16 - style ID
2402 			// 3) float - point size
2403 			// 4) uint8 - spacing
2404 			// 5) float - rotation
2405 			// 6) uint32 - flags
2406 			// 7) float - additional "nonspace" delta
2407 			// 8) float - additional "space" delta
2408 			// 9) int32 - numChars
2409 			// 10) int32 - numBytes
2410 			// 11) char - the char buffer with size numBytes
2411 
2412 			// Returns:
2413 			// 1) float - escapement buffer with numChar entries
2414 
2415 			uint16 familyID, styleID;
2416 			uint32 flags;
2417 			float size, rotation;
2418 			uint8 spacing;
2419 
2420 			link.Read<uint16>(&familyID);
2421 			link.Read<uint16>(&styleID);
2422 			link.Read<float>(&size);
2423 			link.Read<uint8>(&spacing);
2424 			link.Read<float>(&rotation);
2425 			link.Read<uint32>(&flags);
2426 
2427 			escapement_delta delta;
2428 			link.Read<float>(&delta.nonspace);
2429 			link.Read<float>(&delta.space);
2430 
2431 			int32 numChars;
2432 			link.Read<int32>(&numChars);
2433 
2434 			uint32 numBytes;
2435 			link.Read<uint32>(&numBytes);
2436 
2437 			BStackOrHeapArray<char, 256> charArray(numBytes);
2438 			BStackOrHeapArray<float, 64> escapements(numChars);
2439 			if (!charArray.IsValid() || !escapements.IsValid()) {
2440 				fLink.StartMessage(B_NO_MEMORY);
2441 				fLink.Flush();
2442 				break;
2443 			}
2444 
2445 			link.Read(charArray, numBytes);
2446 
2447 			// figure out escapements
2448 
2449 			ServerFont font;
2450 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2451 			if (status == B_OK) {
2452 				font.SetSize(size);
2453 				font.SetSpacing(spacing);
2454 				font.SetRotation(rotation);
2455 				font.SetFlags(flags);
2456 
2457 				status = font.GetEscapements(charArray, numBytes, numChars,
2458 					delta, escapements);
2459 
2460 				if (status == B_OK) {
2461 					fLink.StartMessage(B_OK);
2462 					fLink.Attach(escapements, numChars * sizeof(float));
2463 				}
2464 			}
2465 
2466 			if (status != B_OK)
2467 				fLink.StartMessage(status);
2468 
2469 			fLink.Flush();
2470 			break;
2471 		}
2472 
2473 		case AS_GET_BOUNDINGBOXES_CHARS:
2474 		case AS_GET_BOUNDINGBOXES_STRING:
2475 		{
2476 			FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_CHARS\n", Signature()));
2477 
2478 			// Attached Data:
2479 			// 1) uint16 - family ID
2480 			// 2) uint16 - style ID
2481 			// 3) float - point size
2482 			// 4) float - rotation
2483 			// 5) float - shear
2484 			// 6) float - false bold width
2485 			// 7) uint8 - spacing
2486 			// 8) uint32 - flags
2487 			// 9) font_metric_mode - mode
2488 			// 10) bool - string escapement
2489 			// 11) escapement_delta - additional delta
2490 			// 12) int32 - numChars
2491 			// 13) int32 - numBytes
2492 			// 14) char - the char buffer with size numBytes
2493 
2494 			// Returns:
2495 			// 1) BRect - rects with numChar entries
2496 
2497 			uint16 familyID, styleID;
2498 			uint32 flags;
2499 			float size, rotation, shear, falseBoldWidth;
2500 			uint8 spacing;
2501 			font_metric_mode mode;
2502 			bool stringEscapement;
2503 
2504 			link.Read<uint16>(&familyID);
2505 			link.Read<uint16>(&styleID);
2506 			link.Read<float>(&size);
2507 			link.Read<float>(&rotation);
2508 			link.Read<float>(&shear);
2509 			link.Read<float>(&falseBoldWidth);
2510 			link.Read<uint8>(&spacing);
2511 			link.Read<uint32>(&flags);
2512 			link.Read<font_metric_mode>(&mode);
2513 			link.Read<bool>(&stringEscapement);
2514 
2515 			escapement_delta delta;
2516 			link.Read<escapement_delta>(&delta);
2517 
2518 			int32 numChars;
2519 			link.Read<int32>(&numChars);
2520 
2521 			uint32 numBytes;
2522 			link.Read<uint32>(&numBytes);
2523 
2524 			BStackOrHeapArray<char, 256> charArray(numBytes);
2525 			BStackOrHeapArray<BRect, 64> rectArray(numChars);
2526 			if (!charArray.IsValid() || !rectArray.IsValid()) {
2527 				fLink.StartMessage(B_NO_MEMORY);
2528 				fLink.Flush();
2529 				break;
2530 			}
2531 
2532 			link.Read(charArray, numBytes);
2533 
2534 			// figure out escapements
2535 
2536 			ServerFont font;
2537 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2538 			if (status == B_OK) {
2539 				font.SetSize(size);
2540 				font.SetRotation(rotation);
2541 				font.SetShear(shear);
2542 				font.SetFalseBoldWidth(falseBoldWidth);
2543 				font.SetSpacing(spacing);
2544 				font.SetFlags(flags);
2545 
2546 				// TODO: implement for real
2547 				status = font.GetBoundingBoxes(charArray, numBytes,
2548 					numChars, rectArray, stringEscapement, mode, delta,
2549 					code == AS_GET_BOUNDINGBOXES_STRING);
2550 				if (status == B_OK) {
2551 					fLink.StartMessage(B_OK);
2552 					for (int32 i = 0; i < numChars; i++)
2553 						fLink.Attach<BRect>(rectArray[i]);
2554 				}
2555 			}
2556 
2557 			if (status != B_OK)
2558 				fLink.StartMessage(status);
2559 
2560 			fLink.Flush();
2561 			break;
2562 		}
2563 
2564 		case AS_GET_BOUNDINGBOXES_STRINGS:
2565 		{
2566 			FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_STRINGS\n",
2567 				Signature()));
2568 
2569 			// Attached Data:
2570 			// 1) uint16 - family ID
2571 			// 2) uint16 - style ID
2572 			// 3) float - point size
2573 			// 4) float - rotation
2574 			// 5) float - shear
2575 			// 6) float - false bold width
2576 			// 7) uint8 - spacing
2577 			// 8) uint32 - flags
2578 			// 9) font_metric_mode - mode
2579 			// 10) int32 numStrings
2580 			// 11) escapement_delta - additional delta (numStrings times)
2581 			// 12) int32 string length to measure (numStrings times)
2582 			// 13) string - string (numStrings times)
2583 
2584 			// Returns:
2585 			// 1) BRect - rects with numStrings entries
2586 
2587 			uint16 familyID, styleID;
2588 			uint32 flags;
2589 			float ptsize, rotation, shear, falseBoldWidth;
2590 			uint8 spacing;
2591 			font_metric_mode mode;
2592 
2593 			link.Read<uint16>(&familyID);
2594 			link.Read<uint16>(&styleID);
2595 			link.Read<float>(&ptsize);
2596 			link.Read<float>(&rotation);
2597 			link.Read<float>(&shear);
2598 			link.Read<float>(&falseBoldWidth);
2599 			link.Read<uint8>(&spacing);
2600 			link.Read<uint32>(&flags);
2601 			link.Read<font_metric_mode>(&mode);
2602 
2603 			int32 numStrings;
2604 			link.Read<int32>(&numStrings);
2605 
2606 			BStackOrHeapArray<escapement_delta, 64> deltaArray(numStrings);
2607 			BStackOrHeapArray<char*, 64> stringArray(numStrings);
2608 			BStackOrHeapArray<size_t, 64> lengthArray(numStrings);
2609 			BStackOrHeapArray<BRect, 64> rectArray(numStrings);
2610 			if (!deltaArray.IsValid() || !stringArray.IsValid()
2611 				|| !lengthArray.IsValid() || !rectArray.IsValid()) {
2612 				fLink.StartMessage(B_NO_MEMORY);
2613 				fLink.Flush();
2614 				break;
2615 			}
2616 
2617 			for (int32 i = 0; i < numStrings; i++) {
2618 				// This version of ReadString allocates the strings, we free
2619 				// them below
2620 				link.ReadString(&stringArray[i], &lengthArray[i]);
2621 				link.Read<escapement_delta>(&deltaArray[i]);
2622 			}
2623 
2624 			ServerFont font;
2625 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2626 			if (status == B_OK) {
2627 				font.SetSize(ptsize);
2628 				font.SetRotation(rotation);
2629 				font.SetShear(shear);
2630 				font.SetFalseBoldWidth(falseBoldWidth);
2631 				font.SetSpacing(spacing);
2632 				font.SetFlags(flags);
2633 
2634 				status = font.GetBoundingBoxesForStrings(stringArray,
2635 					lengthArray, numStrings, rectArray, mode, deltaArray);
2636 				if (status == B_OK) {
2637 					fLink.StartMessage(B_OK);
2638 					fLink.Attach(rectArray, numStrings * sizeof(BRect));
2639 				}
2640 			}
2641 
2642 			for (int32 i = 0; i < numStrings; i++)
2643 				free(stringArray[i]);
2644 
2645 			if (status != B_OK)
2646 				fLink.StartMessage(status);
2647 
2648 			fLink.Flush();
2649 			break;
2650 		}
2651 
2652 		// Screen commands
2653 
2654 		case AS_VALID_SCREEN_ID:
2655 		{
2656 			// Attached data
2657 			// 1) int32 screen
2658 
2659 			int32 id;
2660 			if (link.Read<int32>(&id) == B_OK
2661 				&& id == B_MAIN_SCREEN_ID.id)
2662 				fLink.StartMessage(B_OK);
2663 			else
2664 				fLink.StartMessage(B_ERROR);
2665 
2666 			fLink.Flush();
2667 			break;
2668 		}
2669 
2670 		case AS_GET_NEXT_SCREEN_ID:
2671 		{
2672 			// Attached data
2673 			// 1) int32 screen
2674 
2675 			int32 id;
2676 			link.Read<int32>(&id);
2677 
2678 			// TODO: for now, just say we're the last one
2679 			fLink.StartMessage(B_ENTRY_NOT_FOUND);
2680 			fLink.Flush();
2681 			break;
2682 		}
2683 
2684 		case AS_GET_SCREEN_ID_FROM_WINDOW:
2685 		{
2686 			status_t status = B_BAD_VALUE;
2687 
2688 			// Attached data
2689 			// 1) int32 - window client token
2690 
2691 			int32 clientToken;
2692 			if (link.Read<int32>(&clientToken) != B_OK)
2693 				status = B_BAD_DATA;
2694 			else {
2695 				BAutolock locker(fWindowListLock);
2696 
2697 				for (int32 i = fWindowList.CountItems(); i-- > 0;) {
2698 					ServerWindow* serverWindow = fWindowList.ItemAt(i);
2699 
2700 					if (serverWindow->ClientToken() == clientToken) {
2701 						AutoReadLocker _(fDesktop->ScreenLocker());
2702 
2703 						// found it!
2704 						Window* window = serverWindow->Window();
2705 						const Screen* screen = NULL;
2706 						if (window != NULL)
2707 							screen = window->Screen();
2708 
2709 						if (screen == NULL) {
2710 							// The window hasn't been added to the desktop yet,
2711 							// or it's an offscreen window
2712 							break;
2713 						}
2714 
2715 						fLink.StartMessage(B_OK);
2716 						fLink.Attach<int32>(screen->ID());
2717 						status = B_OK;
2718 						break;
2719 					}
2720 				}
2721 			}
2722 
2723 			if (status != B_OK)
2724 				fLink.StartMessage(status);
2725 			fLink.Flush();
2726 			break;
2727 		}
2728 
2729 		case AS_SCREEN_GET_MODE:
2730 		{
2731 			STRACE(("ServerApp %s: AS_SCREEN_GET_MODE\n", Signature()));
2732 
2733 			// Attached data
2734 			// 1) int32 screen
2735 			// 2) uint32 workspace index
2736 
2737 			int32 id;
2738 			link.Read<int32>(&id);
2739 			uint32 workspace;
2740 			link.Read<uint32>(&workspace);
2741 
2742 			display_mode mode;
2743 			status_t status = fDesktop->GetScreenMode(workspace, id, mode);
2744 
2745 			fLink.StartMessage(status);
2746 			if (status == B_OK)
2747 				fLink.Attach<display_mode>(mode);
2748 			fLink.Flush();
2749 			break;
2750 		}
2751 
2752 		case AS_SCREEN_SET_MODE:
2753 		{
2754 			STRACE(("ServerApp %s: AS_SCREEN_SET_MODE\n", Signature()));
2755 
2756 			// Attached data
2757 			// 1) int32 screen
2758 			// 2) workspace index
2759 			// 3) display_mode to set
2760 			// 4) 'makeDefault' boolean
2761 
2762 			int32 id;
2763 			link.Read<int32>(&id);
2764 			uint32 workspace;
2765 			link.Read<uint32>(&workspace);
2766 
2767 			display_mode mode;
2768 			link.Read<display_mode>(&mode);
2769 
2770 			bool makeDefault = false;
2771 			status_t status = link.Read<bool>(&makeDefault);
2772 
2773 			if (status == B_OK) {
2774 				status = fDesktop->SetScreenMode(workspace, id, mode,
2775 					makeDefault);
2776 			}
2777 			if (status == B_OK) {
2778 				if (workspace == (uint32)B_CURRENT_WORKSPACE_INDEX
2779 					&& fDesktop->LockSingleWindow()) {
2780 					workspace = fDesktop->CurrentWorkspace();
2781 					fDesktop->UnlockSingleWindow();
2782 				}
2783 
2784 				if (!makeDefault) {
2785 					// Memorize the screen change, so that it can be reverted
2786 					// later
2787 					fTemporaryDisplayModeChange |= 1 << workspace;
2788 				} else
2789 					fTemporaryDisplayModeChange &= ~(1 << workspace);
2790 			}
2791 
2792 			fLink.StartMessage(status);
2793 			fLink.Flush();
2794 			break;
2795 		}
2796 
2797 		case AS_PROPOSE_MODE:
2798 		{
2799 			STRACE(("ServerApp %s: AS_PROPOSE_MODE\n", Signature()));
2800 			int32 id;
2801 			link.Read<int32>(&id);
2802 
2803 			display_mode target, low, high;
2804 			link.Read<display_mode>(&target);
2805 			link.Read<display_mode>(&low);
2806 			link.Read<display_mode>(&high);
2807 			status_t status = fDesktop->HWInterface()->ProposeMode(&target,
2808 				&low, &high);
2809 
2810 			// ProposeMode() returns B_BAD_VALUE to hint that the candidate is
2811 			// not within the given limits (but is supported)
2812 			if (status == B_OK || status == B_BAD_VALUE) {
2813 				fLink.StartMessage(B_OK);
2814 				fLink.Attach<display_mode>(target);
2815 				fLink.Attach<bool>(status == B_OK);
2816 			} else
2817 				fLink.StartMessage(status);
2818 
2819 			fLink.Flush();
2820 			break;
2821 		}
2822 
2823 		case AS_GET_MODE_LIST:
2824 		{
2825 			int32 id;
2826 			link.Read<int32>(&id);
2827 			// TODO: use this screen id
2828 
2829 			display_mode* modeList;
2830 			uint32 count;
2831 			status_t status = fDesktop->HWInterface()->GetModeList(&modeList,
2832 				&count);
2833 			if (status == B_OK) {
2834 				fLink.StartMessage(B_OK);
2835 				fLink.Attach<uint32>(count);
2836 				fLink.Attach(modeList, sizeof(display_mode) * count);
2837 
2838 				delete[] modeList;
2839 			} else
2840 				fLink.StartMessage(status);
2841 
2842 			fLink.Flush();
2843 			break;
2844 		}
2845 
2846 		case AS_GET_SCREEN_FRAME:
2847 		{
2848 			STRACE(("ServerApp %s: AS_GET_SCREEN_FRAME\n", Signature()));
2849 
2850 			// Attached data
2851 			// 1) int32 screen
2852 			// 2) uint32 workspace index
2853 
2854 			int32 id;
2855 			link.Read<int32>(&id);
2856 			uint32 workspace;
2857 			link.Read<uint32>(&workspace);
2858 
2859 			BRect frame;
2860 			status_t status = fDesktop->GetScreenFrame(workspace, id, frame);
2861 
2862 			fLink.StartMessage(status);
2863 			if (status == B_OK)
2864 				fLink.Attach<BRect>(frame);
2865 
2866 			fLink.Flush();
2867 			break;
2868 		}
2869 
2870 		case AS_SCREEN_GET_COLORMAP:
2871 		{
2872 			STRACE(("ServerApp %s: AS_SCREEN_GET_COLORMAP\n", Signature()));
2873 
2874 			int32 id;
2875 			link.Read<int32>(&id);
2876 
2877 			const color_map* colorMap = SystemColorMap();
2878 			if (colorMap != NULL) {
2879 				fLink.StartMessage(B_OK);
2880 				fLink.Attach<color_map>(*colorMap);
2881 			} else
2882 				fLink.StartMessage(B_ERROR);
2883 
2884 			fLink.Flush();
2885 			break;
2886 		}
2887 
2888 		case AS_GET_DESKTOP_COLOR:
2889 		{
2890 			STRACE(("ServerApp %s: get desktop color\n", Signature()));
2891 
2892 			uint32 index;
2893 			link.Read<uint32>(&index);
2894 
2895 			fLink.StartMessage(B_OK);
2896 			fDesktop->LockSingleWindow();
2897 
2898 			// we're nice to our children (and also take the default case
2899 			// into account which asks for the current workspace)
2900 			if (index >= (uint32)kMaxWorkspaces)
2901 				index = fDesktop->CurrentWorkspace();
2902 
2903 			Workspace workspace(*fDesktop, index, true);
2904 			fLink.Attach<rgb_color>(workspace.Color());
2905 
2906 			fDesktop->UnlockSingleWindow();
2907 			fLink.Flush();
2908 			break;
2909 		}
2910 
2911 		case AS_SET_DESKTOP_COLOR:
2912 		{
2913 			STRACE(("ServerApp %s: set desktop color\n", Signature()));
2914 
2915 			rgb_color color;
2916 			uint32 index;
2917 			bool makeDefault;
2918 
2919 			link.Read<rgb_color>(&color);
2920 			link.Read<uint32>(&index);
2921 			if (link.Read<bool>(&makeDefault) != B_OK)
2922 				break;
2923 
2924 			fDesktop->LockAllWindows();
2925 
2926 			// we're nice to our children (and also take the default case
2927 			// into account which asks for the current workspace)
2928 			if (index >= (uint32)kMaxWorkspaces)
2929 				index = fDesktop->CurrentWorkspace();
2930 
2931 			Workspace workspace(*fDesktop, index);
2932 			workspace.SetColor(color, makeDefault);
2933 
2934 			fDesktop->UnlockAllWindows();
2935 			break;
2936 		}
2937 
2938 		case AS_GET_ACCELERANT_INFO:
2939 		{
2940 			STRACE(("ServerApp %s: get accelerant info\n", Signature()));
2941 
2942 			// We aren't using the screen_id for now...
2943 			int32 id;
2944 			link.Read<int32>(&id);
2945 
2946 			accelerant_device_info accelerantInfo;
2947 			// TODO: I wonder if there should be a "desktop" lock...
2948 			status_t status
2949 				= fDesktop->HWInterface()->GetDeviceInfo(&accelerantInfo);
2950 			if (status == B_OK) {
2951 				fLink.StartMessage(B_OK);
2952 				fLink.Attach<accelerant_device_info>(accelerantInfo);
2953 			} else
2954 				fLink.StartMessage(status);
2955 
2956 			fLink.Flush();
2957 			break;
2958 		}
2959 
2960 		case AS_GET_MONITOR_INFO:
2961 		{
2962 			STRACE(("ServerApp %s: get monitor info\n", Signature()));
2963 
2964 			// We aren't using the screen_id for now...
2965 			int32 id;
2966 			link.Read<int32>(&id);
2967 
2968 			monitor_info info;
2969 			// TODO: I wonder if there should be a "desktop" lock...
2970 			status_t status = fDesktop->HWInterface()->GetMonitorInfo(&info);
2971 			if (status == B_OK) {
2972 				fLink.StartMessage(B_OK);
2973 				fLink.Attach<monitor_info>(info);
2974 			} else
2975 				fLink.StartMessage(status);
2976 
2977 			fLink.Flush();
2978 			break;
2979 		}
2980 
2981 		case AS_GET_FRAME_BUFFER_CONFIG:
2982 		{
2983 			STRACE(("ServerApp %s: get frame buffer config\n", Signature()));
2984 
2985 			// We aren't using the screen_id for now...
2986 			int32 id;
2987 			link.Read<int32>(&id);
2988 
2989 			frame_buffer_config config;
2990 			// TODO: I wonder if there should be a "desktop" lock...
2991 			status_t status = fDesktop->HWInterface()->GetFrameBufferConfig(config);
2992 			if (status == B_OK) {
2993 				fLink.StartMessage(B_OK);
2994 				fLink.Attach<frame_buffer_config>(config);
2995 			} else
2996 				fLink.StartMessage(status);
2997 
2998 			fLink.Flush();
2999 			break;
3000 		}
3001 
3002 		case AS_GET_RETRACE_SEMAPHORE:
3003 		{
3004 			STRACE(("ServerApp %s: get retrace semaphore\n", Signature()));
3005 
3006 			// We aren't using the screen_id for now...
3007 			int32 id;
3008 			link.Read<int32>(&id);
3009 
3010 			fLink.StartMessage(B_OK);
3011 			fLink.Attach<sem_id>(fDesktop->HWInterface()->RetraceSemaphore());
3012 			fLink.Flush();
3013 			break;
3014 		}
3015 
3016 		case AS_GET_TIMING_CONSTRAINTS:
3017 		{
3018 			STRACE(("ServerApp %s: get timing constraints\n", Signature()));
3019 
3020 			// We aren't using the screen_id for now...
3021 			int32 id;
3022 			link.Read<int32>(&id);
3023 
3024 			display_timing_constraints constraints;
3025 			status_t status = fDesktop->HWInterface()->GetTimingConstraints(
3026 				&constraints);
3027 			if (status == B_OK) {
3028 				fLink.StartMessage(B_OK);
3029 				fLink.Attach<display_timing_constraints>(constraints);
3030 			} else
3031 				fLink.StartMessage(status);
3032 
3033 			fLink.Flush();
3034 			break;
3035 		}
3036 
3037 		case AS_GET_PIXEL_CLOCK_LIMITS:
3038 		{
3039 			STRACE(("ServerApp %s: get pixel clock limits\n", Signature()));
3040 			// We aren't using the screen_id for now...
3041 			int32 id;
3042 			link.Read<int32>(&id);
3043 			display_mode mode;
3044 			link.Read<display_mode>(&mode);
3045 
3046 			uint32 low, high;
3047 			status_t status = fDesktop->HWInterface()->GetPixelClockLimits(&mode,
3048 				&low, &high);
3049 			if (status == B_OK) {
3050 				fLink.StartMessage(B_OK);
3051 				fLink.Attach<uint32>(low);
3052 				fLink.Attach<uint32>(high);
3053 			} else
3054 				fLink.StartMessage(status);
3055 
3056 			fLink.Flush();
3057 			break;
3058 		}
3059 
3060 		case AS_SET_DPMS:
3061 		{
3062 			STRACE(("ServerApp %s: AS_SET_DPMS\n", Signature()));
3063 			int32 id;
3064 			link.Read<int32>(&id);
3065 
3066 			uint32 mode;
3067 			link.Read<uint32>(&mode);
3068 
3069 			status_t status = fDesktop->HWInterface()->SetDPMSMode(mode);
3070 			fLink.StartMessage(status);
3071 
3072 			fLink.Flush();
3073 			break;
3074 		}
3075 
3076 		case AS_GET_DPMS_STATE:
3077 		{
3078 			STRACE(("ServerApp %s: AS_GET_DPMS_STATE\n", Signature()));
3079 
3080 			int32 id;
3081 			link.Read<int32>(&id);
3082 
3083 			uint32 state = fDesktop->HWInterface()->DPMSMode();
3084 			fLink.StartMessage(B_OK);
3085 			fLink.Attach<uint32>(state);
3086 			fLink.Flush();
3087 			break;
3088 		}
3089 
3090 		case AS_GET_DPMS_CAPABILITIES:
3091 		{
3092 			STRACE(("ServerApp %s: AS_GET_DPMS_CAPABILITIES\n", Signature()));
3093 			int32 id;
3094 			link.Read<int32>(&id);
3095 
3096 			uint32 capabilities = fDesktop->HWInterface()->DPMSCapabilities();
3097 			fLink.StartMessage(B_OK);
3098 			fLink.Attach<uint32>(capabilities);
3099 			fLink.Flush();
3100 			break;
3101 		}
3102 
3103 		case AS_SCREEN_SET_BRIGHTNESS:
3104 		{
3105 			STRACE(("ServerApp %s: AS_SCREEN_SET_BRIGHTNESS\n", Signature()));
3106 			int32 id;
3107 			link.Read<int32>(&id);
3108 
3109 			float brightness;
3110 			link.Read<float>(&brightness);
3111 
3112 			status_t status = fDesktop->HWInterface()->SetBrightness(brightness);
3113 			fLink.StartMessage(status);
3114 
3115 			fLink.Flush();
3116 			break;
3117 		}
3118 
3119 		case AS_SCREEN_GET_BRIGHTNESS:
3120 		{
3121 			STRACE(("ServerApp %s: AS_SCREEN_GET_BRIGHTNESS\n", Signature()));
3122 			int32 id;
3123 			link.Read<int32>(&id);
3124 
3125 			float brightness;
3126 			status_t result = fDesktop->HWInterface()->GetBrightness(&brightness);
3127 			fLink.StartMessage(result);
3128 			if (result == B_OK)
3129 				fLink.Attach<float>(brightness);
3130 			fLink.Flush();
3131 			break;
3132 		}
3133 
3134 		case AS_READ_BITMAP:
3135 		{
3136 			STRACE(("ServerApp %s: AS_READ_BITMAP\n", Signature()));
3137 			int32 token;
3138 			link.Read<int32>(&token);
3139 
3140 			bool drawCursor = true;
3141 			link.Read<bool>(&drawCursor);
3142 
3143 			BRect bounds;
3144 			link.Read<BRect>(&bounds);
3145 
3146 			bool success = false;
3147 
3148 			ServerBitmap* bitmap = GetBitmap(token);
3149 			if (bitmap != NULL) {
3150 				if (fDesktop->GetDrawingEngine()->LockExclusiveAccess()) {
3151 					success = fDesktop->GetDrawingEngine()->ReadBitmap(bitmap,
3152 						drawCursor, bounds) == B_OK;
3153 					fDesktop->GetDrawingEngine()->UnlockExclusiveAccess();
3154 				}
3155 				bitmap->ReleaseReference();
3156 			}
3157 
3158 			if (success)
3159 				fLink.StartMessage(B_OK);
3160 			else
3161 				fLink.StartMessage(B_BAD_VALUE);
3162 
3163 			fLink.Flush();
3164 			break;
3165 		}
3166 
3167 		case AS_GET_ACCELERANT_PATH:
3168 		{
3169 			int32 id;
3170 			fLink.Read<int32>(&id);
3171 
3172 			BString path;
3173 			status_t status = fDesktop->HWInterface()->GetAccelerantPath(path);
3174 			fLink.StartMessage(status);
3175 			if (status == B_OK)
3176 				fLink.AttachString(path.String());
3177 
3178 			fLink.Flush();
3179 			break;
3180 		}
3181 
3182 		case AS_GET_DRIVER_PATH:
3183 		{
3184 			int32 id;
3185 			fLink.Read<int32>(&id);
3186 
3187 			BString path;
3188 			status_t status = fDesktop->HWInterface()->GetDriverPath(path);
3189 			fLink.StartMessage(status);
3190 			if (status == B_OK)
3191 				fLink.AttachString(path.String());
3192 
3193 			fLink.Flush();
3194 			break;
3195 		}
3196 
3197 		// BWindowScreen communication
3198 
3199 		case AS_DIRECT_SCREEN_LOCK:
3200 		{
3201 			bool lock;
3202 			link.Read<bool>(&lock);
3203 
3204 			status_t status;
3205 			if (lock)
3206 				status = fDesktop->LockDirectScreen(ClientTeam());
3207 			else
3208 				status = fDesktop->UnlockDirectScreen(ClientTeam());
3209 
3210 			fLink.StartMessage(status);
3211 			fLink.Flush();
3212 			break;
3213 		}
3214 
3215 		// Hinting and aliasing
3216 
3217 		case AS_SET_SUBPIXEL_ANTIALIASING:
3218 		{
3219 			bool subpix;
3220 			if (link.Read<bool>(&subpix) == B_OK) {
3221 				LockedDesktopSettings settings(fDesktop);
3222 				settings.SetSubpixelAntialiasing(subpix);
3223 			}
3224 			fDesktop->Redraw();
3225 			break;
3226 		}
3227 
3228 		case AS_GET_SUBPIXEL_ANTIALIASING:
3229 		{
3230 			DesktopSettings settings(fDesktop);
3231 			fLink.StartMessage(B_OK);
3232 			fLink.Attach<bool>(settings.SubpixelAntialiasing());
3233 			fLink.Flush();
3234 			break;
3235 		}
3236 
3237 		case AS_SET_HINTING:
3238 		{
3239 			uint8 hinting;
3240 			if (link.Read<uint8>(&hinting) == B_OK && hinting < 3) {
3241 				LockedDesktopSettings settings(fDesktop);
3242 				if (hinting != settings.Hinting()) {
3243 					settings.SetHinting(hinting);
3244 					fDesktop->Redraw();
3245 				}
3246 			}
3247 			break;
3248 		}
3249 
3250 		case AS_GET_HINTING:
3251 		{
3252 			DesktopSettings settings(fDesktop);
3253 			fLink.StartMessage(B_OK);
3254 			fLink.Attach<uint8>(settings.Hinting());
3255 			fLink.Flush();
3256 			break;
3257 		}
3258 
3259 		case AS_SET_SUBPIXEL_AVERAGE_WEIGHT:
3260 		{
3261 			uint8 averageWeight;
3262 			if (link.Read<uint8>(&averageWeight) == B_OK) {
3263 				LockedDesktopSettings settings(fDesktop);
3264 				settings.SetSubpixelAverageWeight(averageWeight);
3265 			}
3266 			fDesktop->Redraw();
3267 			break;
3268 		}
3269 
3270 		case AS_GET_SUBPIXEL_AVERAGE_WEIGHT:
3271 		{
3272 			DesktopSettings settings(fDesktop);
3273 			fLink.StartMessage(B_OK);
3274 			fLink.Attach<uint8>(settings.SubpixelAverageWeight());
3275 			fLink.Flush();
3276 			break;
3277 		}
3278 
3279 		case AS_SET_SUBPIXEL_ORDERING:
3280 		{
3281 			bool subpixelOrdering;
3282 			if (link.Read<bool>(&subpixelOrdering) == B_OK) {
3283 				LockedDesktopSettings settings(fDesktop);
3284 				settings.SetSubpixelOrderingRegular(subpixelOrdering);
3285 			}
3286 			fDesktop->Redraw();
3287 			break;
3288 		}
3289 
3290 		case AS_GET_SUBPIXEL_ORDERING:
3291 		{
3292 			DesktopSettings settings(fDesktop);
3293 			fLink.StartMessage(B_OK);
3294 			fLink.Attach<bool>(settings.IsSubpixelOrderingRegular());
3295 			fLink.Flush();
3296 			break;
3297 		}
3298 
3299 		default:
3300 			printf("ServerApp %s received unhandled message code %" B_PRId32
3301 				"\n", Signature(), code);
3302 
3303 			if (link.NeedsReply()) {
3304 				// the client is now blocking and waiting for a reply!
3305 				fLink.StartMessage(B_ERROR);
3306 				fLink.Flush();
3307 			} else
3308 				puts("message doesn't need a reply!");
3309 			break;
3310 	}
3311 }
3312 
3313 
3314 /*!	\brief The thread function ServerApps use to monitor messages
3315 */
3316 void
3317 ServerApp::_MessageLooper()
3318 {
3319 	// Message-dispatching loop for the ServerApp
3320 
3321 	// get our own team ID
3322 	thread_info threadInfo;
3323 	get_thread_info(fThread, &threadInfo);
3324 
3325 	// First let's tell the client how to talk with us.
3326 	fLink.StartMessage(B_OK);
3327 	fLink.Attach<port_id>(fMessagePort);
3328 	fLink.Attach<area_id>(fDesktop->SharedReadOnlyArea());
3329 	fLink.Attach<team_id>(threadInfo.team);
3330 	fLink.Flush();
3331 
3332 	BPrivate::LinkReceiver &receiver = fLink.Receiver();
3333 
3334 	int32 code;
3335 	status_t err = B_OK;
3336 
3337 	while (!fQuitting) {
3338 		STRACE(("info: ServerApp::_MessageLooper() listening on port %" B_PRId32
3339 			".\n", fMessagePort));
3340 
3341 		err = receiver.GetNextMessage(code);
3342 		if (err != B_OK || code == B_QUIT_REQUESTED) {
3343 			STRACE(("ServerApp: application seems to be gone...\n"));
3344 
3345 			// Tell desktop to quit us
3346 			BPrivate::LinkSender link(fDesktop->MessagePort());
3347 			link.StartMessage(AS_DELETE_APP);
3348 			link.Attach<thread_id>(Thread());
3349 			link.Flush();
3350 			break;
3351 		}
3352 
3353 		switch (code) {
3354 			case kMsgAppQuit:
3355 				// we receive this from our destructor on quit
3356 				fQuitting = true;
3357 				break;
3358 
3359 			case AS_QUIT_APP:
3360 			{
3361 				// This message is received only when the app_server is asked
3362 				// to shut down in test/debug mode. Of course, if we are testing
3363 				// while using AccelerantDriver, we do NOT want to shut down
3364 				// client applications. The server can be quit in this fashion
3365 				// through the driver's interface, such as closing the
3366 				// ViewDriver's window.
3367 
3368 				STRACE(("ServerApp %s:Server shutdown notification received\n",
3369 					Signature()));
3370 
3371 				// If we are using the real, accelerated version of the
3372 				// DrawingEngine, we do NOT want the user to be able shut down
3373 				// the server. The results would NOT be pretty
3374 #if TEST_MODE
3375 				BMessage pleaseQuit(B_QUIT_REQUESTED);
3376 				SendMessageToClient(&pleaseQuit);
3377 #endif
3378 				break;
3379 			}
3380 
3381 			default:
3382 				STRACE(("ServerApp %s: Got a Message to dispatch\n",
3383 					Signature()));
3384 				_DispatchMessage(code, receiver);
3385 				break;
3386 		}
3387 	}
3388 
3389 	// Quit() will send us a message; we're handling the exiting procedure
3390 	thread_id sender;
3391 	sem_id shutdownSemaphore;
3392 	receive_data(&sender, &shutdownSemaphore, sizeof(sem_id));
3393 
3394 	delete this;
3395 
3396 	if (shutdownSemaphore >= B_OK)
3397 		release_sem(shutdownSemaphore);
3398 }
3399 
3400 
3401 status_t
3402 ServerApp::_CreateWindow(int32 code, BPrivate::LinkReceiver& link,
3403 	port_id& clientReplyPort)
3404 {
3405 	// Attached data:
3406 	// 1) int32 bitmap token (only for AS_CREATE_OFFSCREEN_WINDOW)
3407 	// 2) BRect window frame
3408 	// 3) uint32 window look
3409 	// 4) uint32 window feel
3410 	// 5) uint32 window flags
3411 	// 6) uint32 workspace index
3412 	// 7) int32 BHandler token of the window
3413 	// 8) port_id window's reply port
3414 	// 9) port_id window's looper port
3415 	// 10) const char * title
3416 
3417 	BRect frame;
3418 	int32 bitmapToken;
3419 	uint32 look;
3420 	uint32 feel;
3421 	uint32 flags;
3422 	uint32 workspaces;
3423 	int32 token;
3424 	port_id looperPort;
3425 	char* title;
3426 
3427 	if (code == AS_CREATE_OFFSCREEN_WINDOW)
3428 		link.Read<int32>(&bitmapToken);
3429 
3430 	link.Read<BRect>(&frame);
3431 	link.Read<uint32>(&look);
3432 	link.Read<uint32>(&feel);
3433 	link.Read<uint32>(&flags);
3434 	link.Read<uint32>(&workspaces);
3435 	link.Read<int32>(&token);
3436 	link.Read<port_id>(&clientReplyPort);
3437 	link.Read<port_id>(&looperPort);
3438 	if (link.ReadString(&title) != B_OK)
3439 		return B_ERROR;
3440 
3441 	if (!frame.IsValid()) {
3442 		// make sure we pass a valid rectangle to ServerWindow
3443 		frame.right = frame.left + 1;
3444 		frame.bottom = frame.top + 1;
3445 	}
3446 
3447 	status_t status = B_NO_MEMORY;
3448 	ServerWindow *window = NULL;
3449 
3450 	if (code == AS_CREATE_OFFSCREEN_WINDOW) {
3451 		ServerBitmap* bitmap = GetBitmap(bitmapToken);
3452 
3453 		if (bitmap != NULL) {
3454 			window = new (nothrow) OffscreenServerWindow(title, this,
3455 				clientReplyPort, looperPort, token, bitmap);
3456 		} else
3457 			status = B_ERROR;
3458 	} else {
3459 		window = new (nothrow) ServerWindow(title, this, clientReplyPort,
3460 			looperPort, token);
3461 		STRACE(("\nServerApp %s: New Window %s (%g:%g, %g:%g)\n",
3462 			Signature(), title, frame.left, frame.top,
3463 			frame.right, frame.bottom));
3464 	}
3465 
3466 	free(title);
3467 
3468 	// NOTE: the reply to the client is handled in ServerWindow::Run()
3469 	if (window != NULL) {
3470 		status = window->Init(frame, (window_look)look, (window_feel)feel,
3471 			flags, workspaces);
3472 		if (status == B_OK) {
3473 			status = window->Run();
3474 			if (status != B_OK) {
3475 				syslog(LOG_ERR, "ServerApp::_CreateWindow() - failed to run "
3476 					"the window thread\n");
3477 			}
3478 		}
3479 
3480 		if (status != B_OK)
3481 			delete window;
3482 	}
3483 
3484 	return status;
3485 }
3486 
3487 
3488 bool
3489 ServerApp::_HasWindowUnderMouse()
3490 {
3491 	BAutolock locker(fWindowListLock);
3492 
3493 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
3494 		ServerWindow* serverWindow = fWindowList.ItemAt(i);
3495 
3496 		if (fDesktop->ViewUnderMouse(serverWindow->Window()) != B_NULL_TOKEN)
3497 			return true;
3498 	}
3499 
3500 	return false;
3501 }
3502 
3503 
3504 bool
3505 ServerApp::_AddBitmap(ServerBitmap* bitmap)
3506 {
3507 	BAutolock _(fMapLocker);
3508 
3509 	try {
3510 		fBitmapMap.insert(std::make_pair(bitmap->Token(), bitmap));
3511 	} catch (std::bad_alloc& exception) {
3512 		return false;
3513 	}
3514 
3515 	bitmap->SetOwner(this);
3516 	return true;
3517 }
3518 
3519 
3520 void
3521 ServerApp::_DeleteBitmap(ServerBitmap* bitmap)
3522 {
3523 	ASSERT(fMapLocker.IsLocked());
3524 
3525 	gBitmapManager->BitmapRemoved(bitmap);
3526 	fBitmapMap.erase(bitmap->Token());
3527 
3528 	bitmap->ReleaseReference();
3529 }
3530 
3531 
3532 ServerBitmap*
3533 ServerApp::_FindBitmap(int32 token) const
3534 {
3535 	ASSERT(fMapLocker.IsLocked());
3536 
3537 	BitmapMap::const_iterator iterator = fBitmapMap.find(token);
3538 	if (iterator == fBitmapMap.end())
3539 		return NULL;
3540 
3541 	return iterator->second;
3542 }
3543 
3544 
3545 ServerPicture*
3546 ServerApp::_FindPicture(int32 token) const
3547 {
3548 	ASSERT(fMapLocker.IsLocked());
3549 
3550 	PictureMap::const_iterator iterator = fPictureMap.find(token);
3551 	if (iterator == fPictureMap.end())
3552 		return NULL;
3553 
3554 	return iterator->second;
3555 }
3556