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