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