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