xref: /haiku/src/servers/app/ServerApp.cpp (revision c42868a015daa160e093679b2637b1cf9f0b26ba)
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_UNICODE_BLOCKS:
2032 		{
2033 			FTRACE(("ServerApp %s: AS_GET_UNICODE_BLOCKS\n", Signature()));
2034 
2035 			// Attached Data:
2036 			// 1) uint16 family ID
2037 			// 2) uint16 style ID
2038 
2039 			// Returns:
2040 			// 1) unicode_block - bitfield of Unicode blocks in font
2041 
2042 			uint16 familyID, styleID;
2043 			link.Read<uint16>(&familyID);
2044 			link.Read<uint16>(&styleID);
2045 
2046 			ServerFont font;
2047 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2048 			if (status == B_OK) {
2049 				unicode_block blocksForFont;
2050 				font.GetUnicodeBlocks(blocksForFont);
2051 
2052 				fLink.StartMessage(B_OK);
2053 				fLink.Attach<unicode_block>(blocksForFont);
2054 			} else
2055 				fLink.StartMessage(status);
2056 
2057 			fLink.Flush();
2058 			break;
2059 		}
2060 
2061 		case AS_GET_HAS_UNICODE_BLOCK:
2062 		{
2063 			FTRACE(("ServerApp %s: AS_INCLUDES_UNICODE_BLOCK\n", Signature()));
2064 
2065 			// Attached Data:
2066 			// 1) uint16 family ID
2067 			// 2) uint16 style ID
2068 			// 3 uint32 start of unicode block
2069 			// 4) uint32 end of unicode block
2070 
2071 			// Returns:
2072 			// 1) bool - whether or not font includes specified block range
2073 
2074 			uint16 familyID, styleID;
2075 			uint32 start, end;
2076 			link.Read<uint16>(&familyID);
2077 			link.Read<uint16>(&styleID);
2078 			link.Read<uint32>(&start);
2079 			link.Read<uint32>(&end);
2080 
2081 			ServerFont font;
2082 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2083 			if (status == B_OK) {
2084 				bool hasBlock;
2085 
2086 				status = font.IncludesUnicodeBlock(start, end, hasBlock);
2087 				fLink.StartMessage(status);
2088 				fLink.Attach<bool>(hasBlock);
2089 			} else
2090 				fLink.StartMessage(status);
2091 
2092 			fLink.Flush();
2093 			break;
2094 		}
2095 
2096 		case AS_GET_GLYPH_SHAPES:
2097 		{
2098 			FTRACE(("ServerApp %s: AS_GET_GLYPH_SHAPES\n", Signature()));
2099 
2100 			// Attached Data:
2101 			// 1) uint16 - family ID
2102 			// 2) uint16 - style ID
2103 			// 3) float - point size
2104 			// 4) float - shear
2105 			// 5) float - rotation
2106 			// 6) float - false bold width
2107 			// 6) uint32 - flags
2108 			// 7) int32 - numChars
2109 			// 8) int32 - numBytes
2110 			// 8) char - chars (bytesInBuffer times)
2111 
2112 			// Returns:
2113 			// 1) BShape - glyph shape
2114 			// numChars times
2115 
2116 			uint16 familyID, styleID;
2117 			uint32 flags;
2118 			float size, shear, rotation, falseBoldWidth;
2119 
2120 			link.Read<uint16>(&familyID);
2121 			link.Read<uint16>(&styleID);
2122 			link.Read<float>(&size);
2123 			link.Read<float>(&shear);
2124 			link.Read<float>(&rotation);
2125 			link.Read<float>(&falseBoldWidth);
2126 			link.Read<uint32>(&flags);
2127 
2128 			int32 numChars, numBytes;
2129 			link.Read<int32>(&numChars);
2130 			link.Read<int32>(&numBytes);
2131 
2132 			// TODO: proper error checking
2133 			char* charArray = new (nothrow) char[numBytes];
2134 			link.Read(charArray, numBytes);
2135 
2136 			ServerFont font;
2137 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2138 			if (status == B_OK) {
2139 				font.SetSize(size);
2140 				font.SetShear(shear);
2141 				font.SetRotation(rotation);
2142 				font.SetFalseBoldWidth(falseBoldWidth);
2143 				font.SetFlags(flags);
2144 
2145 				// TODO: proper error checking
2146 				BShape** shapes = new (nothrow) BShape*[numChars];
2147 				status = font.GetGlyphShapes(charArray, numChars, shapes);
2148 				if (status == B_OK) {
2149 					fLink.StartMessage(B_OK);
2150 					for (int32 i = 0; i < numChars; i++) {
2151 						fLink.AttachShape(*shapes[i]);
2152 						delete shapes[i];
2153 					}
2154 				} else
2155 					fLink.StartMessage(status);
2156 
2157 				delete[] shapes;
2158 			} else
2159 				fLink.StartMessage(status);
2160 
2161 			delete[] charArray;
2162 			fLink.Flush();
2163 			break;
2164 		}
2165 
2166 		case AS_GET_HAS_GLYPHS:
2167 		{
2168 			FTRACE(("ServerApp %s: AS_GET_HAS_GLYPHS\n", Signature()));
2169 
2170 			// Attached Data:
2171 			// 1) uint16 - family ID
2172 			// 2) uint16 - style ID
2173 			// 3) int32 - numChars
2174 			// 4) int32 - numBytes
2175 			// 5) char - the char buffer with size numBytes
2176 
2177 			uint16 familyID, styleID;
2178 			link.Read<uint16>(&familyID);
2179 			link.Read<uint16>(&styleID);
2180 
2181 			int32 numChars, numBytes;
2182 			link.Read<int32>(&numChars);
2183 			link.Read<int32>(&numBytes);
2184 			// TODO: proper error checking
2185 			char* charArray = new (nothrow) char[numBytes];
2186 			link.Read(charArray, numBytes);
2187 
2188 			ServerFont font;
2189 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2190 			if (status == B_OK) {
2191 				bool hasArray[numChars];
2192 				status = font.GetHasGlyphs(charArray, numBytes, hasArray);
2193 				if (status == B_OK) {
2194 					fLink.StartMessage(B_OK);
2195 					fLink.Attach(hasArray, sizeof(hasArray));
2196 				} else
2197 					fLink.StartMessage(status);
2198 			} else
2199 				fLink.StartMessage(status);
2200 
2201 			delete[] charArray;
2202 			fLink.Flush();
2203 			break;
2204 		}
2205 
2206 		case AS_GET_EDGES:
2207 		{
2208 			FTRACE(("ServerApp %s: AS_GET_EDGES\n", Signature()));
2209 
2210 			// Attached Data:
2211 			// 1) uint16 - family ID
2212 			// 2) uint16 - style ID
2213 			// 3) int32 - numChars
2214 			// 4) int32 - numBytes
2215 			// 5) char - the char buffer with size numBytes
2216 
2217 			uint16 familyID, styleID;
2218 			link.Read<uint16>(&familyID);
2219 			link.Read<uint16>(&styleID);
2220 
2221 			int32 numChars;
2222 			link.Read<int32>(&numChars);
2223 
2224 			uint32 numBytes;
2225 			link.Read<uint32>(&numBytes);
2226 			// TODO: proper error checking
2227 			char* charArray = new (nothrow) char[numBytes];
2228 			link.Read(charArray, numBytes);
2229 
2230 			ServerFont font;
2231 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2232 			if (status == B_OK) {
2233 				edge_info edgeArray[numChars];
2234 				status = font.GetEdges(charArray, numBytes, edgeArray);
2235 				if (status == B_OK) {
2236 					fLink.StartMessage(B_OK);
2237 					fLink.Attach(edgeArray, sizeof(edgeArray));
2238 				} else
2239 					fLink.StartMessage(status);
2240 			} else
2241 				fLink.StartMessage(status);
2242 
2243 			delete[] charArray;
2244 			fLink.Flush();
2245 			break;
2246 		}
2247 
2248 		case AS_GET_ESCAPEMENTS:
2249 		{
2250 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS\n", Signature()));
2251 
2252 			// Attached Data:
2253 			// 1) uint16 - family ID
2254 			// 2) uint16 - style ID
2255 			// 3) float - point size
2256 			// 4) uint8 - spacing
2257 			// 5) float - rotation
2258 			// 6) uint32 - flags
2259 			// 7) int32 - numChars
2260 			// 8) char - char     -\       both
2261 			// 9) BPoint - offset -/ (numChars times)
2262 
2263 			// Returns:
2264 			// 1) BPoint - escapement
2265 			// numChars times
2266 
2267 			uint16 familyID, styleID;
2268 			uint32 flags;
2269 			float size, rotation;
2270 			uint8 spacing;
2271 
2272 			link.Read<uint16>(&familyID);
2273 			link.Read<uint16>(&styleID);
2274 			link.Read<float>(&size);
2275 			link.Read<uint8>(&spacing);
2276 			link.Read<float>(&rotation);
2277 			link.Read<uint32>(&flags);
2278 
2279 			escapement_delta delta;
2280 			link.Read<float>(&delta.nonspace);
2281 			link.Read<float>(&delta.space);
2282 
2283 			bool wantsOffsets;
2284 			link.Read<bool>(&wantsOffsets);
2285 
2286 			int32 numChars;
2287 			link.Read<int32>(&numChars);
2288 
2289 			uint32 numBytes;
2290 			link.Read<uint32>(&numBytes);
2291 
2292 			char* charArray = new(std::nothrow) char[numBytes];
2293 			BPoint* escapements = new(std::nothrow) BPoint[numChars];
2294 			BPoint* offsets = NULL;
2295 			if (wantsOffsets)
2296 				offsets = new(std::nothrow) BPoint[numChars];
2297 
2298 			if (charArray == NULL || escapements == NULL
2299 				|| (offsets == NULL && wantsOffsets)) {
2300 				delete[] charArray;
2301 				delete[] escapements;
2302 				delete[] offsets;
2303 
2304 				fLink.StartMessage(B_NO_MEMORY);
2305 				fLink.Flush();
2306 				break;
2307 			}
2308 
2309 			link.Read(charArray, numBytes);
2310 
2311 			ServerFont font;
2312 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2313 			if (status == B_OK) {
2314 				font.SetSize(size);
2315 				font.SetSpacing(spacing);
2316 				font.SetRotation(rotation);
2317 				font.SetFlags(flags);
2318 
2319 				status = font.GetEscapements(charArray, numBytes, numChars,
2320 					delta, escapements, offsets);
2321 
2322 				if (status == B_OK) {
2323 					fLink.StartMessage(B_OK);
2324 					for (int32 i = 0; i < numChars; i++)
2325 						fLink.Attach<BPoint>(escapements[i]);
2326 
2327 					if (offsets) {
2328 						for (int32 i = 0; i < numChars; i++)
2329 							fLink.Attach<BPoint>(offsets[i]);
2330 					}
2331 				} else
2332 					fLink.StartMessage(status);
2333 			} else
2334 				fLink.StartMessage(status);
2335 
2336 			delete[] charArray;
2337 			delete[] escapements;
2338 			delete[] offsets;
2339 			fLink.Flush();
2340 			break;
2341 		}
2342 
2343 		case AS_GET_ESCAPEMENTS_AS_FLOATS:
2344 		{
2345 			FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS_AS_FLOATS\n", Signature()));
2346 
2347 			// Attached Data:
2348 			// 1) uint16 - family ID
2349 			// 2) uint16 - style ID
2350 			// 3) float - point size
2351 			// 4) uint8 - spacing
2352 			// 5) float - rotation
2353 			// 6) uint32 - flags
2354 			// 7) float - additional "nonspace" delta
2355 			// 8) float - additional "space" delta
2356 			// 9) int32 - numChars
2357 			// 10) int32 - numBytes
2358 			// 11) char - the char buffer with size numBytes
2359 
2360 			// Returns:
2361 			// 1) float - escapement buffer with numChar entries
2362 
2363 			uint16 familyID, styleID;
2364 			uint32 flags;
2365 			float size, rotation;
2366 			uint8 spacing;
2367 
2368 			link.Read<uint16>(&familyID);
2369 			link.Read<uint16>(&styleID);
2370 			link.Read<float>(&size);
2371 			link.Read<uint8>(&spacing);
2372 			link.Read<float>(&rotation);
2373 			link.Read<uint32>(&flags);
2374 
2375 			escapement_delta delta;
2376 			link.Read<float>(&delta.nonspace);
2377 			link.Read<float>(&delta.space);
2378 
2379 			int32 numChars;
2380 			link.Read<int32>(&numChars);
2381 
2382 			uint32 numBytes;
2383 			link.Read<uint32>(&numBytes);
2384 
2385 			char* charArray = new (nothrow) char[numBytes];
2386 			float* escapements = new (nothrow) float[numChars];
2387 			if (charArray == NULL || escapements == NULL) {
2388 				delete[] charArray;
2389 				delete[] escapements;
2390 				fLink.StartMessage(B_NO_MEMORY);
2391 				fLink.Flush();
2392 				break;
2393 			}
2394 
2395 			link.Read(charArray, numBytes);
2396 
2397 			// figure out escapements
2398 
2399 			ServerFont font;
2400 			status_t status = font.SetFamilyAndStyle(familyID, styleID);
2401 			if (status == B_OK) {
2402 				font.SetSize(size);
2403 				font.SetSpacing(spacing);
2404 				font.SetRotation(rotation);
2405 				font.SetFlags(flags);
2406 
2407 				status = font.GetEscapements(charArray, numBytes, numChars,
2408 					delta, escapements);
2409 
2410 				if (status == B_OK) {
2411 					fLink.StartMessage(B_OK);
2412 					fLink.Attach(escapements, numChars * sizeof(float));
2413 				}
2414 			}
2415 
2416 			delete[] charArray;
2417 			delete[] escapements;
2418 
2419 			if (status != B_OK)
2420 				fLink.StartMessage(status);
2421 
2422 			fLink.Flush();
2423 			break;
2424 		}
2425 
2426 		case AS_GET_BOUNDINGBOXES_CHARS:
2427 		case AS_GET_BOUNDINGBOXES_STRING:
2428 		{
2429 			FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_CHARS\n", Signature()));
2430 
2431 			// Attached Data:
2432 			// 1) uint16 - family ID
2433 			// 2) uint16 - style ID
2434 			// 3) float - point size
2435 			// 4) float - rotation
2436 			// 5) float - shear
2437 			// 6) float - false bold width
2438 			// 7) uint8 - spacing
2439 			// 8) uint32 - flags
2440 			// 9) font_metric_mode - mode
2441 			// 10) bool - string escapement
2442 			// 11) escapement_delta - additional delta
2443 			// 12) int32 - numChars
2444 			// 13) int32 - numBytes
2445 			// 14) char - the char buffer with size numBytes
2446 
2447 			// Returns:
2448 			// 1) BRect - rects with numChar entries
2449 
2450 			uint16 familyID, styleID;
2451 			uint32 flags;
2452 			float size, rotation, shear, falseBoldWidth;
2453 			uint8 spacing;
2454 			font_metric_mode mode;
2455 			bool stringEscapement;
2456 
2457 			link.Read<uint16>(&familyID);
2458 			link.Read<uint16>(&styleID);
2459 			link.Read<float>(&size);
2460 			link.Read<float>(&rotation);
2461 			link.Read<float>(&shear);
2462 			link.Read<float>(&falseBoldWidth);
2463 			link.Read<uint8>(&spacing);
2464 			link.Read<uint32>(&flags);
2465 			link.Read<font_metric_mode>(&mode);
2466 			link.Read<bool>(&stringEscapement);
2467 
2468 			escapement_delta delta;
2469 			link.Read<escapement_delta>(&delta);
2470 
2471 			int32 numChars;
2472 			link.Read<int32>(&numChars);
2473 
2474 			uint32 numBytes;
2475 			link.Read<uint32>(&numBytes);
2476 
2477 			bool success = false;
2478 
2479 			char* charArray = new(std::nothrow) char[numBytes];
2480 			BRect* rectArray = new(std::nothrow) BRect[numChars];
2481 			if (charArray != NULL && rectArray != NULL) {
2482 				link.Read(charArray, numBytes);
2483 
2484 				// figure out escapements
2485 
2486 				ServerFont font;
2487 				if (font.SetFamilyAndStyle(familyID, styleID) == B_OK) {
2488 					font.SetSize(size);
2489 					font.SetRotation(rotation);
2490 					font.SetShear(shear);
2491 					font.SetFalseBoldWidth(falseBoldWidth);
2492 					font.SetSpacing(spacing);
2493 					font.SetFlags(flags);
2494 
2495 					// TODO: implement for real
2496 					if (font.GetBoundingBoxes(charArray, numBytes,
2497 							rectArray, stringEscapement, mode, delta,
2498 							code == AS_GET_BOUNDINGBOXES_STRING) == B_OK) {
2499 
2500 						fLink.StartMessage(B_OK);
2501 						for (int32 i = 0; i < numChars; i++)
2502 							fLink.Attach<BRect>(rectArray[i]);
2503 
2504 						success = true;
2505 					}
2506 				}
2507 			}
2508 
2509 			if (!success)
2510 				fLink.StartMessage(B_ERROR);
2511 
2512 			fLink.Flush();
2513 
2514 			delete[] charArray;
2515 			delete[] rectArray;
2516 			break;
2517 		}
2518 
2519 		case AS_GET_BOUNDINGBOXES_STRINGS:
2520 		{
2521 			FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_STRINGS\n",
2522 				Signature()));
2523 
2524 			// Attached Data:
2525 			// 1) uint16 - family ID
2526 			// 2) uint16 - style ID
2527 			// 3) float - point size
2528 			// 4) float - rotation
2529 			// 5) float - shear
2530 			// 6) float - false bold width
2531 			// 7) uint8 - spacing
2532 			// 8) uint32 - flags
2533 			// 9) font_metric_mode - mode
2534 			// 10) int32 numStrings
2535 			// 11) escapement_delta - additional delta (numStrings times)
2536 			// 12) int32 string length to measure (numStrings times)
2537 			// 13) string - string (numStrings times)
2538 
2539 			// Returns:
2540 			// 1) BRect - rects with numStrings entries
2541 
2542 			uint16 familyID, styleID;
2543 			uint32 flags;
2544 			float ptsize, rotation, shear, falseBoldWidth;
2545 			uint8 spacing;
2546 			font_metric_mode mode;
2547 
2548 			link.Read<uint16>(&familyID);
2549 			link.Read<uint16>(&styleID);
2550 			link.Read<float>(&ptsize);
2551 			link.Read<float>(&rotation);
2552 			link.Read<float>(&shear);
2553 			link.Read<float>(&falseBoldWidth);
2554 			link.Read<uint8>(&spacing);
2555 			link.Read<uint32>(&flags);
2556 			link.Read<font_metric_mode>(&mode);
2557 
2558 			int32 numStrings;
2559 			link.Read<int32>(&numStrings);
2560 
2561 			escapement_delta deltaArray[numStrings];
2562 			char* stringArray[numStrings];
2563 			int32 lengthArray[numStrings];
2564 			for(int32 i = 0; i < numStrings; i++) {
2565 				// This version of ReadString allocates the strings, we free
2566 				// them below
2567 				// TODO: this does not work on 64-bit (size_t != int32)
2568 				link.ReadString(&stringArray[i], (size_t*)&lengthArray[i]);
2569 				link.Read<escapement_delta>(&deltaArray[i]);
2570 			}
2571 
2572 			BStackOrHeapArray<BRect, 64> rectArray(numStrings);
2573 
2574 			ServerFont font;
2575 			bool success = false;
2576 			if (font.SetFamilyAndStyle(familyID, styleID) == B_OK) {
2577 				font.SetSize(ptsize);
2578 				font.SetRotation(rotation);
2579 				font.SetShear(shear);
2580 				font.SetFalseBoldWidth(falseBoldWidth);
2581 				font.SetSpacing(spacing);
2582 				font.SetFlags(flags);
2583 
2584 				if (font.GetBoundingBoxesForStrings(stringArray, lengthArray,
2585 					numStrings, rectArray, mode, deltaArray) == B_OK) {
2586 					fLink.StartMessage(B_OK);
2587 					fLink.Attach(rectArray, numStrings * sizeof(BRect));
2588 					success = true;
2589 				}
2590 			}
2591 
2592 			for (int32 i = 0; i < numStrings; i++)
2593 				free(stringArray[i]);
2594 
2595 			if (!success)
2596 				fLink.StartMessage(B_ERROR);
2597 
2598 			fLink.Flush();
2599 			break;
2600 		}
2601 
2602 		// Screen commands
2603 
2604 		case AS_VALID_SCREEN_ID:
2605 		{
2606 			// Attached data
2607 			// 1) int32 screen
2608 
2609 			int32 id;
2610 			if (link.Read<int32>(&id) == B_OK
2611 				&& id == B_MAIN_SCREEN_ID.id)
2612 				fLink.StartMessage(B_OK);
2613 			else
2614 				fLink.StartMessage(B_ERROR);
2615 
2616 			fLink.Flush();
2617 			break;
2618 		}
2619 
2620 		case AS_GET_NEXT_SCREEN_ID:
2621 		{
2622 			// Attached data
2623 			// 1) int32 screen
2624 
2625 			int32 id;
2626 			link.Read<int32>(&id);
2627 
2628 			// TODO: for now, just say we're the last one
2629 			fLink.StartMessage(B_ENTRY_NOT_FOUND);
2630 			fLink.Flush();
2631 			break;
2632 		}
2633 
2634 		case AS_GET_SCREEN_ID_FROM_WINDOW:
2635 		{
2636 			status_t status = B_BAD_VALUE;
2637 
2638 			// Attached data
2639 			// 1) int32 - window client token
2640 
2641 			int32 clientToken;
2642 			if (link.Read<int32>(&clientToken) != B_OK)
2643 				status = B_BAD_DATA;
2644 			else {
2645 				BAutolock locker(fWindowListLock);
2646 
2647 				for (int32 i = fWindowList.CountItems(); i-- > 0;) {
2648 					ServerWindow* serverWindow = fWindowList.ItemAt(i);
2649 
2650 					if (serverWindow->ClientToken() == clientToken) {
2651 						AutoReadLocker _(fDesktop->ScreenLocker());
2652 
2653 						// found it!
2654 						Window* window = serverWindow->Window();
2655 						const Screen* screen = NULL;
2656 						if (window != NULL)
2657 							screen = window->Screen();
2658 
2659 						if (screen == NULL) {
2660 							// The window hasn't been added to the desktop yet,
2661 							// or it's an offscreen window
2662 							break;
2663 						}
2664 
2665 						fLink.StartMessage(B_OK);
2666 						fLink.Attach<int32>(screen->ID());
2667 						status = B_OK;
2668 						break;
2669 					}
2670 				}
2671 			}
2672 
2673 			if (status != B_OK)
2674 				fLink.StartMessage(status);
2675 			fLink.Flush();
2676 			break;
2677 		}
2678 
2679 		case AS_SCREEN_GET_MODE:
2680 		{
2681 			STRACE(("ServerApp %s: AS_SCREEN_GET_MODE\n", Signature()));
2682 
2683 			// Attached data
2684 			// 1) int32 screen
2685 			// 2) uint32 workspace index
2686 
2687 			int32 id;
2688 			link.Read<int32>(&id);
2689 			uint32 workspace;
2690 			link.Read<uint32>(&workspace);
2691 
2692 			display_mode mode;
2693 			status_t status = fDesktop->GetScreenMode(workspace, id, mode);
2694 
2695 			fLink.StartMessage(status);
2696 			if (status == B_OK)
2697 				fLink.Attach<display_mode>(mode);
2698 			fLink.Flush();
2699 			break;
2700 		}
2701 
2702 		case AS_SCREEN_SET_MODE:
2703 		{
2704 			STRACE(("ServerApp %s: AS_SCREEN_SET_MODE\n", Signature()));
2705 
2706 			// Attached data
2707 			// 1) int32 screen
2708 			// 2) workspace index
2709 			// 3) display_mode to set
2710 			// 4) 'makeDefault' boolean
2711 
2712 			int32 id;
2713 			link.Read<int32>(&id);
2714 			uint32 workspace;
2715 			link.Read<uint32>(&workspace);
2716 
2717 			display_mode mode;
2718 			link.Read<display_mode>(&mode);
2719 
2720 			bool makeDefault = false;
2721 			status_t status = link.Read<bool>(&makeDefault);
2722 
2723 			if (status == B_OK) {
2724 				status = fDesktop->SetScreenMode(workspace, id, mode,
2725 					makeDefault);
2726 			}
2727 			if (status == B_OK) {
2728 				if (workspace == (uint32)B_CURRENT_WORKSPACE_INDEX
2729 					&& fDesktop->LockSingleWindow()) {
2730 					workspace = fDesktop->CurrentWorkspace();
2731 					fDesktop->UnlockSingleWindow();
2732 				}
2733 
2734 				if (!makeDefault) {
2735 					// Memorize the screen change, so that it can be reverted
2736 					// later
2737 					fTemporaryDisplayModeChange |= 1 << workspace;
2738 				} else
2739 					fTemporaryDisplayModeChange &= ~(1 << workspace);
2740 			}
2741 
2742 			fLink.StartMessage(status);
2743 			fLink.Flush();
2744 			break;
2745 		}
2746 
2747 		case AS_PROPOSE_MODE:
2748 		{
2749 			STRACE(("ServerApp %s: AS_PROPOSE_MODE\n", Signature()));
2750 			int32 id;
2751 			link.Read<int32>(&id);
2752 
2753 			display_mode target, low, high;
2754 			link.Read<display_mode>(&target);
2755 			link.Read<display_mode>(&low);
2756 			link.Read<display_mode>(&high);
2757 			status_t status = fDesktop->HWInterface()->ProposeMode(&target,
2758 				&low, &high);
2759 
2760 			// ProposeMode() returns B_BAD_VALUE to hint that the candidate is
2761 			// not within the given limits (but is supported)
2762 			if (status == B_OK || status == B_BAD_VALUE) {
2763 				fLink.StartMessage(B_OK);
2764 				fLink.Attach<display_mode>(target);
2765 				fLink.Attach<bool>(status == B_OK);
2766 			} else
2767 				fLink.StartMessage(status);
2768 
2769 			fLink.Flush();
2770 			break;
2771 		}
2772 
2773 		case AS_GET_MODE_LIST:
2774 		{
2775 			int32 id;
2776 			link.Read<int32>(&id);
2777 			// TODO: use this screen id
2778 
2779 			display_mode* modeList;
2780 			uint32 count;
2781 			status_t status = fDesktop->HWInterface()->GetModeList(&modeList,
2782 				&count);
2783 			if (status == B_OK) {
2784 				fLink.StartMessage(B_OK);
2785 				fLink.Attach<uint32>(count);
2786 				fLink.Attach(modeList, sizeof(display_mode) * count);
2787 
2788 				delete[] modeList;
2789 			} else
2790 				fLink.StartMessage(status);
2791 
2792 			fLink.Flush();
2793 			break;
2794 		}
2795 
2796 		case AS_GET_SCREEN_FRAME:
2797 		{
2798 			STRACE(("ServerApp %s: AS_GET_SCREEN_FRAME\n", Signature()));
2799 
2800 			// Attached data
2801 			// 1) int32 screen
2802 			// 2) uint32 workspace index
2803 
2804 			int32 id;
2805 			link.Read<int32>(&id);
2806 			uint32 workspace;
2807 			link.Read<uint32>(&workspace);
2808 
2809 			BRect frame;
2810 			status_t status = fDesktop->GetScreenFrame(workspace, id, frame);
2811 
2812 			fLink.StartMessage(status);
2813 			if (status == B_OK)
2814 				fLink.Attach<BRect>(frame);
2815 
2816 			fLink.Flush();
2817 			break;
2818 		}
2819 
2820 		case AS_SCREEN_GET_COLORMAP:
2821 		{
2822 			STRACE(("ServerApp %s: AS_SCREEN_GET_COLORMAP\n", Signature()));
2823 
2824 			int32 id;
2825 			link.Read<int32>(&id);
2826 
2827 			const color_map* colorMap = SystemColorMap();
2828 			if (colorMap != NULL) {
2829 				fLink.StartMessage(B_OK);
2830 				fLink.Attach<color_map>(*colorMap);
2831 			} else
2832 				fLink.StartMessage(B_ERROR);
2833 
2834 			fLink.Flush();
2835 			break;
2836 		}
2837 
2838 		case AS_GET_DESKTOP_COLOR:
2839 		{
2840 			STRACE(("ServerApp %s: get desktop color\n", Signature()));
2841 
2842 			uint32 index;
2843 			link.Read<uint32>(&index);
2844 
2845 			fLink.StartMessage(B_OK);
2846 			fDesktop->LockSingleWindow();
2847 
2848 			// we're nice to our children (and also take the default case
2849 			// into account which asks for the current workspace)
2850 			if (index >= (uint32)kMaxWorkspaces)
2851 				index = fDesktop->CurrentWorkspace();
2852 
2853 			Workspace workspace(*fDesktop, index, true);
2854 			fLink.Attach<rgb_color>(workspace.Color());
2855 
2856 			fDesktop->UnlockSingleWindow();
2857 			fLink.Flush();
2858 			break;
2859 		}
2860 
2861 		case AS_SET_DESKTOP_COLOR:
2862 		{
2863 			STRACE(("ServerApp %s: set desktop color\n", Signature()));
2864 
2865 			rgb_color color;
2866 			uint32 index;
2867 			bool makeDefault;
2868 
2869 			link.Read<rgb_color>(&color);
2870 			link.Read<uint32>(&index);
2871 			if (link.Read<bool>(&makeDefault) != B_OK)
2872 				break;
2873 
2874 			fDesktop->LockAllWindows();
2875 
2876 			// we're nice to our children (and also take the default case
2877 			// into account which asks for the current workspace)
2878 			if (index >= (uint32)kMaxWorkspaces)
2879 				index = fDesktop->CurrentWorkspace();
2880 
2881 			Workspace workspace(*fDesktop, index);
2882 			workspace.SetColor(color, makeDefault);
2883 
2884 			fDesktop->UnlockAllWindows();
2885 			break;
2886 		}
2887 
2888 		case AS_GET_ACCELERANT_INFO:
2889 		{
2890 			STRACE(("ServerApp %s: get accelerant info\n", Signature()));
2891 
2892 			// We aren't using the screen_id for now...
2893 			int32 id;
2894 			link.Read<int32>(&id);
2895 
2896 			accelerant_device_info accelerantInfo;
2897 			// TODO: I wonder if there should be a "desktop" lock...
2898 			status_t status
2899 				= fDesktop->HWInterface()->GetDeviceInfo(&accelerantInfo);
2900 			if (status == B_OK) {
2901 				fLink.StartMessage(B_OK);
2902 				fLink.Attach<accelerant_device_info>(accelerantInfo);
2903 			} else
2904 				fLink.StartMessage(status);
2905 
2906 			fLink.Flush();
2907 			break;
2908 		}
2909 
2910 		case AS_GET_MONITOR_INFO:
2911 		{
2912 			STRACE(("ServerApp %s: get monitor info\n", Signature()));
2913 
2914 			// We aren't using the screen_id for now...
2915 			int32 id;
2916 			link.Read<int32>(&id);
2917 
2918 			monitor_info info;
2919 			// TODO: I wonder if there should be a "desktop" lock...
2920 			status_t status = fDesktop->HWInterface()->GetMonitorInfo(&info);
2921 			if (status == B_OK) {
2922 				fLink.StartMessage(B_OK);
2923 				fLink.Attach<monitor_info>(info);
2924 			} else
2925 				fLink.StartMessage(status);
2926 
2927 			fLink.Flush();
2928 			break;
2929 		}
2930 
2931 		case AS_GET_FRAME_BUFFER_CONFIG:
2932 		{
2933 			STRACE(("ServerApp %s: get frame buffer config\n", Signature()));
2934 
2935 			// We aren't using the screen_id for now...
2936 			int32 id;
2937 			link.Read<int32>(&id);
2938 
2939 			frame_buffer_config config;
2940 			// TODO: I wonder if there should be a "desktop" lock...
2941 			status_t status = fDesktop->HWInterface()->GetFrameBufferConfig(config);
2942 			if (status == B_OK) {
2943 				fLink.StartMessage(B_OK);
2944 				fLink.Attach<frame_buffer_config>(config);
2945 			} else
2946 				fLink.StartMessage(status);
2947 
2948 			fLink.Flush();
2949 			break;
2950 		}
2951 
2952 		case AS_GET_RETRACE_SEMAPHORE:
2953 		{
2954 			STRACE(("ServerApp %s: get retrace semaphore\n", Signature()));
2955 
2956 			// We aren't using the screen_id for now...
2957 			int32 id;
2958 			link.Read<int32>(&id);
2959 
2960 			fLink.StartMessage(B_OK);
2961 			fLink.Attach<sem_id>(fDesktop->HWInterface()->RetraceSemaphore());
2962 			fLink.Flush();
2963 			break;
2964 		}
2965 
2966 		case AS_GET_TIMING_CONSTRAINTS:
2967 		{
2968 			STRACE(("ServerApp %s: get timing constraints\n", Signature()));
2969 
2970 			// We aren't using the screen_id for now...
2971 			int32 id;
2972 			link.Read<int32>(&id);
2973 
2974 			display_timing_constraints constraints;
2975 			status_t status = fDesktop->HWInterface()->GetTimingConstraints(
2976 				&constraints);
2977 			if (status == B_OK) {
2978 				fLink.StartMessage(B_OK);
2979 				fLink.Attach<display_timing_constraints>(constraints);
2980 			} else
2981 				fLink.StartMessage(status);
2982 
2983 			fLink.Flush();
2984 			break;
2985 		}
2986 
2987 		case AS_GET_PIXEL_CLOCK_LIMITS:
2988 		{
2989 			STRACE(("ServerApp %s: get pixel clock limits\n", Signature()));
2990 			// We aren't using the screen_id for now...
2991 			int32 id;
2992 			link.Read<int32>(&id);
2993 			display_mode mode;
2994 			link.Read<display_mode>(&mode);
2995 
2996 			uint32 low, high;
2997 			status_t status = fDesktop->HWInterface()->GetPixelClockLimits(&mode,
2998 				&low, &high);
2999 			if (status == B_OK) {
3000 				fLink.StartMessage(B_OK);
3001 				fLink.Attach<uint32>(low);
3002 				fLink.Attach<uint32>(high);
3003 			} else
3004 				fLink.StartMessage(status);
3005 
3006 			fLink.Flush();
3007 			break;
3008 		}
3009 
3010 		case AS_SET_DPMS:
3011 		{
3012 			STRACE(("ServerApp %s: AS_SET_DPMS\n", Signature()));
3013 			int32 id;
3014 			link.Read<int32>(&id);
3015 
3016 			uint32 mode;
3017 			link.Read<uint32>(&mode);
3018 
3019 			status_t status = fDesktop->HWInterface()->SetDPMSMode(mode);
3020 			fLink.StartMessage(status);
3021 
3022 			fLink.Flush();
3023 			break;
3024 		}
3025 
3026 		case AS_GET_DPMS_STATE:
3027 		{
3028 			STRACE(("ServerApp %s: AS_GET_DPMS_STATE\n", Signature()));
3029 
3030 			int32 id;
3031 			link.Read<int32>(&id);
3032 
3033 			uint32 state = fDesktop->HWInterface()->DPMSMode();
3034 			fLink.StartMessage(B_OK);
3035 			fLink.Attach<uint32>(state);
3036 			fLink.Flush();
3037 			break;
3038 		}
3039 
3040 		case AS_GET_DPMS_CAPABILITIES:
3041 		{
3042 			STRACE(("ServerApp %s: AS_GET_DPMS_CAPABILITIES\n", Signature()));
3043 			int32 id;
3044 			link.Read<int32>(&id);
3045 
3046 			uint32 capabilities = fDesktop->HWInterface()->DPMSCapabilities();
3047 			fLink.StartMessage(B_OK);
3048 			fLink.Attach<uint32>(capabilities);
3049 			fLink.Flush();
3050 			break;
3051 		}
3052 
3053 		case AS_SCREEN_SET_BRIGHTNESS:
3054 		{
3055 			STRACE(("ServerApp %s: AS_SCREEN_SET_BRIGHTNESS\n", Signature()));
3056 			int32 id;
3057 			link.Read<int32>(&id);
3058 
3059 			float brightness;
3060 			link.Read<float>(&brightness);
3061 
3062 			status_t status = fDesktop->HWInterface()->SetBrightness(brightness);
3063 			fLink.StartMessage(status);
3064 
3065 			fLink.Flush();
3066 			break;
3067 		}
3068 
3069 		case AS_SCREEN_GET_BRIGHTNESS:
3070 		{
3071 			STRACE(("ServerApp %s: AS_SCREEN_GET_BRIGHTNESS\n", Signature()));
3072 			int32 id;
3073 			link.Read<int32>(&id);
3074 
3075 			float brightness;
3076 			status_t result = fDesktop->HWInterface()->GetBrightness(&brightness);
3077 			fLink.StartMessage(result);
3078 			if (result == B_OK)
3079 				fLink.Attach<float>(brightness);
3080 			fLink.Flush();
3081 			break;
3082 		}
3083 
3084 		case AS_READ_BITMAP:
3085 		{
3086 			STRACE(("ServerApp %s: AS_READ_BITMAP\n", Signature()));
3087 			int32 token;
3088 			link.Read<int32>(&token);
3089 
3090 			bool drawCursor = true;
3091 			link.Read<bool>(&drawCursor);
3092 
3093 			BRect bounds;
3094 			link.Read<BRect>(&bounds);
3095 
3096 			bool success = false;
3097 
3098 			ServerBitmap* bitmap = GetBitmap(token);
3099 			if (bitmap != NULL) {
3100 				if (fDesktop->GetDrawingEngine()->LockExclusiveAccess()) {
3101 					success = fDesktop->GetDrawingEngine()->ReadBitmap(bitmap,
3102 						drawCursor, bounds) == B_OK;
3103 					fDesktop->GetDrawingEngine()->UnlockExclusiveAccess();
3104 				}
3105 				bitmap->ReleaseReference();
3106 			}
3107 
3108 			if (success)
3109 				fLink.StartMessage(B_OK);
3110 			else
3111 				fLink.StartMessage(B_BAD_VALUE);
3112 
3113 			fLink.Flush();
3114 			break;
3115 		}
3116 
3117 		case AS_GET_ACCELERANT_PATH:
3118 		{
3119 			int32 id;
3120 			fLink.Read<int32>(&id);
3121 
3122 			BString path;
3123 			status_t status = fDesktop->HWInterface()->GetAccelerantPath(path);
3124 			fLink.StartMessage(status);
3125 			if (status == B_OK)
3126 				fLink.AttachString(path.String());
3127 
3128 			fLink.Flush();
3129 			break;
3130 		}
3131 
3132 		case AS_GET_DRIVER_PATH:
3133 		{
3134 			int32 id;
3135 			fLink.Read<int32>(&id);
3136 
3137 			BString path;
3138 			status_t status = fDesktop->HWInterface()->GetDriverPath(path);
3139 			fLink.StartMessage(status);
3140 			if (status == B_OK)
3141 				fLink.AttachString(path.String());
3142 
3143 			fLink.Flush();
3144 			break;
3145 		}
3146 
3147 		// BWindowScreen communication
3148 
3149 		case AS_DIRECT_SCREEN_LOCK:
3150 		{
3151 			bool lock;
3152 			link.Read<bool>(&lock);
3153 
3154 			status_t status;
3155 			if (lock)
3156 				status = fDesktop->LockDirectScreen(ClientTeam());
3157 			else
3158 				status = fDesktop->UnlockDirectScreen(ClientTeam());
3159 
3160 			fLink.StartMessage(status);
3161 			fLink.Flush();
3162 			break;
3163 		}
3164 
3165 		// Hinting and aliasing
3166 
3167 		case AS_SET_SUBPIXEL_ANTIALIASING:
3168 		{
3169 			bool subpix;
3170 			if (link.Read<bool>(&subpix) == B_OK) {
3171 				LockedDesktopSettings settings(fDesktop);
3172 				settings.SetSubpixelAntialiasing(subpix);
3173 			}
3174 			fDesktop->Redraw();
3175 			break;
3176 		}
3177 
3178 		case AS_GET_SUBPIXEL_ANTIALIASING:
3179 		{
3180 			DesktopSettings settings(fDesktop);
3181 			fLink.StartMessage(B_OK);
3182 			fLink.Attach<bool>(settings.SubpixelAntialiasing());
3183 			fLink.Flush();
3184 			break;
3185 		}
3186 
3187 		case AS_SET_HINTING:
3188 		{
3189 			uint8 hinting;
3190 			if (link.Read<uint8>(&hinting) == B_OK && hinting < 3) {
3191 				LockedDesktopSettings settings(fDesktop);
3192 				if (hinting != settings.Hinting()) {
3193 					settings.SetHinting(hinting);
3194 					fDesktop->Redraw();
3195 				}
3196 			}
3197 			break;
3198 		}
3199 
3200 		case AS_GET_HINTING:
3201 		{
3202 			DesktopSettings settings(fDesktop);
3203 			fLink.StartMessage(B_OK);
3204 			fLink.Attach<uint8>(settings.Hinting());
3205 			fLink.Flush();
3206 			break;
3207 		}
3208 
3209 		case AS_SET_SUBPIXEL_AVERAGE_WEIGHT:
3210 		{
3211 			uint8 averageWeight;
3212 			if (link.Read<uint8>(&averageWeight) == B_OK) {
3213 				LockedDesktopSettings settings(fDesktop);
3214 				settings.SetSubpixelAverageWeight(averageWeight);
3215 			}
3216 			fDesktop->Redraw();
3217 			break;
3218 		}
3219 
3220 		case AS_GET_SUBPIXEL_AVERAGE_WEIGHT:
3221 		{
3222 			DesktopSettings settings(fDesktop);
3223 			fLink.StartMessage(B_OK);
3224 			fLink.Attach<uint8>(settings.SubpixelAverageWeight());
3225 			fLink.Flush();
3226 			break;
3227 		}
3228 
3229 		case AS_SET_SUBPIXEL_ORDERING:
3230 		{
3231 			bool subpixelOrdering;
3232 			if (link.Read<bool>(&subpixelOrdering) == B_OK) {
3233 				LockedDesktopSettings settings(fDesktop);
3234 				settings.SetSubpixelOrderingRegular(subpixelOrdering);
3235 			}
3236 			fDesktop->Redraw();
3237 			break;
3238 		}
3239 
3240 		case AS_GET_SUBPIXEL_ORDERING:
3241 		{
3242 			DesktopSettings settings(fDesktop);
3243 			fLink.StartMessage(B_OK);
3244 			fLink.Attach<bool>(settings.IsSubpixelOrderingRegular());
3245 			fLink.Flush();
3246 			break;
3247 		}
3248 
3249 		default:
3250 			printf("ServerApp %s received unhandled message code %" B_PRId32
3251 				"\n", Signature(), code);
3252 
3253 			if (link.NeedsReply()) {
3254 				// the client is now blocking and waiting for a reply!
3255 				fLink.StartMessage(B_ERROR);
3256 				fLink.Flush();
3257 			} else
3258 				puts("message doesn't need a reply!");
3259 			break;
3260 	}
3261 }
3262 
3263 
3264 /*!	\brief The thread function ServerApps use to monitor messages
3265 */
3266 void
3267 ServerApp::_MessageLooper()
3268 {
3269 	// Message-dispatching loop for the ServerApp
3270 
3271 	// get our own team ID
3272 	thread_info threadInfo;
3273 	get_thread_info(fThread, &threadInfo);
3274 
3275 	// First let's tell the client how to talk with us.
3276 	fLink.StartMessage(B_OK);
3277 	fLink.Attach<port_id>(fMessagePort);
3278 	fLink.Attach<area_id>(fDesktop->SharedReadOnlyArea());
3279 	fLink.Attach<team_id>(threadInfo.team);
3280 	fLink.Flush();
3281 
3282 	BPrivate::LinkReceiver &receiver = fLink.Receiver();
3283 
3284 	int32 code;
3285 	status_t err = B_OK;
3286 
3287 	while (!fQuitting) {
3288 		STRACE(("info: ServerApp::_MessageLooper() listening on port %" B_PRId32
3289 			".\n", fMessagePort));
3290 
3291 		err = receiver.GetNextMessage(code);
3292 		if (err != B_OK || code == B_QUIT_REQUESTED) {
3293 			STRACE(("ServerApp: application seems to be gone...\n"));
3294 
3295 			// Tell desktop to quit us
3296 			BPrivate::LinkSender link(fDesktop->MessagePort());
3297 			link.StartMessage(AS_DELETE_APP);
3298 			link.Attach<thread_id>(Thread());
3299 			link.Flush();
3300 			break;
3301 		}
3302 
3303 		switch (code) {
3304 			case kMsgAppQuit:
3305 				// we receive this from our destructor on quit
3306 				fQuitting = true;
3307 				break;
3308 
3309 			case AS_QUIT_APP:
3310 			{
3311 				// This message is received only when the app_server is asked
3312 				// to shut down in test/debug mode. Of course, if we are testing
3313 				// while using AccelerantDriver, we do NOT want to shut down
3314 				// client applications. The server can be quit in this fashion
3315 				// through the driver's interface, such as closing the
3316 				// ViewDriver's window.
3317 
3318 				STRACE(("ServerApp %s:Server shutdown notification received\n",
3319 					Signature()));
3320 
3321 				// If we are using the real, accelerated version of the
3322 				// DrawingEngine, we do NOT want the user to be able shut down
3323 				// the server. The results would NOT be pretty
3324 #if TEST_MODE
3325 				BMessage pleaseQuit(B_QUIT_REQUESTED);
3326 				SendMessageToClient(&pleaseQuit);
3327 #endif
3328 				break;
3329 			}
3330 
3331 			default:
3332 				STRACE(("ServerApp %s: Got a Message to dispatch\n",
3333 					Signature()));
3334 				_DispatchMessage(code, receiver);
3335 				break;
3336 		}
3337 	}
3338 
3339 	// Quit() will send us a message; we're handling the exiting procedure
3340 	thread_id sender;
3341 	sem_id shutdownSemaphore;
3342 	receive_data(&sender, &shutdownSemaphore, sizeof(sem_id));
3343 
3344 	delete this;
3345 
3346 	if (shutdownSemaphore >= B_OK)
3347 		release_sem(shutdownSemaphore);
3348 }
3349 
3350 
3351 status_t
3352 ServerApp::_CreateWindow(int32 code, BPrivate::LinkReceiver& link,
3353 	port_id& clientReplyPort)
3354 {
3355 	// Attached data:
3356 	// 1) int32 bitmap token (only for AS_CREATE_OFFSCREEN_WINDOW)
3357 	// 2) BRect window frame
3358 	// 3) uint32 window look
3359 	// 4) uint32 window feel
3360 	// 5) uint32 window flags
3361 	// 6) uint32 workspace index
3362 	// 7) int32 BHandler token of the window
3363 	// 8) port_id window's reply port
3364 	// 9) port_id window's looper port
3365 	// 10) const char * title
3366 
3367 	BRect frame;
3368 	int32 bitmapToken;
3369 	uint32 look;
3370 	uint32 feel;
3371 	uint32 flags;
3372 	uint32 workspaces;
3373 	int32 token;
3374 	port_id looperPort;
3375 	char* title;
3376 
3377 	if (code == AS_CREATE_OFFSCREEN_WINDOW)
3378 		link.Read<int32>(&bitmapToken);
3379 
3380 	link.Read<BRect>(&frame);
3381 	link.Read<uint32>(&look);
3382 	link.Read<uint32>(&feel);
3383 	link.Read<uint32>(&flags);
3384 	link.Read<uint32>(&workspaces);
3385 	link.Read<int32>(&token);
3386 	link.Read<port_id>(&clientReplyPort);
3387 	link.Read<port_id>(&looperPort);
3388 	if (link.ReadString(&title) != B_OK)
3389 		return B_ERROR;
3390 
3391 	if (!frame.IsValid()) {
3392 		// make sure we pass a valid rectangle to ServerWindow
3393 		frame.right = frame.left + 1;
3394 		frame.bottom = frame.top + 1;
3395 	}
3396 
3397 	status_t status = B_NO_MEMORY;
3398 	ServerWindow *window = NULL;
3399 
3400 	if (code == AS_CREATE_OFFSCREEN_WINDOW) {
3401 		ServerBitmap* bitmap = GetBitmap(bitmapToken);
3402 
3403 		if (bitmap != NULL) {
3404 			window = new (nothrow) OffscreenServerWindow(title, this,
3405 				clientReplyPort, looperPort, token, bitmap);
3406 		} else
3407 			status = B_ERROR;
3408 	} else {
3409 		window = new (nothrow) ServerWindow(title, this, clientReplyPort,
3410 			looperPort, token);
3411 		STRACE(("\nServerApp %s: New Window %s (%g:%g, %g:%g)\n",
3412 			Signature(), title, frame.left, frame.top,
3413 			frame.right, frame.bottom));
3414 	}
3415 
3416 	free(title);
3417 
3418 	// NOTE: the reply to the client is handled in ServerWindow::Run()
3419 	if (window != NULL) {
3420 		status = window->Init(frame, (window_look)look, (window_feel)feel,
3421 			flags, workspaces);
3422 		if (status == B_OK) {
3423 			status = window->Run();
3424 			if (status != B_OK) {
3425 				syslog(LOG_ERR, "ServerApp::_CreateWindow() - failed to run "
3426 					"the window thread\n");
3427 			}
3428 		}
3429 
3430 		if (status != B_OK)
3431 			delete window;
3432 	}
3433 
3434 	return status;
3435 }
3436 
3437 
3438 bool
3439 ServerApp::_HasWindowUnderMouse()
3440 {
3441 	BAutolock locker(fWindowListLock);
3442 
3443 	for (int32 i = fWindowList.CountItems(); i-- > 0;) {
3444 		ServerWindow* serverWindow = fWindowList.ItemAt(i);
3445 
3446 		if (fDesktop->ViewUnderMouse(serverWindow->Window()) != B_NULL_TOKEN)
3447 			return true;
3448 	}
3449 
3450 	return false;
3451 }
3452 
3453 
3454 bool
3455 ServerApp::_AddBitmap(ServerBitmap* bitmap)
3456 {
3457 	BAutolock _(fMapLocker);
3458 
3459 	try {
3460 		fBitmapMap.insert(std::make_pair(bitmap->Token(), bitmap));
3461 	} catch (std::bad_alloc& exception) {
3462 		return false;
3463 	}
3464 
3465 	bitmap->SetOwner(this);
3466 	return true;
3467 }
3468 
3469 
3470 void
3471 ServerApp::_DeleteBitmap(ServerBitmap* bitmap)
3472 {
3473 	ASSERT(fMapLocker.IsLocked());
3474 
3475 	gBitmapManager->BitmapRemoved(bitmap);
3476 	fBitmapMap.erase(bitmap->Token());
3477 
3478 	bitmap->ReleaseReference();
3479 }
3480 
3481 
3482 ServerBitmap*
3483 ServerApp::_FindBitmap(int32 token) const
3484 {
3485 	ASSERT(fMapLocker.IsLocked());
3486 
3487 	BitmapMap::const_iterator iterator = fBitmapMap.find(token);
3488 	if (iterator == fBitmapMap.end())
3489 		return NULL;
3490 
3491 	return iterator->second;
3492 }
3493 
3494 
3495 ServerPicture*
3496 ServerApp::_FindPicture(int32 token) const
3497 {
3498 	ASSERT(fMapLocker.IsLocked());
3499 
3500 	PictureMap::const_iterator iterator = fPictureMap.find(token);
3501 	if (iterator == fPictureMap.end())
3502 		return NULL;
3503 
3504 	return iterator->second;
3505 }
3506