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