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