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