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