xref: /haiku/src/servers/app/ServerApp.cpp (revision 582da17386c4a192ca30270d6b0b95f561cf5843)
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 overlayRestrictions;
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 				// TODO: fill overlay restrictions
681 			}
682 
683 			fLink.StartMessage(status);
684 			if (status == B_OK)
685 				fLink.Attach(&overlayRestrictions, sizeof(overlay_restrictions));
686 
687 			fLink.Flush();
688 			break;
689 		}
690 
691 		case AS_CREATE_PICTURE:
692 		{
693 			// TODO: Maybe rename this to AS_UPLOAD_PICTURE ?
694 			STRACE(("ServerApp %s: Create Picture\n", Signature()));
695 			status_t status = B_ERROR;
696 			ServerPicture *picture = CreatePicture();
697 			if (picture != NULL)
698 				status = picture->ImportData(link);
699 
700 			if (status == B_OK) {
701 				fLink.StartMessage(B_OK);
702 				fLink.Attach<int32>(picture->Token());
703 			} else
704 				fLink.StartMessage(B_ERROR);
705 
706 			fLink.Flush();
707 			break;
708 		}
709 
710 		case AS_DELETE_PICTURE:
711 		{
712 			STRACE(("ServerApp %s: Delete Picture\n", Signature()));
713 			int32 token;
714 			if (link.Read<int32>(&token) == B_OK)
715 				DeletePicture(token);
716 
717 			break;
718 		}
719 
720 		case AS_CLONE_PICTURE:
721 		{
722 			STRACE(("ServerApp %s: Clone Picture\n", Signature()));
723 			int32 token;
724 			ServerPicture *original = NULL;
725 			if (link.Read<int32>(&token) == B_OK)
726 				original = FindPicture(token);
727 
728 			ServerPicture *cloned = NULL;
729 			if (original != NULL)
730 				cloned = CreatePicture(original);
731 
732 			if (cloned != NULL) {
733 				fLink.StartMessage(B_OK);
734 				fLink.Attach<int32>(cloned->Token());
735 			} else
736 				fLink.StartMessage(B_ERROR);
737 
738 			fLink.Flush();
739 			break;
740 		}
741 
742 		case AS_DOWNLOAD_PICTURE:
743 		{
744 			STRACE(("ServerApp %s: Download Picture\n", Signature()));
745 			int32 token;
746 			link.Read<int32>(&token);
747 			ServerPicture *picture = FindPicture(token);
748 			if (picture != NULL) {
749 				picture->ExportData(fLink);
750 					// ExportData() calls StartMessage() already
751 			} else
752 				fLink.StartMessage(B_ERROR);
753 
754 			fLink.Flush();
755 
756 			break;
757 		}
758 
759 		case AS_COUNT_WORKSPACES:
760 		{
761 			if (fDesktop->LockSingleWindow()) {
762 				DesktopSettings settings(fDesktop);
763 
764 				fLink.StartMessage(B_OK);
765 				fLink.Attach<int32>(settings.WorkspacesCount());
766 				fDesktop->UnlockSingleWindow();
767 			} else
768 				fLink.StartMessage(B_ERROR);
769 
770 			fLink.Flush();
771 			break;
772 		}
773 
774 		case AS_SET_WORKSPACE_COUNT:
775 		{
776 			int32 newCount;
777 			if (link.Read<int32>(&newCount) == B_OK)
778 				fDesktop->SetWorkspacesCount(newCount);
779 			break;
780 		}
781 
782 		case AS_CURRENT_WORKSPACE:
783 			STRACE(("ServerApp %s: get current workspace\n", Signature()));
784 
785 			fLink.StartMessage(B_OK);
786 			fLink.Attach<int32>(fDesktop->CurrentWorkspace());
787 			fLink.Flush();
788 			break;
789 
790 		case AS_ACTIVATE_WORKSPACE:
791 		{
792 			STRACE(("ServerApp %s: activate workspace\n", Signature()));
793 
794 			// TODO: See above
795 			int32 index;
796 			link.Read<int32>(&index);
797 
798 			fDesktop->SetWorkspace(index);
799 			break;
800 		}
801 
802 		case AS_SHOW_CURSOR:
803 		{
804 			STRACE(("ServerApp %s: Show Cursor\n", Signature()));
805 			fCursorHideLevel--;
806 			if (fCursorHideLevel < 0)
807 				fCursorHideLevel = 0;
808 			fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0);
809 			break;
810 		}
811 		case AS_HIDE_CURSOR:
812 		{
813 			STRACE(("ServerApp %s: Hide Cursor\n", Signature()));
814 			fCursorHideLevel++;
815 			fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0);
816 			break;
817 		}
818 		case AS_OBSCURE_CURSOR:
819 		{
820 			STRACE(("ServerApp %s: Obscure Cursor\n", Signature()));
821 			fDesktop->HWInterface()->ObscureCursor();
822 			break;
823 		}
824 		case AS_QUERY_CURSOR_HIDDEN:
825 		{
826 			STRACE(("ServerApp %s: Received IsCursorHidden request\n", Signature()));
827 			fLink.StartMessage(fCursorHideLevel > 0 ? B_OK : B_ERROR);
828 			fLink.Flush();
829 			break;
830 		}
831 		case AS_SET_CURSOR:
832 		{
833 			STRACE(("ServerApp %s: SetCursor\n", Signature()));
834 
835 			// Attached data:
836 			// 1) bool flag to send a reply
837 			// 2) int32 token ID of the cursor to set
838 			// 3) port_id port to receive a reply. Only exists if the sync flag is true.
839 			bool sync;
840 			int32 token;
841 
842 			link.Read<bool>(&sync);
843 			if (link.Read<int32>(&token) != B_OK)
844 				break;
845 
846 			if (!fDesktop->GetCursorManager().Lock())
847 				break;
848 
849 			ServerCursor* oldCursor = fAppCursor;
850 			fAppCursor = fDesktop->GetCursorManager().FindCursor(token);
851 			if (fAppCursor != NULL)
852 				fAppCursor->Acquire();
853 
854 			if (_HasWindowUnderMouse())
855 				fDesktop->SetCursor(CurrentCursor());
856 
857 			if (oldCursor != NULL)
858 				oldCursor->Release();
859 
860 			fDesktop->GetCursorManager().Unlock();
861 
862 			if (sync) {
863 				// The application is expecting a reply
864 				fLink.StartMessage(B_OK);
865 				fLink.Flush();
866 			}
867 			break;
868 		}
869 		case AS_CREATE_CURSOR:
870 		{
871 			STRACE(("ServerApp %s: Create Cursor\n", Signature()));
872 			// Attached data:
873 			// 1) 68 bytes of fAppCursor data
874 			// 2) port_id reply port
875 
876 			status_t status = B_ERROR;
877 			uint8 cursorData[68];
878 			ServerCursor* cursor = NULL;
879 
880 //			if (link.Read(cursorData, sizeof(cursorData)) >= B_OK) {
881 //				cursor = new (nothrow) ServerCursor(cursorData);
882 //				if (cursor == NULL)
883 //					status = B_NO_MEMORY;
884 //			}
885 //
886 //			if (cursor != NULL) {
887 //				cursor->SetOwningTeam(fClientTeam);
888 //				fDesktop->GetCursorManager().AddCursor(cursor);
889 //
890 //				// Synchronous message - BApplication is waiting on the cursor's ID
891 //				fLink.StartMessage(B_OK);
892 //				fLink.Attach<int32>(cursor->Token());
893 //			} else
894 //				fLink.StartMessage(status);
895 
896 			if (link.Read(cursorData, sizeof(cursorData)) >= B_OK) {
897 				cursor = fDesktop->GetCursorManager().CreateCursor(fClientTeam,
898 																   cursorData);
899 				if (cursor == NULL)
900 					status = B_NO_MEMORY;
901 			}
902 
903 			if (cursor != NULL) {
904 				// Synchronous message - BApplication is waiting on the cursor's ID
905 				fLink.StartMessage(B_OK);
906 				fLink.Attach<int32>(cursor->Token());
907 			} else
908 				fLink.StartMessage(status);
909 
910 			fLink.Flush();
911 			break;
912 		}
913 		case AS_DELETE_CURSOR:
914 		{
915 			STRACE(("ServerApp %s: Delete BCursor\n", Signature()));
916 			// Attached data:
917 			// 1) int32 token ID of the cursor to delete
918 			int32 token;
919 			bool pendingViewCursor;
920 			link.Read<int32>(&token);
921 			if (link.Read<bool>(&pendingViewCursor) != B_OK)
922 				break;
923 
924 			if (!fDesktop->GetCursorManager().Lock())
925 				break;
926 
927 			ServerCursor* cursor = fDesktop->GetCursorManager().FindCursor(token);
928 			if (cursor) {
929 				if (pendingViewCursor)
930 					cursor->SetPendingViewCursor(true);
931 
932 				cursor->Release();
933 			}
934 			fDesktop->GetCursorManager().Unlock();
935 
936 			break;
937 		}
938 
939 		case AS_GET_SCROLLBAR_INFO:
940 		{
941 			STRACE(("ServerApp %s: Get ScrollBar info\n", Signature()));
942 
943 			if (fDesktop->LockSingleWindow()) {
944 				scroll_bar_info info;
945 				DesktopSettings settings(fDesktop);
946 				settings.GetScrollBarInfo(info);
947 
948 				fLink.StartMessage(B_OK);
949 				fLink.Attach<scroll_bar_info>(info);
950 				fDesktop->UnlockSingleWindow();
951 			} else
952 				fLink.StartMessage(B_ERROR);
953 
954 				fLink.Flush();
955 			break;
956 		}
957 		case AS_SET_SCROLLBAR_INFO:
958 		{
959 			STRACE(("ServerApp %s: Set ScrollBar info\n", Signature()));
960 			// Attached Data:
961 			// 1) scroll_bar_info scroll bar info structure
962 			scroll_bar_info info;
963 			if (link.Read<scroll_bar_info>(&info) == B_OK) {
964 				LockedDesktopSettings settings(fDesktop);
965 				settings.SetScrollBarInfo(info);
966 			}
967 
968 			fLink.StartMessage(B_OK);
969 			fLink.Flush();
970 			break;
971 		}
972 
973 		case AS_GET_MENU_INFO:
974 		{
975 			STRACE(("ServerApp %s: Get menu info\n", Signature()));
976 			if (fDesktop->LockSingleWindow()) {
977 				menu_info info;
978 				DesktopSettings settings(fDesktop);
979 				settings.GetMenuInfo(info);
980 
981 				fLink.StartMessage(B_OK);
982 				fLink.Attach<menu_info>(info);
983 
984 				fDesktop->UnlockSingleWindow();
985 			} else
986 				fLink.StartMessage(B_ERROR);
987 
988 			fLink.Flush();
989 			break;
990 		}
991 		case AS_SET_MENU_INFO:
992 		{
993 			STRACE(("ServerApp %s: Set menu info\n", Signature()));
994 			menu_info info;
995 			if (link.Read<menu_info>(&info) == B_OK) {
996 				LockedDesktopSettings settings(fDesktop);
997 				settings.SetMenuInfo(info);
998 					// TODO: SetMenuInfo() should do some validity check, so
999 					//	that the answer we're giving can actually be useful
1000 			}
1001 
1002 			fLink.StartMessage(B_OK);
1003 			fLink.Flush();
1004 			break;
1005 		}
1006 
1007 		case AS_SET_MOUSE_MODE:
1008 		{
1009 			STRACE(("ServerApp %s: Set Focus Follows Mouse mode\n", Signature()));
1010 			// Attached Data:
1011 			// 1) enum mode_mouse FFM mouse mode
1012 			mode_mouse mouseMode;
1013 			if (link.Read<mode_mouse>(&mouseMode) == B_OK) {
1014 				LockedDesktopSettings settings(fDesktop);
1015 				settings.SetMouseMode(mouseMode);
1016 			}
1017 			break;
1018 		}
1019 		case AS_GET_MOUSE_MODE:
1020 		{
1021 			STRACE(("ServerApp %s: Get Focus Follows Mouse mode\n", Signature()));
1022 
1023 			if (fDesktop->LockSingleWindow()) {
1024 				DesktopSettings settings(fDesktop);
1025 
1026 				fLink.StartMessage(B_OK);
1027 				fLink.Attach<mode_mouse>(settings.MouseMode());
1028 
1029 				fDesktop->UnlockSingleWindow();
1030 			} else
1031 				fLink.StartMessage(B_ERROR);
1032 
1033 			fLink.Flush();
1034 			break;
1035 		}
1036 
1037 		case AS_GET_SHOW_ALL_DRAGGERS:
1038 		{
1039 			STRACE(("ServerApp %s: Get Show All Draggers\n", Signature()));
1040 
1041 			if (fDesktop->LockSingleWindow()) {
1042 				DesktopSettings settings(fDesktop);
1043 
1044 				fLink.StartMessage(B_OK);
1045 				fLink.Attach<bool>(settings.ShowAllDraggers());
1046 
1047 				fDesktop->UnlockSingleWindow();
1048 			} else
1049 				fLink.StartMessage(B_ERROR);
1050 
1051 			fLink.Flush();
1052 			break;
1053 		}
1054 
1055 		case AS_SET_SHOW_ALL_DRAGGERS:
1056 		{
1057 			STRACE(("ServerApp %s: Set Show All Draggers\n", Signature()));
1058 
1059 			bool changed = false;
1060 			bool show;
1061 			if (link.Read<bool>(&show) == B_OK) {
1062 				LockedDesktopSettings settings(fDesktop);
1063 				if (show != settings.ShowAllDraggers()) {
1064 					settings.SetShowAllDraggers(show);
1065 					changed = true;
1066 				}
1067 			}
1068 
1069 			if (changed)
1070 				fDesktop->BroadcastToAllApps(kMsgUpdateShowAllDraggers);
1071 			break;
1072 		}
1073 
1074 		case kMsgUpdateShowAllDraggers:
1075 		{
1076 			bool show = false;
1077 			if (fDesktop->LockSingleWindow()) {
1078 				DesktopSettings settings(fDesktop);
1079 				show = settings.ShowAllDraggers();
1080 				fDesktop->UnlockSingleWindow();
1081 			}
1082 			BMessage update(_SHOW_DRAG_HANDLES_);
1083 			update.AddBool("show", show);
1084 
1085 			SendMessageToClient(&update);
1086 			break;
1087 		}
1088 
1089 		/* font messages */
1090 
1091 		case AS_SET_SYSTEM_FONT:
1092 		{
1093 			// gets:
1094 			//	1) string - font type ("plain", ...)
1095 			//	2) string - family
1096 			//	3) string - style
1097 			//	4) float - size
1098 
1099 			char type[B_OS_NAME_LENGTH];
1100 			font_family familyName;
1101 			font_style styleName;
1102 			float size;
1103 
1104 			if (link.ReadString(type, sizeof(type)) == B_OK
1105 				&& link.ReadString(familyName, sizeof(familyName)) == B_OK
1106 				&& link.ReadString(styleName, sizeof(styleName)) == B_OK
1107 				&& link.Read<float>(&size) == B_OK) {
1108 				gFontManager->Lock();
1109 
1110 				FontStyle* style = gFontManager->GetStyle(familyName, styleName);
1111 				if (style != NULL) {
1112 					ServerFont font(*style, size);
1113 					gFontManager->Unlock();
1114 						// We must not have locked the font manager when
1115 						// locking the desktop (through LockedDesktopSettings
1116 						// below)
1117 
1118 					LockedDesktopSettings settings(fDesktop);
1119 
1120 					if (!strcmp(type, "plain"))
1121 						settings.SetDefaultPlainFont(font);
1122 					else if (!strcmp(type, "bold"))
1123 						settings.SetDefaultBoldFont(font);
1124 					else if (!strcmp(type, "fixed"))
1125 						settings.SetDefaultFixedFont(font);
1126 				} else
1127 					gFontManager->Unlock();
1128 			}
1129 			break;
1130 		}
1131 		case AS_GET_SYSTEM_DEFAULT_FONT:
1132 		{
1133 			// input:
1134 			//	1) string - font type ("plain", ...)
1135 
1136 			ServerFont font;
1137 
1138 			char type[B_OS_NAME_LENGTH];
1139 			status_t status = link.ReadString(type, sizeof(type));
1140 			if (status == B_OK) {
1141 				if (!strcmp(type, "plain")) {
1142 					font = *gFontManager->DefaultPlainFont();
1143 				} else if (!strcmp(type, "bold")) {
1144 					font = *gFontManager->DefaultBoldFont();
1145 				} else if (!strcmp(type, "fixed")) {
1146 					font = *gFontManager->DefaultFixedFont();
1147 				} else
1148 					status = B_BAD_VALUE;
1149 			}
1150 
1151 			if (status == B_OK) {
1152 				// returns:
1153 				//	1) string - family
1154 				//	2) string - style
1155 				//	3) float - size
1156 
1157 				fLink.StartMessage(B_OK);
1158 				fLink.AttachString(font.Family());
1159 				fLink.AttachString(font.Style());
1160 				fLink.Attach<float>(font.Size());
1161 			} else
1162 				fLink.StartMessage(status);
1163 
1164 			fLink.Flush();
1165 			break;
1166 		}
1167 		case AS_GET_SYSTEM_FONTS:
1168 		{
1169 			FTRACE(("ServerApp %s: AS_GET_SYSTEM_FONTS\n", Signature()));
1170 			// Returns:
1171 			// 1) uint16 - family ID
1172 			// 2) uint16 - style ID
1173 			// 3) float - size in points
1174 			// 4) uint16 - face flags
1175 			// 5) uint32 - font flags
1176 
1177 			if (!fDesktop->LockSingleWindow()) {
1178 				fLink.StartMessage(B_OK);
1179 				fLink.Flush();
1180 				break;
1181 			}
1182 
1183 			DesktopSettings settings(fDesktop);
1184 			fLink.StartMessage(B_OK);
1185 
1186 			for (int32 i = 0; i < 3; i++) {
1187 				ServerFont font;
1188 				switch (i) {
1189 					case 0:
1190 						settings.GetDefaultPlainFont(font);
1191 						fLink.AttachString("plain");
1192 						break;
1193 					case 1:
1194 						settings.GetDefaultBoldFont(font);
1195 						fLink.AttachString("bold");
1196 						break;
1197 					case 2:
1198 						settings.GetDefaultFixedFont(font);
1199 						fLink.AttachString("fixed");
1200 						break;
1201 				}
1202 
1203 				fLink.Attach<uint16>(font.FamilyID());
1204 				fLink.Attach<uint16>(font.StyleID());
1205 				fLink.Attach<float>(font.Size());
1206 				fLink.Attach<uint16>(font.Face());
1207 				fLink.Attach<uint32>(font.Flags());
1208 			}
1209 
1210 			fDesktop->UnlockSingleWindow();
1211 			fLink.Flush();
1212 			break;
1213 		}
1214 		case AS_GET_FONT_LIST_REVISION:
1215 		{
1216 			STRACE(("ServerApp %s: AS_GET_FONT_LIST_REVISION\n", Signature()));
1217 
1218 			fLink.StartMessage(B_OK);
1219 			fLink.Attach<int32>(gFontManager->CheckRevision(fDesktop->UserID()));
1220 			fLink.Flush();
1221 			break;
1222 		}
1223 		case AS_GET_FAMILY_AND_STYLES:
1224 		{
1225 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLES\n", Signature()));
1226 			// Attached Data:
1227 			// 1) int32 the index of the font family to get
1228 
1229 			// Returns:
1230 			// 1) string - name of family
1231 			// 2) uint32 - flags of font family (B_IS_FIXED || B_HAS_TUNED_FONT)
1232 			// 3) count of styles in that family
1233 			// For each style:
1234 			//		1) string - name of style
1235 			//		2) uint16 - face of style
1236 			//		3) uint32 - flags of style
1237 
1238 			int32 index;
1239 			link.Read<int32>(&index);
1240 
1241 			gFontManager->Lock();
1242 
1243 			FontFamily* family = gFontManager->FamilyAt(index);
1244 			if (family) {
1245 				fLink.StartMessage(B_OK);
1246 				fLink.AttachString(family->Name());
1247 				fLink.Attach<uint32>(family->Flags());
1248 
1249 				int32 count = family->CountStyles();
1250 				fLink.Attach<int32>(count);
1251 
1252 				for (int32 i = 0; i < count; i++) {
1253 					FontStyle* style = family->StyleAt(i);
1254 
1255 					fLink.AttachString(style->Name());
1256 					fLink.Attach<uint16>(style->Face());
1257 					fLink.Attach<uint32>(style->Flags());
1258 				}
1259 			} else
1260 				fLink.StartMessage(B_BAD_VALUE);
1261 
1262 			gFontManager->Unlock();
1263 			fLink.Flush();
1264 			break;
1265 		}
1266 		case AS_GET_FAMILY_AND_STYLE:
1267 		{
1268 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE\n", Signature()));
1269 			// Attached Data:
1270 			// 1) uint16 - family ID
1271 			// 2) uint16 - style ID
1272 
1273 			// Returns:
1274 			// 1) font_family The name of the font family
1275 			// 2) font_style - name of the style
1276 			uint16 familyID, styleID;
1277 			link.Read<uint16>(&familyID);
1278 			link.Read<uint16>(&styleID);
1279 
1280 			gFontManager->Lock();
1281 
1282 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1283 			if (fontStyle != NULL) {
1284 				fLink.StartMessage(B_OK);
1285 				fLink.AttachString(fontStyle->Family()->Name());
1286 				fLink.AttachString(fontStyle->Name());
1287 			} else
1288 				fLink.StartMessage(B_BAD_VALUE);
1289 
1290 			fLink.Flush();
1291 			gFontManager->Unlock();
1292 			break;
1293 		}
1294 		case AS_GET_FAMILY_AND_STYLE_IDS:
1295 		{
1296 			FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE_IDS\n", Signature()));
1297 			// Attached Data:
1298 			// 1) font_family - name of font family to use
1299 			// 2) font_style - name of style in family
1300 			// 3) family ID - only used if 1) is empty
1301 			// 4) style ID - only used if 2) is empty
1302 			// 5) face - the font's current face
1303 
1304 			// Returns:
1305 			// 1) uint16 - family ID
1306 			// 2) uint16 - style ID
1307 			// 3) uint16 - face
1308 
1309 			font_family family;
1310 			font_style style;
1311 			uint16 familyID, styleID;
1312 			uint16 face;
1313 			if (link.ReadString(family, sizeof(font_family)) == B_OK
1314 				&& link.ReadString(style, sizeof(font_style)) == B_OK
1315 				&& link.Read<uint16>(&familyID) == B_OK
1316 				&& link.Read<uint16>(&styleID) == B_OK
1317 				&& link.Read<uint16>(&face) == B_OK) {
1318 				// get the font and return IDs and face
1319 				gFontManager->Lock();
1320 
1321 				FontStyle *fontStyle = gFontManager->GetStyle(family, style,
1322 					familyID, styleID, face);
1323 
1324 				if (fontStyle != NULL) {
1325 					fLink.StartMessage(B_OK);
1326 					fLink.Attach<uint16>(fontStyle->Family()->ID());
1327 					fLink.Attach<uint16>(fontStyle->ID());
1328 
1329 					// we try to keep the font face close to what we got
1330 					face = fontStyle->PreservedFace(face);
1331 
1332 					fLink.Attach<uint16>(face);
1333 				} else
1334 					fLink.StartMessage(B_NAME_NOT_FOUND);
1335 
1336 				gFontManager->Unlock();
1337 			} else
1338 				fLink.StartMessage(B_BAD_VALUE);
1339 
1340 			fLink.Flush();
1341 			break;
1342 		}
1343 		case AS_GET_FONT_FILE_FORMAT:
1344 		{
1345 			FTRACE(("ServerApp %s: AS_GET_FONT_FILE_FORMAT\n", Signature()));
1346 			// Attached Data:
1347 			// 1) uint16 - family ID
1348 			// 2) uint16 - style ID
1349 
1350 			// Returns:
1351 			// 1) uint16 font_file_format of font
1352 
1353 			int32 familyID, styleID;
1354 			link.Read<int32>(&familyID);
1355 			link.Read<int32>(&styleID);
1356 
1357 			gFontManager->Lock();
1358 
1359 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1360 			if (fontStyle) {
1361 				fLink.StartMessage(B_OK);
1362 				fLink.Attach<uint16>((uint16)fontStyle->FileFormat());
1363 			} else
1364 				fLink.StartMessage(B_BAD_VALUE);
1365 
1366 			gFontManager->Unlock();
1367 			fLink.Flush();
1368 			break;
1369 		}
1370 		case AS_GET_STRING_WIDTHS:
1371 		{
1372 			FTRACE(("ServerApp %s: AS_GET_STRING_WIDTHS\n", Signature()));
1373 			// Attached Data:
1374 			// 1) uint16 ID of family
1375 			// 2) uint16 ID of style
1376 			// 3) float point size of font
1377 			// 4) uint8 spacing to use
1378 			// 5) int32 numStrings
1379 			// 6) int32 string length to measure (numStrings times)
1380 			// 7) string String to measure (numStrings times)
1381 
1382 			// Returns:
1383 			// 1) float - width of the string in pixels (numStrings times)
1384 
1385 			uint16 family, style;
1386 			float size;
1387 			uint8 spacing;
1388 
1389 			link.Read<uint16>(&family);
1390 			link.Read<uint16>(&style);
1391 			link.Read<float>(&size);
1392 			link.Read<uint8>(&spacing);
1393 			int32 numStrings;
1394 			if (link.Read<int32>(&numStrings) != B_OK) {
1395 				// this results in a B_BAD_VALUE return
1396 				numStrings = 0;
1397 				size = 0.0f;
1398 			}
1399 
1400 			float widthArray[numStrings];
1401 			int32 lengthArray[numStrings];
1402 			char *stringArray[numStrings];
1403 			for (int32 i = 0; i < numStrings; i++) {
1404 				// This version of ReadString allocates the strings, we free them below
1405 				link.ReadString(&stringArray[i], (size_t *)&lengthArray[i]);
1406 			}
1407 
1408 			ServerFont font;
1409 
1410 			if (font.SetFamilyAndStyle(family, style) == B_OK && size > 0) {
1411 				font.SetSize(size);
1412 				font.SetSpacing(spacing);
1413 
1414 				for (int32 i = 0; i < numStrings; i++) {
1415 					if (!stringArray[i] || lengthArray[i] <= 0)
1416 						widthArray[i] = 0.0;
1417 					else {
1418 						widthArray[i] = fDesktop->GetDrawingEngine()->StringWidth(stringArray[i], lengthArray[i], font);
1419 						// NOTE: The line below will return the exact same thing. However,
1420 						// the line above uses the AGG rendering backend, for which glyph caching
1421 						// actually works. It is about 20 times faster!
1422 						// TODO: I've disabled the AGG version for now, as it produces a dead lock
1423 						//	(font use), that I am currently too lazy to investigate...
1424 //						widthArray[i] = font.StringWidth(stringArray[i], lengthArray[i]);
1425 					}
1426 				}
1427 
1428 				fLink.StartMessage(B_OK);
1429 				fLink.Attach(widthArray, sizeof(widthArray));
1430 			} else
1431 				fLink.StartMessage(B_BAD_VALUE);
1432 
1433 			fLink.Flush();
1434 
1435 			for (int32 i = 0; i < numStrings; i++) {
1436 				free(stringArray[i]);
1437 			}
1438 			break;
1439 		}
1440 		case AS_GET_FONT_BOUNDING_BOX:
1441 		{
1442 			FTRACE(("ServerApp %s: AS_GET_BOUNDING_BOX unimplemented\n",
1443 				Signature()));
1444 			// Attached Data:
1445 			// 1) uint16 - family ID
1446 			// 2) uint16 - style ID
1447 
1448 			// Returns:
1449 			// 1) BRect - box holding entire font
1450 
1451 			// ToDo: implement me!
1452 			fLink.StartMessage(B_ERROR);
1453 			fLink.Flush();
1454 			break;
1455 		}
1456 		case AS_GET_TUNED_COUNT:
1457 		{
1458 			FTRACE(("ServerApp %s: AS_GET_TUNED_COUNT\n", Signature()));
1459 			// Attached Data:
1460 			// 1) uint16 - family ID
1461 			// 2) uint16 - style ID
1462 
1463 			// Returns:
1464 			// 1) int32 - number of font strikes available
1465 			uint16 familyID, styleID;
1466 			link.Read<uint16>(&familyID);
1467 			link.Read<uint16>(&styleID);
1468 
1469 			gFontManager->Lock();
1470 
1471 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1472 			if (fontStyle != NULL) {
1473 				fLink.StartMessage(B_OK);
1474 				fLink.Attach<int32>(fontStyle->TunedCount());
1475 			} else
1476 				fLink.StartMessage(B_BAD_VALUE);
1477 
1478 			gFontManager->Unlock();
1479 			fLink.Flush();
1480 			break;
1481 		}
1482 		case AS_GET_TUNED_INFO:
1483 		{
1484 			FTRACE(("ServerApp %s: AS_GET_TUNED_INFO unimplmemented\n",
1485 				Signature()));
1486 			// Attached Data:
1487 			// 1) uint16 - family ID
1488 			// 2) uint16 - style ID
1489 			// 3) uint32 - index of the particular font strike
1490 
1491 			// Returns:
1492 			// 1) tuned_font_info - info on the strike specified
1493 			// ToDo: implement me!
1494 			fLink.StartMessage(B_ERROR);
1495 			fLink.Flush();
1496 			break;
1497 		}
1498 		case AS_GET_EXTRA_FONT_FLAGS:
1499 		{
1500 			FTRACE(("ServerApp %s: AS_GET_EXTRA_FONT_FLAGS\n",
1501 				Signature()));
1502 			// Attached Data:
1503 			// 1) uint16 - family ID
1504 			// 2) uint16 - style ID
1505 
1506 			// Returns:
1507 			// 1) uint32 - extra font flags
1508 			uint16 familyID, styleID;
1509 			link.Read<uint16>(&familyID);
1510 			link.Read<uint16>(&styleID);
1511 
1512 			gFontManager->Lock();
1513 
1514 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1515 			if (fontStyle != NULL) {
1516 				fLink.StartMessage(B_OK);
1517 				fLink.Attach<uint32>(fontStyle->Flags());
1518 			} else
1519 				fLink.StartMessage(B_BAD_VALUE);
1520 
1521 			gFontManager->Unlock();
1522 			fLink.Flush();
1523 			break;
1524 		}
1525 		case AS_GET_FONT_HEIGHT:
1526 		{
1527 			FTRACE(("ServerApp %s: AS_GET_FONT_HEIGHT\n", Signature()));
1528 			// Attached Data:
1529 			// 1) uint16 family ID
1530 			// 2) uint16 style ID
1531 			// 3) float size
1532 			uint16 familyID, styleID;
1533 			float size;
1534 			link.Read<uint16>(&familyID);
1535 			link.Read<uint16>(&styleID);
1536 			link.Read<float>(&size);
1537 
1538 			gFontManager->Lock();
1539 
1540 			FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
1541 			if (fontStyle != NULL) {
1542 				font_height height;
1543 				fontStyle->GetHeight(size, height);
1544 
1545 				fLink.StartMessage(B_OK);
1546 				fLink.Attach<font_height>(height);
1547 			} else
1548 				fLink.StartMessage(B_BAD_VALUE);
1549 
1550 			gFontManager->Unlock();
1551 			fLink.Flush();
1552 			break;
1553 		}
1554 		case AS_GET_GLYPH_SHAPES:
1555 		{
1556 			FTRACE(("ServerApp %s: AS_GET_GLYPH_SHAPES\n", Signature()));
1557 			// Attached Data:
1558 			// 1) uint16 - family ID
1559 			// 2) uint16 - style ID
1560 			// 3) float - point size
1561 			// 4) float - shear
1562 			// 5) float - rotation
1563 			// 6) float - false bold width
1564 			// 6) uint32 - flags
1565 			// 7) int32 - numChars
1566 			// 8) int32 - numBytes
1567 			// 8) char - chars (bytesInBuffer times)
1568 
1569 			// Returns:
1570 			// 1) BShape - glyph shape
1571 			// numChars times
1572 
1573 			uint16 familyID, styleID;
1574 			uint32 flags;
1575 			float size, shear, rotation, falseBoldWidth;
1576 
1577 			link.Read<uint16>(&familyID);
1578 			link.Read<uint16>(&styleID);
1579 			link.Read<float>(&size);
1580 			link.Read<float>(&shear);
1581 			link.Read<float>(&rotation);
1582 			link.Read<float>(&falseBoldWidth);
1583 			link.Read<uint32>(&flags);
1584 
1585 			int32 numChars, numBytes;
1586 			link.Read<int32>(&numChars);
1587 			link.Read<int32>(&numBytes);
1588 
1589 			char* charArray = new (nothrow) char[numBytes];
1590 			link.Read(charArray, numBytes);
1591 
1592 			ServerFont font;
1593 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1594 			if (status == B_OK) {
1595 				font.SetSize(size);
1596 				font.SetShear(shear);
1597 				font.SetRotation(rotation);
1598 				font.SetFalseBoldWidth(falseBoldWidth);
1599 				font.SetFlags(flags);
1600 
1601 				BShape** shapes = new (nothrow) BShape*[numChars];
1602 				status = font.GetGlyphShapes(charArray, numChars, shapes);
1603 				if (status == B_OK) {
1604 					fLink.StartMessage(B_OK);
1605 					for (int32 i = 0; i < numChars; i++) {
1606 						fLink.AttachShape(*shapes[i]);
1607 						delete shapes[i];
1608 					}
1609 				} else
1610 					fLink.StartMessage(status);
1611 
1612 				delete[] shapes;
1613 			} else
1614 				fLink.StartMessage(status);
1615 
1616 			delete[] charArray;
1617 			fLink.Flush();
1618 			break;
1619 		}
1620 		case AS_GET_HAS_GLYPHS:
1621 		{
1622 			FTRACE(("ServerApp %s: AS_GET_HAS_GLYPHS\n", Signature()));
1623 			// Attached Data:
1624 			// 1) uint16 - family ID
1625 			// 2) uint16 - style ID
1626 			// 3) int32 - numChars
1627 			// 4) int32 - numBytes
1628 			// 5) char - the char buffer with size numBytes
1629 
1630 			uint16 familyID, styleID;
1631 			link.Read<uint16>(&familyID);
1632 			link.Read<uint16>(&styleID);
1633 
1634 			int32 numChars, numBytes;
1635 			link.Read<int32>(&numChars);
1636 			link.Read<int32>(&numBytes);
1637 			char* charArray = new (nothrow) char[numBytes];
1638 			link.Read(charArray, numBytes);
1639 
1640 			ServerFont font;
1641 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1642 			if (status == B_OK) {
1643 				bool hasArray[numChars];
1644 				status = font.GetHasGlyphs(charArray, numChars, hasArray);
1645 				if (status == B_OK) {
1646 					fLink.StartMessage(B_OK);
1647 					fLink.Attach(hasArray, sizeof(hasArray));
1648 				} else
1649 					fLink.StartMessage(status);
1650 			} else
1651 				fLink.StartMessage(status);
1652 
1653 			delete[] charArray;
1654 			fLink.Flush();
1655 			break;
1656 		}
1657 		case AS_GET_EDGES:
1658 		{
1659 			FTRACE(("ServerApp %s: AS_GET_EDGES\n", Signature()));
1660 			// Attached Data:
1661 			// 1) uint16 - family ID
1662 			// 2) uint16 - style ID
1663 			// 3) int32 - numChars
1664 			// 4) int32 - numBytes
1665 			// 5) char - the char buffer with size numBytes
1666 
1667 			uint16 familyID, styleID;
1668 			link.Read<uint16>(&familyID);
1669 			link.Read<uint16>(&styleID);
1670 
1671 			int32 numChars;
1672 			link.Read<int32>(&numChars);
1673 
1674 			uint32 numBytes;
1675 			link.Read<uint32>(&numBytes);
1676 			char* charArray = new (nothrow) char[numBytes];
1677 			link.Read(charArray, numBytes);
1678 
1679 			ServerFont font;
1680 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1681 			if (status == B_OK) {
1682 				edge_info edgeArray[numChars];
1683 				status = font.GetEdges(charArray, numChars, edgeArray);
1684 				if (status == B_OK) {
1685 					fLink.StartMessage(B_OK);
1686 					fLink.Attach(edgeArray, sizeof(edgeArray));
1687 				} else
1688 					fLink.StartMessage(status);
1689 			} else
1690 				fLink.StartMessage(status);
1691 
1692 			delete[] charArray;
1693 			fLink.Flush();
1694 			break;
1695 		}
1696 		case AS_GET_ESCAPEMENTS:
1697 		{
1698 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS\n", Signature()));
1699 			// Attached Data:
1700 			// 1) uint16 - family ID
1701 			// 2) uint16 - style ID
1702 			// 3) float - point size
1703 			// 4) uint8 - spacing
1704 			// 5) float - rotation
1705 			// 6) uint32 - flags
1706 			// 7) int32 - numChars
1707 			// 8) char - char     -\       both
1708 			// 9) BPoint - offset -/ (numChars times)
1709 
1710 			// Returns:
1711 			// 1) BPoint - escapement
1712 			// numChars times
1713 
1714 			uint16 familyID, styleID;
1715 			uint32 flags;
1716 			float size, rotation;
1717 			uint8 spacing;
1718 
1719 			link.Read<uint16>(&familyID);
1720 			link.Read<uint16>(&styleID);
1721 			link.Read<float>(&size);
1722 			link.Read<uint8>(&spacing);
1723 			link.Read<float>(&rotation);
1724 			link.Read<uint32>(&flags);
1725 
1726 			escapement_delta delta;
1727 			link.Read<float>(&delta.nonspace);
1728 			link.Read<float>(&delta.space);
1729 
1730 			bool wantsOffsets;
1731 			link.Read<bool>(&wantsOffsets);
1732 
1733 			int32 numChars;
1734 			link.Read<int32>(&numChars);
1735 
1736 			uint32 numBytes;
1737 			link.Read<uint32>(&numBytes);
1738 			char *charArray = new (nothrow) char[numBytes];
1739 			link.Read(charArray, numBytes);
1740 
1741 			ServerFont font;
1742 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1743 			if (status == B_OK) {
1744 				font.SetSize(size);
1745 				font.SetSpacing(spacing);
1746 				font.SetRotation(rotation);
1747 				font.SetFlags(flags);
1748 
1749 				BPoint *escapements = new (nothrow) BPoint[numChars];
1750 				BPoint *offsets = NULL;
1751 				if (wantsOffsets)
1752 					offsets = new (nothrow) BPoint[numChars];
1753 
1754 				status = font.GetEscapements(charArray, numChars, delta,
1755 					escapements, offsets);
1756 
1757 				if (status == B_OK) {
1758 					fLink.StartMessage(B_OK);
1759 					for (int32 i = 0; i < numChars; i++)
1760 						fLink.Attach<BPoint>(escapements[i]);
1761 
1762 					if (wantsOffsets) {
1763 						for (int32 i = 0; i < numChars; i++)
1764 							fLink.Attach<BPoint>(offsets[i]);
1765 					}
1766 				} else
1767 					fLink.StartMessage(status);
1768 
1769 				delete[] escapements;
1770 				delete[] offsets;
1771 
1772 			} else
1773 				fLink.StartMessage(status);
1774 
1775 			delete[] charArray;
1776 			fLink.Flush();
1777 			break;
1778 		}
1779 		case AS_GET_ESCAPEMENTS_AS_FLOATS:
1780 		{
1781 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS_AS_FLOATS\n", Signature()));
1782 			// Attached Data:
1783 			// 1) uint16 - family ID
1784 			// 2) uint16 - style ID
1785 			// 3) float - point size
1786 			// 4) uint8 - spacing
1787 			// 5) float - rotation
1788 			// 6) uint32 - flags
1789 
1790 			// 7) float - additional "nonspace" delta
1791 			// 8) float - additional "space" delta
1792 
1793 			// 9) int32 - numChars
1794 			// 10) int32 - numBytes
1795 			// 11) char - the char buffer with size numBytes
1796 
1797 			// Returns:
1798 			// 1) float - escapement buffer with numChar entries
1799 
1800 			uint16 familyID, styleID;
1801 			uint32 flags;
1802 			float size, rotation;
1803 			uint8 spacing;
1804 
1805 			link.Read<uint16>(&familyID);
1806 			link.Read<uint16>(&styleID);
1807 			link.Read<float>(&size);
1808 			link.Read<uint8>(&spacing);
1809 			link.Read<float>(&rotation);
1810 			link.Read<uint32>(&flags);
1811 
1812 			escapement_delta delta;
1813 			link.Read<float>(&delta.nonspace);
1814 			link.Read<float>(&delta.space);
1815 
1816 			int32 numChars;
1817 			link.Read<int32>(&numChars);
1818 
1819 			uint32 numBytes;
1820 			link.Read<uint32>(&numBytes);
1821 			char* charArray = new (nothrow) char[numBytes];
1822 			link.Read(charArray, numBytes);
1823 
1824 			float* escapements = new (nothrow) float[numChars];
1825 
1826 			// figure out escapements
1827 
1828 			ServerFont font;
1829 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
1830 			if (status == B_OK) {
1831 				font.SetSize(size);
1832 				font.SetSpacing(spacing);
1833 				font.SetRotation(rotation);
1834 				font.SetFlags(flags);
1835 
1836 				status = font.GetEscapements(charArray, numChars, delta,
1837 					escapements);
1838 
1839 				if (status == B_OK) {
1840 					fLink.StartMessage(B_OK);
1841 					fLink.Attach(escapements, numChars * sizeof(float));
1842 				}
1843 			}
1844 
1845 			delete[] charArray;
1846 			delete[] escapements;
1847 
1848 			if (status != B_OK)
1849 				fLink.StartMessage(status);
1850 
1851 			fLink.Flush();
1852 			break;
1853 		}
1854 		case AS_GET_BOUNDINGBOXES_CHARS:
1855 		{
1856 			FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_CHARS\n", Signature()));
1857 			// Attached Data:
1858 			// 1) uint16 - family ID
1859 			// 2) uint16 - style ID
1860 			// 3) float - point size
1861 			// 4) float - rotation
1862 			// 5) float - shear
1863 			// 6) float - false bold width
1864 			// 7) uint8 - spacing
1865 			// 8) uint32 - flags
1866 
1867 			// 9) font_metric_mode - mode
1868 			// 10) bool - string escapement
1869 
1870 			// 11) escapement_delta - additional delta
1871 
1872 			// 12) int32 - numChars
1873 			// 13) int32 - numBytes
1874 			// 14) char - the char buffer with size numBytes
1875 
1876 			// Returns:
1877 			// 1) BRect - rects with numChar entries
1878 
1879 			uint16 famid, styid;
1880 			uint32 flags;
1881 			float ptsize, rotation, shear, falseBoldWidth;
1882 			uint8 spacing;
1883 			font_metric_mode mode;
1884 			bool string_escapement;
1885 
1886 			link.Read<uint16>(&famid);
1887 			link.Read<uint16>(&styid);
1888 			link.Read<float>(&ptsize);
1889 			link.Read<float>(&rotation);
1890 			link.Read<float>(&shear);
1891 			link.Read<float>(&falseBoldWidth);
1892 			link.Read<uint8>(&spacing);
1893 			link.Read<uint32>(&flags);
1894 			link.Read<font_metric_mode>(&mode);
1895 			link.Read<bool>(&string_escapement);
1896 
1897 			escapement_delta delta;
1898 			link.Read<escapement_delta>(&delta);
1899 
1900 			int32 numChars;
1901 			link.Read<int32>(&numChars);
1902 
1903 			uint32 numBytes;
1904 			link.Read<uint32>(&numBytes);
1905 
1906 			char *charArray = new (nothrow) char[numBytes];
1907 			link.Read(charArray, numBytes);
1908 
1909 			BRect rectArray[numChars];
1910 			// figure out escapements
1911 
1912 			ServerFont font;
1913 			bool success = false;
1914 			if (font.SetFamilyAndStyle(famid, styid) == B_OK) {
1915 				font.SetSize(ptsize);
1916 				font.SetRotation(rotation);
1917 				font.SetShear(shear);
1918 				font.SetFalseBoldWidth(falseBoldWidth);
1919 				font.SetSpacing(spacing);
1920 				font.SetFlags(flags);
1921 
1922 				// TODO implement for real
1923 				if (font.GetBoundingBoxesAsString(charArray, numChars,
1924 					rectArray, string_escapement, mode, delta) == B_OK) {
1925 					fLink.StartMessage(B_OK);
1926 					fLink.Attach(rectArray, sizeof(rectArray));
1927 					success = true;
1928 				}
1929 			}
1930 
1931 			if (!success)
1932 				fLink.StartMessage(B_ERROR);
1933 
1934 			delete[] charArray;
1935 			fLink.Flush();
1936 			break;
1937 		}
1938 		case AS_GET_BOUNDINGBOXES_STRINGS:
1939 		{
1940 			FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_STRINGS\n", Signature()));
1941 			// Attached Data:
1942 			// 1) uint16 - family ID
1943 			// 2) uint16 - style ID
1944 			// 3) float - point size
1945 			// 4) float - rotation
1946 			// 5) float - shear
1947 			// 6) float - false bold width
1948 			// 7) uint8 - spacing
1949 			// 8) uint32 - flags
1950 
1951 			// 9) font_metric_mode - mode
1952 			// 10) int32 numStrings
1953 
1954 			// 11) escapement_delta - additional delta (numStrings times)
1955 			// 12) int32 string length to measure (numStrings times)
1956 			// 13) string - string (numStrings times)
1957 
1958 			// Returns:
1959 			// 1) BRect - rects with numStrings entries
1960 
1961 			uint16 famid, styid;
1962 			uint32 flags;
1963 			float ptsize, rotation, shear, falseBoldWidth;
1964 			uint8 spacing;
1965 			font_metric_mode mode;
1966 
1967 			link.Read<uint16>(&famid);
1968 			link.Read<uint16>(&styid);
1969 			link.Read<float>(&ptsize);
1970 			link.Read<float>(&rotation);
1971 			link.Read<float>(&shear);
1972 			link.Read<float>(&falseBoldWidth);
1973 			link.Read<uint8>(&spacing);
1974 			link.Read<uint32>(&flags);
1975 			link.Read<font_metric_mode>(&mode);
1976 
1977 			int32 numStrings;
1978 			link.Read<int32>(&numStrings);
1979 
1980 			escapement_delta deltaArray[numStrings];
1981 			char *stringArray[numStrings];
1982 			int32 lengthArray[numStrings];
1983 			for(int32 i=0; i<numStrings; i++) {
1984 				// This version of ReadString allocates the strings, we free them below
1985 				link.ReadString(&stringArray[i], (size_t *)&lengthArray[i]);
1986 				link.Read<escapement_delta>(&deltaArray[i]);
1987 			}
1988 
1989 			BRect rectArray[numStrings];
1990 
1991 			ServerFont font;
1992 			bool success = false;
1993 			if (font.SetFamilyAndStyle(famid, styid) == B_OK) {
1994 				font.SetSize(ptsize);
1995 				font.SetRotation(rotation);
1996 				font.SetShear(shear);
1997 				font.SetFalseBoldWidth(falseBoldWidth);
1998 				font.SetSpacing(spacing);
1999 				font.SetFlags(flags);
2000 
2001 				if (font.GetBoundingBoxesForStrings(stringArray, lengthArray,
2002 					numStrings, rectArray, mode, deltaArray) == B_OK) {
2003 					fLink.StartMessage(B_OK);
2004 					fLink.Attach(rectArray, sizeof(rectArray));
2005 					success = true;
2006 				}
2007 			}
2008 
2009 			for (int32 i = 0; i < numStrings; i++)
2010 				free(stringArray[i]);
2011 
2012 			if (!success)
2013 				fLink.StartMessage(B_ERROR);
2014 
2015 			fLink.Flush();
2016 			break;
2017 		}
2018 
2019 		/* screen commands */
2020 
2021 		case AS_VALID_SCREEN_ID:
2022 		{
2023 			// Attached data
2024 			// 1) screen_id screen
2025 			screen_id id;
2026 			if (link.Read<screen_id>(&id) == B_OK
2027 				&& id.id == B_MAIN_SCREEN_ID.id)
2028 				fLink.StartMessage(B_OK);
2029 			else
2030 				fLink.StartMessage(B_ERROR);
2031 
2032 			fLink.Flush();
2033 			break;
2034 		}
2035 
2036 		case AS_GET_NEXT_SCREEN_ID:
2037 		{
2038 			// Attached data
2039 			// 1) screen_id screen
2040 			screen_id id;
2041 			link.Read<screen_id>(&id);
2042 
2043 			// TODO: for now, just say we're the last one
2044 			fLink.StartMessage(B_ENTRY_NOT_FOUND);
2045 			fLink.Flush();
2046 			break;
2047 		}
2048 
2049 		case AS_GET_SCREEN_ID_FROM_WINDOW:
2050 		{
2051 			status_t status = B_ENTRY_NOT_FOUND;
2052 
2053 			// Attached data
2054 			// 1) int32 - window client token
2055 			int32 clientToken;
2056 			if (link.Read<int32>(&clientToken) != B_OK)
2057 				status = B_BAD_DATA;
2058 			else {
2059 				BAutolock locker(fWindowListLock);
2060 
2061 				for (int32 i = fWindowList.CountItems(); i-- > 0;) {
2062 					ServerWindow* window = fWindowList.ItemAt(i);
2063 
2064 					if (window->ClientToken() == clientToken) {
2065 						// got it!
2066 						fLink.StartMessage(B_OK);
2067 						fLink.Attach<screen_id>(B_MAIN_SCREEN_ID);
2068 							// TODO: for now...
2069 						status = B_OK;
2070 					}
2071 				}
2072 			}
2073 
2074 			if (status != B_OK)
2075 				fLink.StartMessage(status);
2076 			fLink.Flush();
2077 			break;
2078 		}
2079 
2080 		case AS_SCREEN_GET_MODE:
2081 		{
2082 			STRACE(("ServerApp %s: AS_SCREEN_GET_MODE\n", Signature()));
2083 			// Attached data
2084 			// 1) screen_id screen
2085 			// 2) uint32 workspace index
2086 			screen_id id;
2087 			link.Read<screen_id>(&id);
2088 			uint32 workspace;
2089 			link.Read<uint32>(&workspace);
2090 
2091 			// TODO: the display_mode can be different between
2092 			// the various screens.
2093 			// We have the screen_id and the workspace number, with these
2094 			// we need to find the corresponding "driver", and call getmode on it
2095 			display_mode mode;
2096 			fDesktop->ScreenAt(0)->GetMode(&mode);
2097 			// actually this isn't still enough as different workspaces can
2098 			// have different display_modes
2099 
2100 			fLink.StartMessage(B_OK);
2101 			fLink.Attach<display_mode>(mode);
2102 			fLink.Flush();
2103 			break;
2104 		}
2105 		case AS_SCREEN_SET_MODE:
2106 		{
2107 			STRACE(("ServerApp %s: AS_SCREEN_SET_MODE\n", Signature()));
2108 			// Attached data
2109 			// 1) screen_id
2110 			// 2) workspace index
2111 			// 3) display_mode to set
2112 			// 4) 'makeDefault' boolean
2113 			// TODO: See above: workspaces support, etc.
2114 
2115 			screen_id id;
2116 			link.Read<screen_id>(&id);
2117 
2118 			uint32 workspace;
2119 			link.Read<uint32>(&workspace);
2120 
2121 			display_mode mode;
2122 			link.Read<display_mode>(&mode);
2123 
2124 			bool makeDefault = false;
2125 			status_t status = link.Read<bool>(&makeDefault);
2126 
2127 			if (status == B_OK && fDesktop->LockAllWindows()) {
2128 				display_mode oldMode;
2129 				fDesktop->ScreenAt(0)->GetMode(&oldMode);
2130 				if (memcmp(&oldMode, &mode, sizeof(display_mode))) {
2131 					status = fDesktop->ScreenAt(0)->SetMode(mode, makeDefault);
2132 					if (status == B_OK) {
2133 						gInputManager->UpdateScreenBounds(fDesktop->ScreenAt(0)->Frame());
2134 						fDesktop->ScreenChanged(fDesktop->ScreenAt(0), makeDefault);
2135 					}
2136 				} else
2137 					status = B_OK;
2138 				fDesktop->UnlockAllWindows();
2139 			} else
2140 				status = B_ERROR;
2141 
2142 			fLink.StartMessage(status);
2143 			fLink.Flush();
2144 			break;
2145 		}
2146 
2147 		case AS_PROPOSE_MODE:
2148 		{
2149 			STRACE(("ServerApp %s: AS_PROPOSE_MODE\n", Signature()));
2150 			screen_id id;
2151 			link.Read<screen_id>(&id);
2152 
2153 			display_mode target, low, high;
2154 			link.Read<display_mode>(&target);
2155 			link.Read<display_mode>(&low);
2156 			link.Read<display_mode>(&high);
2157 			status_t status = fDesktop->HWInterface()->ProposeMode(&target, &low, &high);
2158 
2159 			// ProposeMode() returns B_BAD_VALUE to hint that the candidate is
2160 			// not within the given limits (but is supported)
2161 			if (status == B_OK || status == B_BAD_VALUE) {
2162 				fLink.StartMessage(B_OK);
2163 				fLink.Attach<display_mode>(target);
2164 				fLink.Attach<bool>(status == B_OK);
2165 			} else
2166 				fLink.StartMessage(status);
2167 
2168 			fLink.Flush();
2169 			break;
2170 		}
2171 
2172 		case AS_GET_MODE_LIST:
2173 		{
2174 			screen_id id;
2175 			link.Read<screen_id>(&id);
2176 			// TODO: use this screen id
2177 
2178 			display_mode* modeList;
2179 			uint32 count;
2180 			status_t status = fDesktop->HWInterface()->GetModeList(&modeList, &count);
2181 			if (status == B_OK) {
2182 				fLink.StartMessage(B_OK);
2183 				fLink.Attach<uint32>(count);
2184 				fLink.Attach(modeList, sizeof(display_mode) * count);
2185 
2186 				delete[] modeList;
2187 			} else
2188 				fLink.StartMessage(status);
2189 
2190 			fLink.Flush();
2191 			break;
2192 		}
2193 
2194 		case AS_SCREEN_GET_COLORMAP:
2195 		{
2196 			STRACE(("ServerApp %s: AS_SCREEN_GET_COLORMAP\n", Signature()));
2197 
2198 			screen_id id;
2199 			link.Read<screen_id>(&id);
2200 
2201 			const color_map *colorMap = SystemColorMap();
2202 			if (colorMap != NULL) {
2203 				fLink.StartMessage(B_OK);
2204 				fLink.Attach<color_map>(*colorMap);
2205 			} else
2206 				fLink.StartMessage(B_ERROR);
2207 
2208 			fLink.Flush();
2209 			break;
2210 		}
2211 
2212 		case AS_GET_DESKTOP_COLOR:
2213 		{
2214 			STRACE(("ServerApp %s: get desktop color\n", Signature()));
2215 
2216 			uint32 index;
2217 			link.Read<uint32>(&index);
2218 
2219 			fLink.StartMessage(B_OK);
2220 			fDesktop->Lock();
2221 
2222 			// we're nice to our children (and also take the default case
2223 			// into account which asks for the current workspace)
2224 			if (index >= (uint32)kMaxWorkspaces)
2225 				index = fDesktop->CurrentWorkspace();
2226 
2227 			Workspace workspace(*fDesktop, index);
2228 			fLink.Attach<rgb_color>(workspace.Color().GetColor32());
2229 
2230 			fDesktop->Unlock();
2231 			fLink.Flush();
2232 			break;
2233 		}
2234 
2235 		case AS_SET_DESKTOP_COLOR:
2236 		{
2237 			STRACE(("ServerApp %s: set desktop color\n", Signature()));
2238 
2239 			rgb_color color;
2240 			uint32 index;
2241 			bool makeDefault;
2242 
2243 			link.Read<rgb_color>(&color);
2244 			link.Read<uint32>(&index);
2245 			if (link.Read<bool>(&makeDefault) != B_OK)
2246 				break;
2247 
2248 			fDesktop->Lock();
2249 
2250 			// we're nice to our children (and also take the default case
2251 			// into account which asks for the current workspace)
2252 			if (index >= (uint32)kMaxWorkspaces)
2253 				index = fDesktop->CurrentWorkspace();
2254 
2255 			Workspace workspace(*fDesktop, index);
2256 			workspace.SetColor(color, makeDefault);
2257 
2258 			fDesktop->Unlock();
2259 			break;
2260 		}
2261 
2262 		case AS_GET_ACCELERANT_INFO:
2263 		{
2264 			STRACE(("ServerApp %s: get accelerant info\n", Signature()));
2265 
2266 			// We aren't using the screen_id for now...
2267 			screen_id id;
2268 			link.Read<screen_id>(&id);
2269 
2270 			accelerant_device_info accelerantInfo;
2271 			// TODO: I wonder if there should be a "desktop" lock...
2272 			status_t status = fDesktop->HWInterface()->GetDeviceInfo(&accelerantInfo);
2273 			if (status == B_OK) {
2274 				fLink.StartMessage(B_OK);
2275 				fLink.Attach<accelerant_device_info>(accelerantInfo);
2276 			} else
2277 				fLink.StartMessage(status);
2278 
2279 			fLink.Flush();
2280 			break;
2281 		}
2282 
2283 		case AS_GET_FRAME_BUFFER_CONFIG:
2284 		{
2285 			STRACE(("ServerApp %s: get frame buffer config\n", Signature()));
2286 
2287 			// We aren't using the screen_id for now...
2288 			screen_id id;
2289 			link.Read<screen_id>(&id);
2290 
2291 			frame_buffer_config config;
2292 			// TODO: I wonder if there should be a "desktop" lock...
2293 			status_t status = fDesktop->HWInterface()->GetFrameBufferConfig(config);
2294 			if (status == B_OK) {
2295 				fLink.StartMessage(B_OK);
2296 				fLink.Attach<frame_buffer_config>(config);
2297 			} else
2298 				fLink.StartMessage(status);
2299 
2300 			fLink.Flush();
2301 			break;
2302 		}
2303 
2304 		case AS_GET_RETRACE_SEMAPHORE:
2305 		{
2306 			STRACE(("ServerApp %s: get retrace semaphore\n", Signature()));
2307 
2308 			// We aren't using the screen_id for now...
2309 			screen_id id;
2310 			link.Read<screen_id>(&id);
2311 
2312 			fLink.StartMessage(B_OK);
2313 			fLink.Attach<sem_id>(fDesktop->HWInterface()->RetraceSemaphore());
2314 			fLink.Flush();
2315 			break;
2316 		}
2317 
2318 		case AS_GET_TIMING_CONSTRAINTS:
2319 		{
2320 			STRACE(("ServerApp %s: get timing constraints\n", Signature()));
2321 			// We aren't using the screen_id for now...
2322 			screen_id id;
2323 			link.Read<screen_id>(&id);
2324 
2325 			display_timing_constraints constraints;
2326 			status_t status = fDesktop->HWInterface()->GetTimingConstraints(
2327 				&constraints);
2328 			if (status == B_OK) {
2329 				fLink.StartMessage(B_OK);
2330 				fLink.Attach<display_timing_constraints>(constraints);
2331 			} else
2332 				fLink.StartMessage(status);
2333 
2334 			fLink.Flush();
2335 			break;
2336 		}
2337 
2338 		case AS_GET_PIXEL_CLOCK_LIMITS:
2339 		{
2340 			STRACE(("ServerApp %s: get pixel clock limits\n", Signature()));
2341 			// We aren't using the screen_id for now...
2342 			screen_id id;
2343 			link.Read<screen_id>(&id);
2344 			display_mode mode;
2345 			link.Read<display_mode>(&mode);
2346 
2347 			uint32 low, high;
2348 			status_t status = fDesktop->HWInterface()->GetPixelClockLimits(&mode,
2349 				&low, &high);
2350 			if (status == B_OK) {
2351 				fLink.StartMessage(B_OK);
2352 				fLink.Attach<uint32>(low);
2353 				fLink.Attach<uint32>(high);
2354 			} else
2355 				fLink.StartMessage(status);
2356 
2357 			fLink.Flush();
2358 			break;
2359 		}
2360 
2361 		case AS_SET_DPMS:
2362 		{
2363 			STRACE(("ServerApp %s: AS_SET_DPMS\n", Signature()));
2364 			screen_id id;
2365 			link.Read<screen_id>(&id);
2366 
2367 			uint32 mode;
2368 			link.Read<uint32>(&mode);
2369 
2370 			status_t status = fDesktop->HWInterface()->SetDPMSMode(mode);
2371 			fLink.StartMessage(status);
2372 
2373 			fLink.Flush();
2374 			break;
2375 		}
2376 
2377 		case AS_GET_DPMS_STATE:
2378 		{
2379 			STRACE(("ServerApp %s: AS_GET_DPMS_STATE\n", Signature()));
2380 
2381 			screen_id id;
2382 			link.Read<screen_id>(&id);
2383 
2384 			uint32 state = fDesktop->HWInterface()->DPMSMode();
2385 			fLink.StartMessage(B_OK);
2386 			fLink.Attach<uint32>(state);
2387 			fLink.Flush();
2388 			break;
2389 		}
2390 
2391 		case AS_GET_DPMS_CAPABILITIES:
2392 		{
2393 			STRACE(("ServerApp %s: AS_GET_DPMS_CAPABILITIES\n", Signature()));
2394 			screen_id id;
2395 			link.Read<screen_id>(&id);
2396 
2397 			uint32 capabilities = fDesktop->HWInterface()->DPMSCapabilities();
2398 			fLink.StartMessage(B_OK);
2399 			fLink.Attach<uint32>(capabilities);
2400 			fLink.Flush();
2401 			break;
2402 		}
2403 
2404 		case AS_READ_BITMAP:
2405 		{
2406 			STRACE(("ServerApp %s: AS_READ_BITMAP\n", Signature()));
2407 			int32 bitmapToken;
2408 			link.Read<int32>(&bitmapToken);
2409 
2410 			bool drawCursor = true;
2411 			link.Read<bool>(&drawCursor);
2412 
2413 			BRect bounds;
2414 			link.Read<BRect>(&bounds);
2415 
2416 			ServerBitmap *bitmap = FindBitmap(bitmapToken);
2417 			if (bitmap != NULL) {
2418 				if (fDesktop->GetDrawingEngine()->ReadBitmap(bitmap,
2419 					drawCursor, bounds) == B_OK) {
2420 					fLink.StartMessage(B_OK);
2421 				} else
2422 					fLink.StartMessage(B_BAD_VALUE);
2423 			} else
2424 				fLink.StartMessage(B_BAD_VALUE);
2425 
2426 			fLink.Flush();
2427 			break;
2428 		}
2429 
2430 		case AS_GET_ACCELERANT_PATH:
2431 		{
2432 			int32 index;
2433 			fLink.Read<int32>(&index);
2434 
2435 			BString path;
2436 			status_t status = fDesktop->HWInterface()->GetAccelerantPath(path);
2437 			fLink.StartMessage(status);
2438 			if (status == B_OK)
2439 				fLink.AttachString(path.String());
2440 
2441 			fLink.Flush();
2442 			break;
2443 		}
2444 
2445 		case AS_GET_DRIVER_PATH:
2446 		{
2447 			int32 index;
2448 			fLink.Read<int32>(&index);
2449 
2450 			BString path;
2451 			status_t status = fDesktop->HWInterface()->GetDriverPath(path);
2452 			fLink.StartMessage(status);
2453 			if (status == B_OK)
2454 				fLink.AttachString(path.String());
2455 
2456 			fLink.Flush();
2457 			break;
2458 		}
2459 
2460 		default:
2461 			printf("ServerApp %s received unhandled message code %ld\n",
2462 				Signature(), code);
2463 
2464 			if (link.NeedsReply()) {
2465 				// the client is now blocking and waiting for a reply!
2466 				fLink.StartMessage(B_ERROR);
2467 				fLink.Flush();
2468 			} else
2469 				puts("message doesn't need a reply!");
2470 			break;
2471 	}
2472 }
2473 
2474 
2475 status_t
2476 ServerApp::_CreateWindow(int32 code, BPrivate::LinkReceiver& link,
2477 	port_id& clientReplyPort)
2478 {
2479 	// Attached data:
2480 	// 1) int32 bitmap token (only for AS_CREATE_OFFSCREEN_WINDOW)
2481 	// 2) BRect window frame
2482 	// 3) uint32 window look
2483 	// 4) uint32 window feel
2484 	// 5) uint32 window flags
2485 	// 6) uint32 workspace index
2486 	// 7) int32 BHandler token of the window
2487 	// 8) port_id window's reply port
2488 	// 9) port_id window's looper port
2489 	// 10) const char * title
2490 
2491 	BRect frame;
2492 	int32 bitmapToken;
2493 	uint32 look;
2494 	uint32 feel;
2495 	uint32 flags;
2496 	uint32 workspaces;
2497 	int32 token;
2498 	port_id looperPort;
2499 	char* title;
2500 
2501 	if (code == AS_CREATE_OFFSCREEN_WINDOW)
2502 		link.Read<int32>(&bitmapToken);
2503 
2504 	link.Read<BRect>(&frame);
2505 	link.Read<uint32>(&look);
2506 	link.Read<uint32>(&feel);
2507 	link.Read<uint32>(&flags);
2508 	link.Read<uint32>(&workspaces);
2509 	link.Read<int32>(&token);
2510 	link.Read<port_id>(&clientReplyPort);
2511 	link.Read<port_id>(&looperPort);
2512 	if (link.ReadString(&title) != B_OK)
2513 		return B_ERROR;
2514 
2515 	if (!frame.IsValid()) {
2516 		// make sure we pass a valid rectangle to ServerWindow
2517 		frame.right = frame.left + 1;
2518 		frame.bottom = frame.top + 1;
2519 	}
2520 
2521 	status_t status = B_ERROR;
2522 	ServerWindow *window = NULL;
2523 
2524 	if (code == AS_CREATE_OFFSCREEN_WINDOW) {
2525 		ServerBitmap* bitmap = FindBitmap(bitmapToken);
2526 
2527 		if (bitmap != NULL) {
2528 			window = new (nothrow) OffscreenServerWindow(title, this, clientReplyPort,
2529 				looperPort, token, bitmap);
2530 		}
2531 	} else {
2532 		window = new (nothrow) ServerWindow(title, this, clientReplyPort, looperPort, token);
2533 		STRACE(("\nServerApp %s: New Window %s (%g:%g, %g:%g)\n",
2534 			Signature(), title, frame.left, frame.top,
2535 			frame.right, frame.bottom));
2536 	}
2537 
2538 	free(title);
2539 
2540 	// NOTE: the reply to the client is handled in ServerWindow::Run()
2541 	if (window != NULL) {
2542 		status = window->Init(frame, (window_look)look, (window_feel)feel,
2543 			flags, workspaces);
2544 		if (status == B_OK && !window->Run()) {
2545 			fprintf(stderr, "ServerApp::_CreateWindow() - failed to run the window thread\n");
2546 			status = B_ERROR;
2547 		}
2548 
2549 		if (status < B_OK)
2550 			delete window;
2551 	}
2552 
2553 	return status;
2554 }
2555 
2556 
2557 bool
2558 ServerApp::AddWindow(ServerWindow* window)
2559 {
2560 	BAutolock locker(fWindowListLock);
2561 
2562 	return fWindowList.AddItem(window);
2563 }
2564 
2565 
2566 void
2567 ServerApp::RemoveWindow(ServerWindow* window)
2568 {
2569 	BAutolock locker(fWindowListLock);
2570 
2571 	fWindowList.RemoveItem(window);
2572 }
2573 
2574 
2575 bool
2576 ServerApp::InWorkspace(int32 index) const
2577 {
2578 	BAutolock locker(fWindowListLock);
2579 
2580 	// we could cache this, but then we'd have to recompute the cached
2581 	// value everytime a window has closed or changed workspaces
2582 
2583 	// TODO: support initial application workspace!
2584 
2585 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
2586 		ServerWindow* serverWindow = fWindowList.ItemAt(i);
2587 
2588 		const WindowLayer* window = serverWindow->Window();
2589 		if (window == NULL || window->IsOffscreenWindow())
2590 			continue;
2591 
2592 		// only normal and unhidden windows count
2593 
2594 		if (window->IsNormal() && !window->IsHidden() && window->InWorkspace(index))
2595 			return true;
2596 	}
2597 
2598 	return false;
2599 }
2600 
2601 
2602 uint32
2603 ServerApp::Workspaces() const
2604 {
2605 	uint32 workspaces = 0;
2606 
2607 	BAutolock locker(fWindowListLock);
2608 
2609 	// we could cache this, but then we'd have to recompute the cached
2610 	// value everytime a window has closed or changed workspaces
2611 
2612 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
2613 		ServerWindow* serverWindow = fWindowList.ItemAt(i);
2614 
2615 		const WindowLayer* window = serverWindow->Window();
2616 		if (window == NULL || window->IsOffscreenWindow())
2617 			continue;
2618 
2619 		// only normal and unhidden windows count
2620 
2621 		if (window->IsNormal() && !window->IsHidden())
2622 			workspaces |= window->Workspaces();
2623 	}
2624 
2625 	// TODO: add initial application workspace!
2626 	return workspaces;
2627 }
2628 
2629 
2630 int32
2631 ServerApp::CountBitmaps() const
2632 {
2633 	return fBitmapList.CountItems();
2634 }
2635 
2636 
2637 /*!
2638 	\brief Looks up a ServerApp's ServerBitmap in its list
2639 	\param token ID token of the bitmap to find
2640 	\return The bitmap having that ID or NULL if not found
2641 */
2642 ServerBitmap*
2643 ServerApp::FindBitmap(int32 token) const
2644 {
2645 	// TODO: we need to make sure the bitmap is ours?!
2646 	ServerBitmap* bitmap;
2647 	if (gTokenSpace.GetToken(token, kBitmapToken, (void**)&bitmap) == B_OK)
2648 		return bitmap;
2649 
2650 	return NULL;
2651 }
2652 
2653 
2654 int32
2655 ServerApp::CountPictures() const
2656 {
2657 	return fPictureList.CountItems();
2658 }
2659 
2660 
2661 ServerPicture *
2662 ServerApp::CreatePicture(const ServerPicture *original)
2663 {
2664 	ServerPicture *picture;
2665 	if (original != NULL)
2666 		picture = new (nothrow) ServerPicture(*original);
2667 	else
2668 		picture = new (nothrow) ServerPicture();
2669 
2670 	if (picture != NULL)
2671 		fPictureList.AddItem(picture);
2672 
2673 	return picture;
2674 }
2675 
2676 
2677 ServerPicture *
2678 ServerApp::FindPicture(const int32 &token) const
2679 {
2680 	// TODO: we need to make sure the picture is ours?!
2681 	ServerPicture* picture;
2682 	if (gTokenSpace.GetToken(token, kPictureToken, (void**)&picture) == B_OK)
2683 		return picture;
2684 
2685 	return NULL;
2686 }
2687 
2688 
2689 bool
2690 ServerApp::DeletePicture(const int32 &token)
2691 {
2692 	ServerPicture *picture = FindPicture(token);
2693 	if (picture == NULL)
2694 		return false;
2695 
2696 	if (!fPictureList.RemoveItem(picture))
2697 		return false;
2698 
2699 	delete picture;
2700 
2701 	return true;
2702 }
2703 
2704 
2705 team_id
2706 ServerApp::ClientTeam() const
2707 {
2708 	return fClientTeam;
2709 }
2710 
2711