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