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