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