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