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