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