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