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