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