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