/*
 * Copyright 2001-2019, Haiku.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		DarkWyrm <bpmagic@columbus.rr.com>
 *		Adrian Oanca <adioanca@gmail.com>
 *		Stephan Aßmus <superstippi@gmx.de>
 *		Stefano Ceccherini <stefano.ceccherini@gmail.com>
 *		Axel Dörfler <axeld@pinc-software.de>
 *		Artur Wyszynski <harakash@gmail.com>
 *		Philippe Saint-Pierre <stpere@gmail.com>
 *		Brecht Machiels <brecht@mos6581.org>
 *		Julian Harnath <julian.harnath@rwth-aachen.de>
 *		Joseph Groover <looncraz@looncraz.net>
 */
 
 
/*!	\class ServerWindow
 
	The ServerWindow class handles all BWindow messaging; it forwards all
	BWindow requests to the corresponding app_server classes, that is Desktop,
	Window, and View.
	Furthermore, it also sends app_server requests/notices to its BWindow. There
	is one ServerWindow per BWindow.
*/
 
 
#include "ServerWindow.h"
 
#include <syslog.h>
#include <new>
 
#include <AppDefs.h>
#include <Autolock.h>
#include <Debug.h>
#include <DirectWindow.h>
#include <TokenSpace.h>
#include <View.h>
#include <GradientLinear.h>
#include <GradientRadial.h>
#include <GradientRadialFocus.h>
#include <GradientDiamond.h>
#include <GradientConic.h>
 
#include <MessagePrivate.h>
#include <PortLink.h>
#include <ShapePrivate.h>
#include <ServerProtocolStructs.h>
#include <ViewPrivate.h>
#include <WindowInfo.h>
#include <WindowPrivate.h>
 
#include "clipping.h"
#include "utf8_functions.h"
 
#include "AlphaMask.h"
#include "AppServer.h"
#include "AutoDeleter.h"
#include "BBitmapBuffer.h"
#include "BitmapManager.h"
#include "Desktop.h"
#include "DirectWindowInfo.h"
#include "DrawingEngine.h"
#include "DrawState.h"
#include "HWInterface.h"
#include "Layer.h"
#include "Overlay.h"
#include "ProfileMessageSupport.h"
#include "RenderingBuffer.h"
#include "ServerApp.h"
#include "ServerBitmap.h"
#include "ServerPicture.h"
#include "ServerProtocol.h"
#include "Window.h"
#include "WorkspacesView.h"
 
 
using std::nothrow;
 
 
//#define TRACE_SERVER_WINDOW
#ifdef TRACE_SERVER_WINDOW
#	include <stdio.h>
#	define STRACE(x) debug_printf x
#else
#	define STRACE(x) ;
#endif
 
//#define TRACE_SERVER_WINDOW_MESSAGES
#ifdef TRACE_SERVER_WINDOW_MESSAGES
#	include <stdio.h>
static const char* kDrawingModeMap[] = {
	"B_OP_COPY",
	"B_OP_OVER",
	"B_OP_ERASE",
	"B_OP_INVERT",
	"B_OP_ADD",
	"B_OP_SUBTRACT",
	"B_OP_BLEND",
	"B_OP_MIN",
	"B_OP_MAX",
	"B_OP_SELECT",
	"B_OP_ALPHA",
 
	"fix kDrawingModeMap",
	"fix kDrawingModeMap",
	"fix kDrawingModeMap",
	"fix kDrawingModeMap",
	"fix kDrawingModeMap",
};
#	define DTRACE(x) debug_printf x
#else
#	define DTRACE(x) ;
#endif
 
//#define TRACE_SERVER_GRADIENTS
#ifdef TRACE_SERVER_GRADIENTS
#	include <OS.h>
#	define GTRACE(x) debug_printf x
#else
#	define GTRACE(x) ;
#endif
 
//#define PROFILE_MESSAGE_LOOP
#ifdef PROFILE_MESSAGE_LOOP
struct profile { int32 code; int32 count; bigtime_t time; };
static profile sMessageProfile[AS_LAST_CODE];
static profile sRedrawProcessingTime;
//static profile sNextMessageTime;
#endif
 
 
//	#pragma mark -
 
 
#ifdef PROFILE_MESSAGE_LOOP
static int
compare_message_profiles(const void* _a, const void* _b)
{
	profile* a = (profile*)*(void**)_a;
	profile* b = (profile*)*(void**)_b;
	if (a->time < b->time)
		return 1;
	if (a->time > b->time)
		return -1;
	return 0;
}
#endif
 
 
//	#pragma mark -
 
 
/*!	Sets up the basic BWindow counterpart - you have to call Init() before
	you can actually use it, though.
*/
ServerWindow::ServerWindow(const char* title, ServerApp* app,
		port_id clientPort, port_id looperPort, int32 clientToken)
	:
	MessageLooper(title && *title ? title : "Unnamed Window"),
	fTitle(NULL),
	fDesktop(app->GetDesktop()),
	fServerApp(app),
	fWindow(NULL),
	fWindowAddedToDesktop(false),
 
	fClientTeam(app->ClientTeam()),
 
	fMessagePort(-1),
	fClientReplyPort(clientPort),
	fClientLooperPort(looperPort),
 
	fClientToken(clientToken),
 
	fCurrentView(NULL),
	fCurrentDrawingRegion(),
	fCurrentDrawingRegionValid(false),
 
	fDirectWindowInfo(NULL),
	fIsDirectlyAccessing(false)
{
	STRACE(("ServerWindow(%s)::ServerWindow()\n", title));
 
	SetTitle(title);
	fServerToken = BPrivate::gDefaultTokens.NewToken(B_SERVER_TOKEN, this);
 
	BMessenger::Private(fFocusMessenger).SetTo(fClientTeam,
		looperPort, B_PREFERRED_TOKEN);
	BMessenger::Private(fHandlerMessenger).SetTo(fClientTeam,
		looperPort, clientToken);
 
	fEventTarget.SetTo(fFocusMessenger);
 
	fDeathSemaphore = create_sem(0, "window death");
}
 
 
/*! Tears down all connections the main app_server objects, and deletes some
	internals.
*/
ServerWindow::~ServerWindow()
{
	STRACE(("ServerWindow(%s@%p):~ServerWindow()\n", fTitle, this));
 
	if (!fWindow->IsOffscreenWindow()) {
		fWindowAddedToDesktop = false;
		fDesktop->RemoveWindow(fWindow);
	}
 
	if (App() != NULL) {
		App()->RemoveWindow(this);
		fServerApp = NULL;
	}
 
	delete fWindow;
 
	free(fTitle);
	delete_port(fMessagePort);
 
	BPrivate::gDefaultTokens.RemoveToken(fServerToken);
 
	delete fDirectWindowInfo;
	STRACE(("ServerWindow(%p) will exit NOW\n", this));
 
	delete_sem(fDeathSemaphore);
 
#ifdef PROFILE_MESSAGE_LOOP
	BList profiles;
	for (int32 i = 0; i < AS_LAST_CODE; i++) {
		if (sMessageProfile[i].count == 0)
			continue;
		sMessageProfile[i].code = i;
		profiles.AddItem(&sMessageProfile[i]);
	}
 
	profiles.SortItems(compare_message_profiles);
 
	BString codeName;
	int32 count = profiles.CountItems();
	for (int32 i = 0; i < count; i++) {
		profile* p = (profile*)profiles.ItemAtFast(i);
		string_for_message_code(p->code, codeName);
		printf("[%s] called %" B_PRId32 " times, %g secs (%" B_PRId64 " usecs "
			"per call)\n", codeName.String(), p->count, p->time / 1000000.0,
			p->time / p->count);
	}
	if (sRedrawProcessingTime.count > 0) {
		printf("average redraw processing time: %g secs, count: %" B_PRId32 " "
			"(%" B_PRId64 " usecs per call)\n",
			sRedrawProcessingTime.time / 1000000.0, sRedrawProcessingTime.count,
			sRedrawProcessingTime.time / sRedrawProcessingTime.count);
	}
//	if (sNextMessageTime.count > 0) {
//		printf("average NextMessage() time: %g secs, count: %ld (%lld usecs per call)\n",
//			sNextMessageTime.time / 1000000.0, sNextMessageTime.count,
//			sNextMessageTime.time / sNextMessageTime.count);
//	}
#endif
}
 
 
status_t
ServerWindow::Init(BRect frame, window_look look, window_feel feel,
	uint32 flags, uint32 workspace)
{
	if (!App()->AddWindow(this)) {
		fServerApp = NULL;
		return B_NO_MEMORY;
	}
 
	if (fTitle == NULL)
		return B_NO_MEMORY;
 
	// fMessagePort is the port to which the app sends messages for the server
	fMessagePort = create_port(100, fTitle);
	if (fMessagePort < B_OK)
		return fMessagePort;
 
	fLink.SetSenderPort(fClientReplyPort);
	fLink.SetReceiverPort(fMessagePort);
 
	// We cannot call MakeWindow in the constructor, since it
	// is a virtual function!
	fWindow = MakeWindow(frame, fTitle, look, feel, flags, workspace);
	if (!fWindow || fWindow->InitCheck() != B_OK) {
		delete fWindow;
		fWindow = NULL;
		return B_NO_MEMORY;
	}
 
	if (!fWindow->IsOffscreenWindow()) {
		fDesktop->AddWindow(fWindow);
		fWindowAddedToDesktop = true;
	}
 
	return B_OK;
}
 
 
/*!	Returns the ServerWindow's Window, if it exists and has been
	added to the Desktop already.
	In other words, you cannot assume this method will always give you
	a valid pointer.
*/
Window*
ServerWindow::Window() const
{
	if (!fWindowAddedToDesktop)
		return NULL;
 
	return fWindow;
}
 
 
void
ServerWindow::_PrepareQuit()
{
	if (fThread == find_thread(NULL)) {
		// make sure we're hidden
		fDesktop->LockSingleWindow();
		_Hide();
		fDesktop->UnlockSingleWindow();
	} else if (fThread >= B_OK)
		PostMessage(AS_INTERNAL_HIDE_WINDOW);
}
 
 
void
ServerWindow::_GetLooperName(char* name, size_t length)
{
	const char *title = Title();
	if (title == NULL || !title[0])
		title = "Unnamed Window";
 
	snprintf(name, length, "w:%" B_PRId32 ":%s", ClientTeam(), title);
}
 
 
/*! Shows the window's Window.
*/
void
ServerWindow::_Show()
{
	// NOTE: if you do something else, other than sending a port message, PLEASE lock
	STRACE(("ServerWindow %s: _Show\n", Title()));
 
	if (fQuitting || fWindow->IsMinimized() || !fWindow->IsHidden()
		|| fWindow->IsOffscreenWindow() || fWindow->TopView() == NULL)
		return;
 
	// TODO: Maybe we need to dispatch a message to the desktop to show/hide us
	// instead of doing it from this thread.
	fDesktop->UnlockSingleWindow();
	fDesktop->ShowWindow(fWindow);
	if (fDirectWindowInfo && fDirectWindowInfo->IsFullScreen())
		_ResizeToFullScreen();
 
	fDesktop->LockSingleWindow();
}
 
 
/*! Hides the window's Window. You need to have all windows locked when
	calling this function.
*/
void
ServerWindow::_Hide()
{
	STRACE(("ServerWindow %s: _Hide\n", Title()));
 
	if (fWindow->IsHidden() || fWindow->IsOffscreenWindow())
		return;
 
	fDesktop->UnlockSingleWindow();
	fDesktop->HideWindow(fWindow);
	fDesktop->LockSingleWindow();
}
 
 
void
ServerWindow::RequestRedraw()
{
	PostMessage(AS_REDRAW, 0);
		// we don't care if this fails - it's only a notification, and if
		// it fails, there are obviously enough messages in the queue
		// already
 
	atomic_add(&fRedrawRequested, 1);
}
 
 
void
ServerWindow::SetTitle(const char* newTitle)
{
	char* oldTitle = fTitle;
 
	if (newTitle == NULL)
		newTitle = "";
 
	fTitle = strdup(newTitle);
	if (fTitle == NULL) {
		// out of memory condition
		fTitle = oldTitle;
		return;
	}
 
	free(oldTitle);
 
	if (Thread() >= B_OK) {
		char name[B_OS_NAME_LENGTH];
		_GetLooperName(name, sizeof(name));
		rename_thread(Thread(), name);
	}
 
	if (fWindow != NULL)
		fDesktop->SetWindowTitle(fWindow, newTitle);
}
 
 
//! Requests that the ServerWindow's BWindow quit
void
ServerWindow::NotifyQuitRequested()
{
	// NOTE: if you do something else, other than sending a port message,
	// PLEASE lock
	STRACE(("ServerWindow %s: Quit\n", fTitle));
 
	BMessage msg(B_QUIT_REQUESTED);
	SendMessageToClient(&msg);
}
 
 
void
ServerWindow::NotifyMinimize(bool minimize)
{
	if (fWindow->Feel() != B_NORMAL_WINDOW_FEEL)
		return;
 
	// The client is responsible for the actual minimization
 
	BMessage msg(B_MINIMIZE);
	msg.AddInt64("when", real_time_clock_usecs());
	msg.AddBool("minimize", minimize);
 
	SendMessageToClient(&msg);
}
 
 
//! Sends a message to the client to perform a Zoom
void
ServerWindow::NotifyZoom()
{
	// NOTE: if you do something else, other than sending a port message,
	// PLEASE lock
	BMessage msg(B_ZOOM);
	SendMessageToClient(&msg);
}
 
 
void
ServerWindow::GetInfo(window_info& info)
{
	info.team = ClientTeam();
	info.server_token = ServerToken();
 
	info.thread = Thread();
	info.client_token = ClientToken();
	info.client_port = fClientLooperPort;
	info.workspaces = fWindow->Workspaces();
 
	// logic taken from Switcher comments and experiments
	if (fWindow->IsHidden())
		info.layer = 0;
	else if (fWindow->IsVisible()) {
		if (fWindow->Feel() == kDesktopWindowFeel)
			info.layer = 2;
		else if (fWindow->IsFloating() || fWindow->IsModal())
			info.layer = 4;
		else
			info.layer = 3;
	} else
		info.layer = 1;
 
	info.feel = fWindow->Feel();
	info.flags = fWindow->Flags();
	info.window_left = (int)floor(fWindow->Frame().left);
	info.window_top = (int)floor(fWindow->Frame().top);
	info.window_right = (int)floor(fWindow->Frame().right);
	info.window_bottom = (int)floor(fWindow->Frame().bottom);
 
	info.show_hide_level = fWindow->ShowLevel();
	info.is_mini = fWindow->IsMinimized();
}
 
 
void
ServerWindow::ResyncDrawState()
{
	_UpdateDrawState(fCurrentView);
}
 
 
View*
ServerWindow::_CreateView(BPrivate::LinkReceiver& link, View** _parent)
{
	// NOTE: no need to check for a lock. This is a private method.
 
	int32 token;
	BRect frame;
	uint32 resizeMask;
	uint32 eventMask;
	uint32 eventOptions;
	uint32 flags;
	bool hidden;
	int32 parentToken;
	char* name = NULL;
	rgb_color viewColor;
	BPoint scrollingOffset;
 
	link.Read<int32>(&token);
	link.ReadString(&name);
	link.Read<BRect>(&frame);
	link.Read<BPoint>(&scrollingOffset);
	link.Read<uint32>(&resizeMask);
	link.Read<uint32>(&eventMask);
	link.Read<uint32>(&eventOptions);
	link.Read<uint32>(&flags);
	link.Read<bool>(&hidden);
	link.Read<rgb_color>(&viewColor);
	link.Read<int32>(&parentToken);
 
	STRACE(("ServerWindow(%s)::_CreateView()-> view %s, token %" B_PRId32 "\n",
		fTitle, name, token));
 
	View* newView;
 
	if ((flags & kWorkspacesViewFlag) != 0) {
		newView = new (nothrow) WorkspacesView(frame, scrollingOffset, name,
			token, resizeMask, flags);
	} else {
		newView = new (nothrow) View(frame, scrollingOffset, name, token,
			resizeMask, flags);
	}
 
	free(name);
 
	if (newView == NULL)
		return NULL;
 
	if (newView->InitCheck() != B_OK) {
		delete newView;
		return NULL;
	}
 
	// there is no way of setting this, other than manually :-)
	newView->SetViewColor(viewColor);
	newView->SetHidden(hidden);
	newView->SetEventMask(eventMask, eventOptions);
 
	if (eventMask != 0 || eventOptions != 0) {
//		fDesktop->UnlockSingleWindow();
//		fDesktop->LockAllWindows();
fDesktop->UnlockAllWindows();
		// TODO: possible deadlock
		fDesktop->EventDispatcher().AddListener(EventTarget(),
			newView->Token(), eventMask, eventOptions);
fDesktop->LockAllWindows();
//		fDesktop->UnlockAllWindows();
//		fDesktop->LockSingleWindow();
	}
 
	// Initialize the view with the current application plain font.
	// NOTE: This might be out of sync with the global app_server plain
	// font, but that is so on purpose! The client needs to resync itself
	// with the app_server fonts upon notification, but if we just use
	// the current font here, the be_plain_font on the client may still
	// hold old values. So this needs to be an update initiated by the
	// client application.
	newView->CurrentState()->SetFont(App()->PlainFont());
 
	if (_parent) {
		View *parent;
		if (App()->ViewTokens().GetToken(parentToken, B_HANDLER_TOKEN,
				(void**)&parent) != B_OK
			|| parent->Window()->ServerWindow() != this) {
			debug_printf("View token not found!\n");
			parent = NULL;
		}
 
		*_parent = parent;
	}
 
	return newView;
}
 
 
/*!	Dispatches all window messages, and those view messages that
	don't need a valid fCurrentView (ie. view creation).
*/
void
ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
{
	switch (code) {
		case AS_SHOW_OR_HIDE_WINDOW:
		{
			int32 showLevel;
			if (link.Read<int32>(&showLevel) == B_OK) {
				DTRACE(("ServerWindow %s: Message AS_SHOW_OR_HIDE_WINDOW, "
					"show level: %" B_PRId32 "\n", Title(), showLevel));
 
				fWindow->SetShowLevel(showLevel);
				if (showLevel <= 0)
					_Show();
				else
					_Hide();
			}
			break;
		}
		// Only for internal use within this class
		case AS_INTERNAL_HIDE_WINDOW:
			_Hide();
			break;
		case AS_MINIMIZE_WINDOW:
		{
			bool minimize;
			if (link.Read<bool>(&minimize) == B_OK) {
				DTRACE(("ServerWindow %s: Message AS_MINIMIZE_WINDOW, "
					"minimize: %d\n", Title(), minimize));
 
				fDesktop->UnlockSingleWindow();
				fDesktop->MinimizeWindow(fWindow, minimize);
				fDesktop->LockSingleWindow();
			}
			break;
		}
 
		case AS_ACTIVATE_WINDOW:
		{
			bool activate = true;
			if (link.Read<bool>(&activate) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_ACTIVATE_WINDOW: activate: "
				"%d\n", Title(), activate));
 
			fDesktop->UnlockSingleWindow();
 
			if (activate)
				fDesktop->SelectWindow(fWindow);
			else
				fDesktop->SendWindowBehind(fWindow, NULL);
 
			fDesktop->LockSingleWindow();
			break;
		}
		case AS_SEND_BEHIND:
		{
			// Has the all-window lock
			int32 token;
			team_id teamID;
			status_t status = B_ERROR;
 
			link.Read<int32>(&token);
			if (link.Read<team_id>(&teamID) == B_OK) {
				::Window* behindOf = fDesktop->FindWindowByClientToken(token,
					teamID);
 
				DTRACE(("ServerWindow %s: Message AS_SEND_BEHIND %s\n",
					Title(), behindOf != NULL ? behindOf->Title() : "NULL"));
 
				if (behindOf != NULL || token == -1) {
					fDesktop->SendWindowBehind(fWindow, behindOf);
					status = B_OK;
				} else
					status = B_NAME_NOT_FOUND;
			}
 
			fLink.StartMessage(status);
			fLink.Flush();
			break;
		}
 
		case B_QUIT_REQUESTED:
			DTRACE(("ServerWindow %s received quit request\n", Title()));
			NotifyQuitRequested();
			break;
 
		case AS_ENABLE_UPDATES:
			DTRACE(("ServerWindow %s: Message AS_ENABLE_UPDATES\n", Title()));
			fWindow->EnableUpdateRequests();
			break;
 
		case AS_DISABLE_UPDATES:
			DTRACE(("ServerWindow %s: Message AS_DISABLE_UPDATES\n", Title()));
			fWindow->DisableUpdateRequests();
			break;
 
		case AS_NEEDS_UPDATE:
			DTRACE(("ServerWindow %s: Message AS_NEEDS_UPDATE: %d\n",
				Title(), fWindow->NeedsUpdate()));
			if (fWindow->NeedsUpdate())
				fLink.StartMessage(B_OK);
			else
				fLink.StartMessage(B_ERROR);
			fLink.Flush();
			break;
 
		case AS_SET_WINDOW_TITLE:
		{
			char* newTitle;
			if (link.ReadString(&newTitle) == B_OK) {
				DTRACE(("ServerWindow %s: Message AS_SET_WINDOW_TITLE: %s\n",
					Title(), newTitle));
 
				SetTitle(newTitle);
				free(newTitle);
			}
			break;
		}
 
		case AS_ADD_TO_SUBSET:
		{
			// Has the all-window lock
			DTRACE(("ServerWindow %s: Message AS_ADD_TO_SUBSET\n", Title()));
			status_t status = B_ERROR;
 
			int32 token;
			if (link.Read<int32>(&token) == B_OK) {
				::Window* window = fDesktop->FindWindowByClientToken(token,
					App()->ClientTeam());
				if (window == NULL || window->Feel() != B_NORMAL_WINDOW_FEEL) {
					status = B_BAD_VALUE;
				} else {
					status = fDesktop->AddWindowToSubset(fWindow, window)
						? B_OK : B_NO_MEMORY;
				}
			}
 
			fLink.StartMessage(status);
			fLink.Flush();
			break;
		}
		case AS_REMOVE_FROM_SUBSET:
		{
			// Has the all-window lock
			DTRACE(("ServerWindow %s: Message AS_REM_FROM_SUBSET\n", Title()));
			status_t status = B_ERROR;
 
			int32 token;
			if (link.Read<int32>(&token) == B_OK) {
				::Window* window = fDesktop->FindWindowByClientToken(token,
					App()->ClientTeam());
				if (window != NULL) {
					fDesktop->RemoveWindowFromSubset(fWindow, window);
					status = B_OK;
				} else
					status = B_BAD_VALUE;
			}
 
			fLink.StartMessage(status);
			fLink.Flush();
			break;
		}
 
		case AS_SET_LOOK:
		{
			// Has the all-window look
			DTRACE(("ServerWindow %s: Message AS_SET_LOOK\n", Title()));
 
			status_t status = B_ERROR;
			int32 look;
			if (link.Read<int32>(&look) == B_OK) {
				// test if look is valid
				status = Window::IsValidLook((window_look)look)
					? B_OK : B_BAD_VALUE;
			}
 
			if (status == B_OK && !fWindow->IsOffscreenWindow())
				fDesktop->SetWindowLook(fWindow, (window_look)look);
 
			fLink.StartMessage(status);
			fLink.Flush();
			break;
		}
		case AS_SET_FEEL:
		{
			// Has the all-window look
			DTRACE(("ServerWindow %s: Message AS_SET_FEEL\n", Title()));
 
			status_t status = B_ERROR;
			int32 feel;
			if (link.Read<int32>(&feel) == B_OK) {
				// test if feel is valid
				status = Window::IsValidFeel((window_feel)feel)
					? B_OK : B_BAD_VALUE;
			}
 
			if (status == B_OK && !fWindow->IsOffscreenWindow())
				fDesktop->SetWindowFeel(fWindow, (window_feel)feel);
 
			fLink.StartMessage(status);
			fLink.Flush();
			break;
		}
		case AS_SET_FLAGS:
		{
			// Has the all-window look
			DTRACE(("ServerWindow %s: Message AS_SET_FLAGS\n", Title()));
 
			status_t status = B_ERROR;
			uint32 flags;
			if (link.Read<uint32>(&flags) == B_OK) {
				// test if flags are valid
				status = (flags & ~Window::ValidWindowFlags()) == 0
					? B_OK : B_BAD_VALUE;
			}
 
			if (status == B_OK && !fWindow->IsOffscreenWindow())
				fDesktop->SetWindowFlags(fWindow, flags);
 
			fLink.StartMessage(status);
			fLink.Flush();
			break;
		}
#if 0
		case AS_SET_ALIGNMENT:
		{
			// TODO: Implement AS_SET_ALIGNMENT
			DTRACE(("ServerWindow %s: Message Set_Alignment unimplemented\n",
				Title()));
			break;
		}
		case AS_GET_ALIGNMENT:
		{
			// TODO: Implement AS_GET_ALIGNMENT
			DTRACE(("ServerWindow %s: Message Get_Alignment unimplemented\n",
				Title()));
			break;
		}
#endif
		case AS_IS_FRONT_WINDOW:
		{
			bool isFront = fDesktop->FrontWindow() == fWindow;
			DTRACE(("ServerWindow %s: Message AS_IS_FRONT_WINDOW: %d\n",
				Title(), isFront));
			fLink.StartMessage(isFront ? B_OK : B_ERROR);
			fLink.Flush();
			break;
		}
 
		case AS_GET_WORKSPACES:
		{
			DTRACE(("ServerWindow %s: Message AS_GET_WORKSPACES\n", Title()));
			fLink.StartMessage(B_OK);
			fLink.Attach<uint32>(fWindow->Workspaces());
			fLink.Flush();
			break;
		}
		case AS_SET_WORKSPACES:
		{
			// Has the all-window lock (but would actually not need to lock at
			// all)
			uint32 newWorkspaces;
			if (link.Read<uint32>(&newWorkspaces) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_SET_WORKSPACES %" B_PRIx32 "\n",
				Title(), newWorkspaces));
 
			fDesktop->SetWindowWorkspaces(fWindow, newWorkspaces);
			break;
		}
		case AS_WINDOW_RESIZE:
		{
			// Has the all-window look
			float xResizeTo;
			float yResizeTo;
			link.Read<float>(&xResizeTo);
			if (link.Read<float>(&yResizeTo) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_WINDOW_RESIZE %.1f, %.1f\n",
				Title(), xResizeTo, yResizeTo));
 
			// comment this code for the time being, as some apps rely
			// on the programmatically resize behavior during user resize
//			if (fWindow->IsResizing()) {
				// While the user resizes the window, we ignore
				// pragmatically set window bounds
//				fLink.StartMessage(B_BUSY);
//			} else {
				fDesktop->ResizeWindowBy(fWindow,
					xResizeTo - fWindow->Frame().Width(),
					yResizeTo - fWindow->Frame().Height());
				fLink.StartMessage(B_OK);
//			}
			fLink.Flush();
			break;
		}
		case AS_WINDOW_MOVE:
		{
			// Has the all-window look
			float xMoveTo;
			float yMoveTo;
			link.Read<float>(&xMoveTo);
			if (link.Read<float>(&yMoveTo) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_WINDOW_MOVE: %.1f, %.1f\n",
				Title(), xMoveTo, yMoveTo));
 
			if (fWindow->IsDragging()) {
				// While the user moves the window, we ignore
				// pragmatically set window positions
				fLink.StartMessage(B_BUSY);
			} else {
				fDesktop->MoveWindowBy(fWindow, xMoveTo - fWindow->Frame().left,
					yMoveTo - fWindow->Frame().top);
				fLink.StartMessage(B_OK);
			}
			fLink.Flush();
			break;
		}
		case AS_SET_SIZE_LIMITS:
		{
			// Has the all-window look
 
			// Attached Data:
			// 1) float minimum width
			// 2) float maximum width
			// 3) float minimum height
			// 4) float maximum height
 
			// TODO: for now, move the client to int32 as well!
			int32 minWidth, maxWidth, minHeight, maxHeight;
			float value;
			link.Read<float>(&value);	minWidth = (int32)value;
			link.Read<float>(&value);	maxWidth = (int32)value;
			link.Read<float>(&value);	minHeight = (int32)value;
			link.Read<float>(&value);	maxHeight = (int32)value;
/*
			link.Read<int32>(&minWidth);
			link.Read<int32>(&maxWidth);
			link.Read<int32>(&minHeight);
			link.Read<int32>(&maxHeight);
*/
			DTRACE(("ServerWindow %s: Message AS_SET_SIZE_LIMITS: "
				"x: %" B_PRId32 "-%" B_PRId32 ", y: %" B_PRId32 "-%" B_PRId32
				"\n", Title(), minWidth, maxWidth, minHeight, maxHeight));
 
			fWindow->SetSizeLimits(minWidth, maxWidth, minHeight, maxHeight);
 
			// and now, sync the client to the limits that we were able to enforce
			fWindow->GetSizeLimits(&minWidth, &maxWidth,
				&minHeight, &maxHeight);
 
			fLink.StartMessage(B_OK);
			fLink.Attach<BRect>(fWindow->Frame());
			fLink.Attach<float>((float)minWidth);
			fLink.Attach<float>((float)maxWidth);
			fLink.Attach<float>((float)minHeight);
			fLink.Attach<float>((float)maxHeight);
 
			fLink.Flush();
 
			fDesktop->NotifySizeLimitsChanged(fWindow, minWidth, maxWidth,
				minHeight, maxHeight);
			break;
		}
 
		case AS_SET_DECORATOR_SETTINGS:
		{
			// Has the all-window look
			DTRACE(("ServerWindow %s: Message AS_SET_DECORATOR_SETTINGS\n",
				Title()));
 
			int32 size;
			if (fWindow && link.Read<int32>(&size) == B_OK) {
				char buffer[size];
				if (link.Read(buffer, size) == B_OK) {
					BMessage settings;
					if (settings.Unflatten(buffer) == B_OK)
						fDesktop->SetWindowDecoratorSettings(fWindow, settings);
				}
			}
			break;
		}
 
		case AS_GET_DECORATOR_SETTINGS:
		{
			DTRACE(("ServerWindow %s: Message AS_GET_DECORATOR_SETTINGS\n",
				Title()));
 
			bool success = false;
 
			BMessage settings;
			if (fWindow->GetDecoratorSettings(&settings)) {
				int32 size = settings.FlattenedSize();
				char buffer[size];
				if (settings.Flatten(buffer, size) == B_OK) {
					success = true;
					fLink.StartMessage(B_OK);
					fLink.Attach<int32>(size);
					fLink.Attach(buffer, size);
				}
			}
 
			if (!success)
				fLink.StartMessage(B_ERROR);
 
			fLink.Flush();
			break;
		}
 
		case AS_SYSTEM_FONT_CHANGED:
		{
			// Has the all-window look
			fDesktop->FontsChanged(fWindow);
			break;
		}
 
		// Forward to client
		case B_FONTS_UPDATED:
		{
			// TODO: would knowing which font was changed be useful?
			BMessage message(code);
			SendMessageToClient(&message);
			break;
		}
 
		case AS_REDRAW:
			// Nothing to do here - the redraws are actually handled by looking
			// at the fRedrawRequested member variable in _MessageLooper().
			break;
 
		case AS_SYNC:
			DTRACE(("ServerWindow %s: Message AS_SYNC\n", Title()));
			// the synchronisation works by the fact that the client
			// window is waiting for this reply, after having received it,
			// client and server queues are in sync (earlier, the client
			// may have pushed drawing commands at the server and now it
			// knows they have all been carried out)
			fLink.StartMessage(B_OK);
			fLink.Flush();
			break;
 
		case AS_BEGIN_UPDATE:
			DTRACE(("ServerWindow %s: Message AS_BEGIN_UPDATE\n", Title()));
			fWindow->BeginUpdate(fLink);
			break;
 
		case AS_END_UPDATE:
			DTRACE(("ServerWindow %s: Message AS_END_UPDATE\n", Title()));
			fWindow->EndUpdate();
			break;
 
		case AS_GET_MOUSE:
		{
			// Has the all-window look
			DTRACE(("ServerWindow %s: Message AS_GET_MOUSE\n", fTitle));
 
			// Returns
			// 1) BPoint mouse location
			// 2) int32 button state
 
			BPoint where;
			int32 buttons;
			fDesktop->GetLastMouseState(&where, &buttons);
 
			fLink.StartMessage(B_OK);
			fLink.Attach<BPoint>(where);
			fLink.Attach<int32>(buttons);
			fLink.Flush();
			break;
		}
 
		// BDirectWindow communication
 
		case AS_DIRECT_WINDOW_GET_SYNC_DATA:
		{
			status_t status = _EnableDirectWindowMode();
 
			fLink.StartMessage(status);
			if (status == B_OK) {
				struct direct_window_sync_data syncData;
				fDirectWindowInfo->GetSyncData(syncData);
 
				fLink.Attach(&syncData, sizeof(syncData));
			}
 
			fLink.Flush();
			break;
		}
		case AS_DIRECT_WINDOW_SET_FULLSCREEN:
		{
			// Has the all-window look
			bool enable;
			link.Read<bool>(&enable);
 
			status_t status = B_OK;
			if (fDirectWindowInfo != NULL)
				_DirectWindowSetFullScreen(enable);
			else
				status = B_BAD_TYPE;
 
			fLink.StartMessage(status);
			fLink.Flush();
			break;
		}
 
		// View creation and destruction (don't need a valid fCurrentView)
 
		case AS_SET_CURRENT_VIEW:
		{
			int32 token;
			if (link.Read<int32>(&token) != B_OK)
				break;
 
			View *current;
			if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN,
					(void**)&current) != B_OK
				|| current->Window()->ServerWindow() != this) {
				// TODO: if this happens, we probably want to kill the app and
				// clean up
				debug_printf("ServerWindow %s: Message "
					"\n\n\nAS_SET_CURRENT_VIEW: view not found, token %"
					B_PRId32 "\n", fTitle, token);
				current = NULL;
			} else {
				DTRACE(("\n\n\nServerWindow %s: Message AS_SET_CURRENT_VIEW: %s, "
					"token %" B_PRId32 "\n", fTitle, current->Name(), token));
				_SetCurrentView(current);
			}
			break;
		}
 
		case AS_VIEW_CREATE_ROOT:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_CREATE_ROOT\n", fTitle));
 
			// Start receiving top_view data -- pass NULL as the parent view.
			// This should be the *only* place where this happens.
			if (fCurrentView != NULL) {
				debug_printf("ServerWindow %s: Message "
					"AS_VIEW_CREATE_ROOT: fCurrentView already set!!\n",
					fTitle);
				break;
			}
 
			_SetCurrentView(_CreateView(link, NULL));
			fWindow->SetTopView(fCurrentView);
			break;
		}
 
		case AS_VIEW_CREATE:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_CREATE: View name: "
				"%s\n", fTitle, fCurrentView->Name()));
 
			View* parent = NULL;
			View* newView = _CreateView(link, &parent);
			if (parent != NULL && newView != NULL)
				parent->AddChild(newView);
			else {
				delete newView;
				debug_printf("ServerWindow %s: Message AS_VIEW_CREATE: "
					"parent or newView NULL!!\n", fTitle);
			}
			break;
		}
 
		case AS_TALK_TO_DESKTOP_LISTENER:
		{
			if (fDesktop->MessageForListener(fWindow, fLink.Receiver(),
				fLink.Sender()))
				break;
			// unhandled message at least send an error if needed
			if (link.NeedsReply()) {
				fLink.StartMessage(B_ERROR);
				fLink.Flush();
			}
			break;
		}
 
		default:
			if (fCurrentView == NULL) {
				BString codeName;
				string_for_message_code(code, codeName);
				debug_printf("ServerWindow %s received unexpected code - "
					"message '%s' before top_view attached.\n",
					Title(), codeName.String());
				if (link.NeedsReply()) {
					fLink.StartMessage(B_ERROR);
					fLink.Flush();
				}
				return;
			}
 
			_DispatchViewMessage(code, link);
			break;
	}
}
 
 
/*!
	Dispatches all view messages that need a valid fCurrentView.
*/
void
ServerWindow::_DispatchViewMessage(int32 code,
	BPrivate::LinkReceiver &link)
{
	if (_DispatchPictureMessage(code, link))
		return;
 
	switch (code) {
		case AS_VIEW_SCROLL:
		{
			float dh;
			float dv;
			link.Read<float>(&dh);
			if (link.Read<float>(&dv) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_SCROLL: View name: "
				"%s, %.1f x %.1f\n", fTitle, fCurrentView->Name(), dh, dv));
			fWindow->ScrollViewBy(fCurrentView, dh, dv);
			break;
		}
		case AS_VIEW_COPY_BITS:
		{
			BRect src;
			BRect dst;
 
			link.Read<BRect>(&src);
			if (link.Read<BRect>(&dst) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_COPY_BITS: View name: "
				"%s, BRect(%.1f, %.1f, %.1f, %.1f) -> "
				"BRect(%.1f, %.1f, %.1f, %.1f)\n", fTitle,
				fCurrentView->Name(), src.left, src.top, src.right, src.bottom,
				dst.left, dst.top, dst.right, dst.bottom));
 
			BRegion contentRegion;
			// TODO: avoid copy operation maybe?
			fWindow->GetContentRegion(&contentRegion);
			fCurrentView->CopyBits(src, dst, contentRegion);
			break;
		}
		case AS_VIEW_DELETE:
		{
			// Received when a view is detached from a window
 
			int32 token;
			if (link.Read<int32>(&token) != B_OK)
				break;
 
			View *view;
			if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN,
					(void**)&view) == B_OK
				&& view->Window()->ServerWindow() == this) {
				View* parent = view->Parent();
 
				DTRACE(("ServerWindow %s: AS_VIEW_DELETE view: %p, "
					"parent: %p\n", fTitle, view, parent));
 
				if (parent != NULL) {
					parent->RemoveChild(view);
 
					if (view->EventMask() != 0) {
						// TODO: possible deadlock (event dispatcher already
						// locked itself, waits for Desktop write lock, but
						// we have it, now we are trying to lock the event
						// dispatcher -> deadlock)
fDesktop->UnlockSingleWindow();
						fDesktop->EventDispatcher().RemoveListener(
							EventTarget(), token);
fDesktop->LockSingleWindow();
					}
 
					if (fCurrentView == view || fCurrentView->HasParent(view))
						_SetCurrentView(parent);
 
					delete view;
				} // else we don't delete the root view
			}
			break;
		}
		case AS_VIEW_SET_STATE:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_STATE: "
				"View name: %s\n", fTitle, fCurrentView->Name()));
 
			fCurrentView->CurrentState()->ReadFromLink(link);
			// TODO: When is this used?!?
			fCurrentView->RebuildClipping(true);
			_UpdateDrawState(fCurrentView);
 
			break;
		}
		case AS_VIEW_SET_FONT_STATE:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FONT_STATE: "
				"View name: %s\n", fTitle, fCurrentView->Name()));
 
			fCurrentView->CurrentState()->ReadFontFromLink(link);
			fWindow->GetDrawingEngine()->SetFont(
				fCurrentView->CurrentState());
			break;
		}
		case AS_VIEW_GET_STATE:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_STATE: "
				"View name: %s\n", fTitle, fCurrentView->Name()));
 
			fLink.StartMessage(B_OK);
 
			// attach state data
			fCurrentView->CurrentState()->WriteToLink(fLink.Sender());
			fLink.Flush();
			break;
		}
		case AS_VIEW_SET_EVENT_MASK:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_EVENT_MASK: "
				"View name: %s\n", fTitle, fCurrentView->Name()));
			uint32 eventMask, options;
 
			link.Read<uint32>(&eventMask);
			if (link.Read<uint32>(&options) == B_OK) {
				fCurrentView->SetEventMask(eventMask, options);
 
fDesktop->UnlockSingleWindow();
				// TODO: possible deadlock!
				if (eventMask != 0 || options != 0) {
					fDesktop->EventDispatcher().AddListener(EventTarget(),
						fCurrentView->Token(), eventMask, options);
				} else {
					fDesktop->EventDispatcher().RemoveListener(EventTarget(),
						fCurrentView->Token());
				}
fDesktop->LockSingleWindow();
			}
			break;
		}
		case AS_VIEW_SET_MOUSE_EVENT_MASK:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_MOUSE_EVENT_MASK: "
				"View name: %s\n", fTitle, fCurrentView->Name()));
			uint32 eventMask, options;
 
			link.Read<uint32>(&eventMask);
			if (link.Read<uint32>(&options) == B_OK) {
fDesktop->UnlockSingleWindow();
				// TODO: possible deadlock
				if (eventMask != 0 || options != 0) {
					if (options & B_LOCK_WINDOW_FOCUS)
						fDesktop->SetFocusLocked(fWindow);
					fDesktop->EventDispatcher().AddTemporaryListener(EventTarget(),
						fCurrentView->Token(), eventMask, options);
				} else {
					fDesktop->EventDispatcher().RemoveTemporaryListener(EventTarget(),
						fCurrentView->Token());
				}
fDesktop->LockSingleWindow();
			}
 
			// TODO: support B_LOCK_WINDOW_FOCUS option in Desktop
			break;
		}
		case AS_VIEW_MOVE_TO:
		{
			float x, y;
			link.Read<float>(&x);
			if (link.Read<float>(&y) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_MOVE_TO: View name: "
				"%s, x: %.1f, y: %.1f\n", fTitle, fCurrentView->Name(), x, y));
 
			float offsetX = x - fCurrentView->Frame().left;
			float offsetY = y - fCurrentView->Frame().top;
 
			BRegion dirty;
			fCurrentView->MoveBy(offsetX, offsetY, &dirty);
 
			// TODO: think about how to avoid this hack:
			// the parent clipping needs to be updated, it is not
			// done in MoveBy() since it would cause
			// too much computations when children are resized because
			// follow modes
			if (View* parent = fCurrentView->Parent())
				parent->RebuildClipping(false);
 
			fWindow->MarkContentDirty(dirty);
			break;
		}
		case AS_VIEW_RESIZE_TO:
		{
			float newWidth, newHeight;
			link.Read<float>(&newWidth);
			if (link.Read<float>(&newHeight) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_RESIZE_TO: View name: "
				"%s, width: %.1f, height: %.1f\n", fTitle,
				fCurrentView->Name(), newWidth, newHeight));
 
			float deltaWidth = newWidth - fCurrentView->Frame().Width();
			float deltaHeight = newHeight - fCurrentView->Frame().Height();
 
			BRegion dirty;
			fCurrentView->ResizeBy(deltaWidth, deltaHeight, &dirty);
 
			// TODO: see above
			if (View* parent = fCurrentView->Parent())
				parent->RebuildClipping(false);
 
			fWindow->MarkContentDirty(dirty);
			break;
		}
		case AS_VIEW_GET_COORD:
		{
			// our offset in the parent -> will be originX and originY
			// in BView
			BPoint parentOffset = fCurrentView->Frame().LeftTop();
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_COORD: "
				"View: %s -> x: %.1f, y: %.1f\n", Title(),
				fCurrentView->Name(), parentOffset.x, parentOffset.y));
 
			fLink.StartMessage(B_OK);
			fLink.Attach<BPoint>(parentOffset);
			fLink.Attach<BRect>(fCurrentView->Bounds());
			fLink.Flush();
			break;
		}
		case AS_VIEW_SET_ORIGIN:
		{
			float x, y;
			link.Read<float>(&x);
			if (link.Read<float>(&y) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_ORIGIN: "
				"View: %s -> x: %.1f, y: %.1f\n", Title(),
				fCurrentView->Name(), x, y));
 
			fCurrentView->SetDrawingOrigin(BPoint(x, y));
			_UpdateDrawState(fCurrentView);
			break;
		}
		case AS_VIEW_GET_ORIGIN:
		{
			BPoint drawingOrigin = fCurrentView->DrawingOrigin();
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_ORIGIN: "
				"View: %s -> x: %.1f, y: %.1f\n", Title(),
				fCurrentView->Name(), drawingOrigin.x, drawingOrigin.y));
 
			fLink.StartMessage(B_OK);
			fLink.Attach<BPoint>(drawingOrigin);
			fLink.Flush();
			break;
		}
		case AS_VIEW_RESIZE_MODE:
		{
			uint32 resizeMode;
			if (link.Read<uint32>(&resizeMode) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_RESIZE_MODE: "
				"View: %s -> %" B_PRId32 "\n", Title(), fCurrentView->Name(),
				resizeMode));
 
			fCurrentView->SetResizeMode(resizeMode);
			break;
		}
		case AS_VIEW_SET_FLAGS:
		{
			uint32 flags;
			link.Read<uint32>(&flags);
 
			// The views clipping changes when the B_DRAW_ON_CHILDREN flag is
			// toggled.
			bool updateClipping = (flags & B_DRAW_ON_CHILDREN)
				^ (fCurrentView->Flags() & B_DRAW_ON_CHILDREN);
 
			fCurrentView->SetFlags(flags);
			_UpdateDrawState(fCurrentView);
 
			if (updateClipping) {
				fCurrentView->RebuildClipping(false);
				fCurrentDrawingRegionValid = false;
			}
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FLAGS: "
				"View: %s -> flags: %" B_PRIu32 "\n", Title(),
				fCurrentView->Name(), flags));
			break;
		}
		case AS_VIEW_HIDE:
			DTRACE(("ServerWindow %s: Message AS_VIEW_HIDE: View: %s\n",
				Title(), fCurrentView->Name()));
			fCurrentView->SetHidden(true);
			break;
 
		case AS_VIEW_SHOW:
			DTRACE(("ServerWindow %s: Message AS_VIEW_SHOW: View: %s\n",
				Title(), fCurrentView->Name()));
			fCurrentView->SetHidden(false);
			break;
 
		case AS_VIEW_SET_LINE_MODE:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_LINE_MODE: "
				"View: %s\n", Title(), fCurrentView->Name()));
			ViewSetLineModeInfo info;
			if (link.Read<ViewSetLineModeInfo>(&info) != B_OK)
				break;
 
			fCurrentView->CurrentState()->SetLineCapMode(info.lineCap);
			fCurrentView->CurrentState()->SetLineJoinMode(info.lineJoin);
			fCurrentView->CurrentState()->SetMiterLimit(info.miterLimit);
 
			fWindow->GetDrawingEngine()->SetStrokeMode(info.lineCap,
				info.lineJoin, info.miterLimit);
 
			break;
		}
		case AS_VIEW_GET_LINE_MODE:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LINE_MODE: "
				"View: %s\n", Title(), fCurrentView->Name()));
			ViewSetLineModeInfo info;
			info.lineJoin = fCurrentView->CurrentState()->LineJoinMode();
			info.lineCap = fCurrentView->CurrentState()->LineCapMode();
			info.miterLimit = fCurrentView->CurrentState()->MiterLimit();
 
			fLink.StartMessage(B_OK);
			fLink.Attach<ViewSetLineModeInfo>(info);
			fLink.Flush();
 
			break;
		}
		case AS_VIEW_SET_FILL_RULE:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FILL_RULE: "
				"View: %s\n", Title(), fCurrentView->Name()));
			int32 fillRule;
			if (link.Read<int32>(&fillRule) != B_OK)
				break;
 
			fCurrentView->CurrentState()->SetFillRule(fillRule);
			fWindow->GetDrawingEngine()->SetFillRule(fillRule);
 
			break;
		}
		case AS_VIEW_GET_FILL_RULE:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_FILL_RULE: "
				"View: %s\n", Title(), fCurrentView->Name()));
			int32 fillRule = fCurrentView->CurrentState()->FillRule();
 
			fLink.StartMessage(B_OK);
			fLink.Attach<int32>(fillRule);
			fLink.Flush();
 
			break;
		}
		case AS_VIEW_PUSH_STATE:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_PUSH_STATE: View: "
				"%s\n", Title(), fCurrentView->Name()));
 
			fCurrentView->PushState();
			// TODO: is this necessary?
//			_UpdateDrawState(fCurrentView);
			break;
		}
		case AS_VIEW_POP_STATE:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_POP_STATE: View: %s\n",
				Title(), fCurrentView->Name()));
 
			fCurrentView->PopState();
			_UpdateDrawState(fCurrentView);
			break;
		}
		case AS_VIEW_SET_SCALE:
		{
			float scale;
			if (link.Read<float>(&scale) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_SCALE: "
				"View: %s -> scale: %.2f\n", Title(), fCurrentView->Name(),
				scale));
 
			fCurrentView->SetScale(scale);
			_UpdateDrawState(fCurrentView);
			break;
		}
		case AS_VIEW_GET_SCALE:
		{
			float scale = fCurrentView->CurrentState()->Scale();
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_SCALE: "
				"View: %s -> scale: %.2f\n",
				Title(), fCurrentView->Name(), scale));
 
			fLink.StartMessage(B_OK);
			fLink.Attach<float>(scale);
			fLink.Flush();
			break;
		}
		case AS_VIEW_SET_TRANSFORM:
		{
			BAffineTransform transform;
			if (link.Read<BAffineTransform>(&transform) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_TRANSFORM: "
				"View: %s -> transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n",
				Title(), fCurrentView->Name(), transform.sx, transform.shy,
				transform.shx, transform.sy, transform.tx, transform.ty));
 
			fCurrentView->CurrentState()->SetTransform(transform);
			_UpdateDrawState(fCurrentView);
			break;
		}
		case AS_VIEW_GET_TRANSFORM:
		{
			BAffineTransform transform
				= fCurrentView->CurrentState()->Transform();
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_TRANSFORM: "
				"View: %s -> transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n",
				Title(), fCurrentView->Name(), transform.sx, transform.shy,
				transform.shx, transform.sy, transform.tx, transform.ty));
 
			fLink.StartMessage(B_OK);
			fLink.Attach<BAffineTransform>(transform);
			fLink.Flush();
			break;
		}
		case AS_VIEW_AFFINE_TRANSLATE:
		{
			double x, y;
			link.Read<double>(&x);
			link.Read<double>(&y);
			BAffineTransform current =
				fCurrentView->CurrentState()->Transform();
			current.PreTranslateBy(x, y);
			fCurrentView->CurrentState()->SetTransform(current);
			_UpdateDrawState(fCurrentView);
			break;
		}
 
		case AS_VIEW_AFFINE_SCALE:
		{
			double x, y;
			link.Read<double>(&x);
			link.Read<double>(&y);
			BAffineTransform current =
				fCurrentView->CurrentState()->Transform();
			current.PreScaleBy(x, y);
			fCurrentView->CurrentState()->SetTransform(current);
			_UpdateDrawState(fCurrentView);
			break;
		}
 
		case AS_VIEW_AFFINE_ROTATE:
		{
			double angleRadians;
			link.Read<double>(&angleRadians);
			BAffineTransform current =
				fCurrentView->CurrentState()->Transform();
			current.PreRotateBy(angleRadians);
			fCurrentView->CurrentState()->SetTransform(current);
			_UpdateDrawState(fCurrentView);
			break;
		}
 
		case AS_VIEW_SET_PEN_LOC:
		{
			BPoint location;
			if (link.Read<BPoint>(&location) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PEN_LOC: "
				"View: %s -> BPoint(%.1f, %.1f)\n", Title(),
				fCurrentView->Name(), location.x, location.y));
 
			fCurrentView->CurrentState()->SetPenLocation(location);
			break;
		}
		case AS_VIEW_GET_PEN_LOC:
		{
			BPoint location = fCurrentView->CurrentState()->PenLocation();
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_PEN_LOC: "
				"View: %s -> BPoint(%.1f, %.1f)\n", Title(),
				fCurrentView->Name(), location.x, location.y));
 
			fLink.StartMessage(B_OK);
			fLink.Attach<BPoint>(location);
			fLink.Flush();
 
			break;
		}
		case AS_VIEW_SET_PEN_SIZE:
		{
			float penSize;
			if (link.Read<float>(&penSize) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PEN_SIZE: "
				"View: %s -> %.1f\n", Title(), fCurrentView->Name(), penSize));
 
			fCurrentView->CurrentState()->SetPenSize(penSize);
			fWindow->GetDrawingEngine()->SetPenSize(
				fCurrentView->CurrentState()->PenSize());
			break;
		}
		case AS_VIEW_GET_PEN_SIZE:
		{
			float penSize = fCurrentView->CurrentState()->UnscaledPenSize();
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_PEN_SIZE: "
				"View: %s -> %.1f\n", Title(), fCurrentView->Name(), penSize));
 
			fLink.StartMessage(B_OK);
			fLink.Attach<float>(penSize);
			fLink.Flush();
 
			break;
		}
		case AS_VIEW_SET_VIEW_COLOR:
		{
			rgb_color color;
			if (link.Read(&color, sizeof(rgb_color)) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_VIEW_COLOR: "
				"View: %s -> rgb_color(%d, %d, %d, %d)\n", Title(),
				fCurrentView->Name(), color.red, color.green, color.blue,
				color.alpha));
 
			fCurrentView->SetViewColor(color);
			break;
		}
		case AS_VIEW_GET_VIEW_COLOR:
		{
			rgb_color color = fCurrentView->ViewColor();
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_VIEW_COLOR: "
				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
				Title(), fCurrentView->Name(), color.red, color.green,
				color.blue, color.alpha));
 
			fLink.StartMessage(B_OK);
			fLink.Attach<rgb_color>(color);
			fLink.Flush();
			break;
		}
		case AS_VIEW_SET_HIGH_COLOR:
		{
			rgb_color color;
			if (link.Read(&color, sizeof(rgb_color)) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_HIGH_COLOR: "
				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
				Title(), fCurrentView->Name(), color.red, color.green,
				color.blue, color.alpha));
 
			fCurrentView->CurrentState()->SetHighColor(color);
			fWindow->GetDrawingEngine()->SetHighColor(color);
			break;
		}
 
		case AS_VIEW_SET_HIGH_UI_COLOR:
		{
			color_which which = B_NO_COLOR;
			float tint = B_NO_TINT;
 
			if (link.Read<color_which>(&which) != B_OK
				|| link.Read<float>(&tint) != B_OK )
				break;
 
			fCurrentView->CurrentState()->SetHighUIColor(which, tint);
 
			// TODO: should we do more color_which validity checking?
			if (which != B_NO_COLOR) {
				DesktopSettings settings(fDesktop);
				rgb_color color = tint_color(settings.UIColor(which), tint);
 
				fCurrentView->CurrentState()->SetHighColor(color);
				fWindow->GetDrawingEngine()->SetHighColor(color);
			}
			break;
		}
		case AS_VIEW_SET_LOW_UI_COLOR:
		{
			color_which which = B_NO_COLOR;
			float tint = B_NO_TINT;
 
			if (link.Read<color_which>(&which) != B_OK
				|| link.Read<float>(&tint) != B_OK )
				break;
 
			fCurrentView->CurrentState()->SetLowUIColor(which, tint);
 
			// TODO: should we do more color_which validity checking?
			if (which != B_NO_COLOR) {
				DesktopSettings settings(fDesktop);
				rgb_color color = tint_color(settings.UIColor(which), tint);
 
				fCurrentView->CurrentState()->SetLowColor(color);
				fWindow->GetDrawingEngine()->SetLowColor(color);
			}
			break;
		}
		case AS_VIEW_SET_VIEW_UI_COLOR:
		{
			color_which which = B_NO_COLOR;
			float tint = B_NO_TINT;
 
			if (link.Read<color_which>(&which) != B_OK
				|| link.Read<float>(&tint) != B_OK )
				break;
 
			// TODO: should we do more color_which validity checking?
			fCurrentView->SetViewUIColor(which, tint);
			break;
		}
		case AS_VIEW_GET_HIGH_UI_COLOR:
		{
			float tint;
			color_which which = fCurrentView->CurrentState()->HighUIColor(&tint);
			rgb_color color = fCurrentView->CurrentState()->HighColor();
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_HIGH_UI_COLOR: "
				"View: %s -> color_which(%i) tint(%.3f) - rgb_color(%i, %i,"
				" %i, %i)\n", Title(), fCurrentView->Name(), which, tint,
				color.red, color.green, color.blue, color.alpha));
 
			fLink.StartMessage(B_OK);
			fLink.Attach<color_which>(which);
			fLink.Attach<float>(tint);
			fLink.Attach<rgb_color>(color);
			fLink.Flush();
			break;
		}
		case AS_VIEW_GET_LOW_UI_COLOR:
		{
			float tint;
			color_which which = fCurrentView->CurrentState()->LowUIColor(&tint);
			rgb_color color = fCurrentView->CurrentState()->LowColor();
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LOW_UI_COLOR: "
				"View: %s -> color_which(%i) tint(%.3f) - rgb_color(%i, %i,"
				" %i, %i)\n", Title(), fCurrentView->Name(), which, tint,
				color.red, color.green, color.blue, color.alpha));
 
			fLink.StartMessage(B_OK);
			fLink.Attach<color_which>(which);
			fLink.Attach<float>(tint);
			fLink.Attach<rgb_color>(color);
			fLink.Flush();
			break;
		}
		case AS_VIEW_GET_VIEW_UI_COLOR:
		{
			float tint;
			color_which which = fCurrentView->ViewUIColor(&tint);
			rgb_color color = fCurrentView->ViewColor();
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_VIEW_UI_COLOR: "
				"View: %s -> color_which(%i) tint(%.3f) - rgb_color(%i, %i,"
				" %i, %i)\n", Title(), fCurrentView->Name(), which, tint,
				color.red, color.green, color.blue, color.alpha));
 
			fLink.StartMessage(B_OK);
			fLink.Attach<color_which>(which);
			fLink.Attach<float>(tint);
			fLink.Attach<rgb_color>(color);
			fLink.Flush();
			break;
		}
		case AS_VIEW_GET_HIGH_COLOR:
		{
			rgb_color color = fCurrentView->CurrentState()->HighColor();
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_HIGH_COLOR: "
				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
				Title(), fCurrentView->Name(), color.red, color.green,
				color.blue, color.alpha));
 
			fLink.StartMessage(B_OK);
			fLink.Attach<rgb_color>(color);
			fLink.Flush();
			break;
		}
		case AS_VIEW_SET_LOW_COLOR:
		{
			rgb_color color;
			if (link.Read(&color, sizeof(rgb_color)) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_LOW_COLOR: "
				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
				Title(), fCurrentView->Name(), color.red, color.green,
				color.blue, color.alpha));
 
			fCurrentView->CurrentState()->SetLowColor(color);
			fWindow->GetDrawingEngine()->SetLowColor(color);
			break;
		}
		case AS_VIEW_GET_LOW_COLOR:
		{
			rgb_color color = fCurrentView->CurrentState()->LowColor();
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LOW_COLOR: "
				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
				Title(), fCurrentView->Name(), color.red, color.green,
				color.blue, color.alpha));
 
			fLink.StartMessage(B_OK);
			fLink.Attach<rgb_color>(color);
			fLink.Flush();
			break;
		}
		case AS_VIEW_SET_PATTERN:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PATTERN: "
				"View: %s\n", fTitle, fCurrentView->Name()));
 
			pattern pat;
			if (link.Read(&pat, sizeof(pattern)) != B_OK)
				break;
 
			fCurrentView->CurrentState()->SetPattern(Pattern(pat));
			fWindow->GetDrawingEngine()->SetPattern(pat);
			break;
		}
 
		case AS_VIEW_SET_BLENDING_MODE:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_BLEND_MODE: "
				"View: %s\n", Title(), fCurrentView->Name()));
 
			ViewBlendingModeInfo info;
			if (link.Read<ViewBlendingModeInfo>(&info) != B_OK)
				break;
 
			fCurrentView->CurrentState()->SetBlendingMode(
				info.sourceAlpha, info.alphaFunction);
			fWindow->GetDrawingEngine()->SetBlendingMode(
				info.sourceAlpha, info.alphaFunction);
			break;
		}
		case AS_VIEW_GET_BLENDING_MODE:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_BLEND_MODE: "
				"View: %s\n", Title(), fCurrentView->Name()));
 
			ViewBlendingModeInfo info;
			info.sourceAlpha = fCurrentView->CurrentState()->AlphaSrcMode();
			info.alphaFunction = fCurrentView->CurrentState()->AlphaFncMode();
 
			fLink.StartMessage(B_OK);
			fLink.Attach<ViewBlendingModeInfo>(info);
			fLink.Flush();
 
			break;
		}
		case AS_VIEW_SET_DRAWING_MODE:
		{
			int8 drawingMode;
			if (link.Read<int8>(&drawingMode) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_DRAW_MODE: "
				"View: %s -> %s\n", Title(), fCurrentView->Name(),
				kDrawingModeMap[drawingMode]));
 
			fCurrentView->CurrentState()->SetDrawingMode(
				(drawing_mode)drawingMode);
			fWindow->GetDrawingEngine()->SetDrawingMode(
				(drawing_mode)drawingMode);
			break;
		}
		case AS_VIEW_GET_DRAWING_MODE:
		{
			int8 drawingMode
				= (int8)(fCurrentView->CurrentState()->GetDrawingMode());
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_DRAW_MODE: "
				"View: %s -> %s\n", Title(), fCurrentView->Name(),
				kDrawingModeMap[drawingMode]));
 
			fLink.StartMessage(B_OK);
			fLink.Attach<int8>(drawingMode);
			fLink.Flush();
 
			break;
		}
		case AS_VIEW_SET_VIEW_BITMAP:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_VIEW_BITMAP: "
				"View: %s\n", Title(), fCurrentView->Name()));
 
			int32 bitmapToken, resizingMode, options;
			BRect srcRect, dstRect;
 
			link.Read<int32>(&bitmapToken);
			link.Read<BRect>(&srcRect);
			link.Read<BRect>(&dstRect);
			link.Read<int32>(&resizingMode);
			status_t status = link.Read<int32>(&options);
 
			rgb_color colorKey = {0};
 
			if (status == B_OK) {
				ServerBitmap* bitmap = fServerApp->GetBitmap(bitmapToken);
				if (bitmapToken == -1 || bitmap != NULL) {
					bool wasOverlay = fCurrentView->ViewBitmap() != NULL
						&& fCurrentView->ViewBitmap()->Overlay() != NULL;
 
					fCurrentView->SetViewBitmap(bitmap, srcRect, dstRect,
						resizingMode, options);
 
					// TODO: if we revert the view color overlay handling
					//	in View::Draw() to the BeOS version, we never
					//	need to invalidate the view for overlays.
 
					// Invalidate view - but only if this is a non-overlay
					// switch
					if (bitmap == NULL || bitmap->Overlay() == NULL
						|| !wasOverlay) {
						BRegion dirty((BRect)fCurrentView->Bounds());
						fWindow->InvalidateView(fCurrentView, dirty);
					}
 
					if (bitmap != NULL && bitmap->Overlay() != NULL) {
						bitmap->Overlay()->SetFlags(options);
						colorKey = bitmap->Overlay()->Color();
					}
 
					if (bitmap != NULL)
						bitmap->ReleaseReference();
				} else
					status = B_BAD_VALUE;
			}
 
			fLink.StartMessage(status);
			if (status == B_OK && (options & AS_REQUEST_COLOR_KEY) != 0) {
				// Attach color key for the overlay bitmap
				fLink.Attach<rgb_color>(colorKey);
			}
 
			fLink.Flush();
			break;
		}
		case AS_VIEW_PRINT_ALIASING:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_PRINT_ALIASING: "
				"View: %s\n", Title(), fCurrentView->Name()));
 
			bool fontAliasing;
			if (link.Read<bool>(&fontAliasing) == B_OK) {
				fCurrentView->CurrentState()->SetForceFontAliasing(fontAliasing);
				_UpdateDrawState(fCurrentView);
			}
			break;
		}
		case AS_VIEW_CLIP_TO_PICTURE:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_CLIP_TO_PICTURE: "
				"View: %s\n", Title(), fCurrentView->Name()));
 
			int32 pictureToken;
			BPoint where;
			bool inverse = false;
 
			link.Read<int32>(&pictureToken);
			if (pictureToken < 0) {
				fCurrentView->SetAlphaMask(NULL);
				_UpdateDrawState(fCurrentView);
				break;
			}
 
			link.Read<BPoint>(&where);
			if (link.Read<bool>(&inverse) != B_OK)
				break;
 
			ServerPicture* picture = fServerApp->GetPicture(pictureToken);
			if (picture == NULL)
				break;
 
			AlphaMask* const mask = new(std::nothrow) PictureAlphaMask(
				fCurrentView->GetAlphaMask(), picture,
				*fCurrentView->CurrentState(), where, inverse);
			fCurrentView->SetAlphaMask(mask);
			if (mask != NULL)
				mask->ReleaseReference();
 
			_UpdateDrawState(fCurrentView);
 
			picture->ReleaseReference();
			break;
		}
 
		case AS_VIEW_GET_CLIP_REGION:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_CLIP_REGION: "
				"View: %s\n", Title(), fCurrentView->Name()));
 
			// if this view is hidden, it has no visible region
			fLink.StartMessage(B_OK);
			if (!fWindow->IsVisible() || !fCurrentView->IsVisible()) {
				BRegion empty;
				fLink.AttachRegion(empty);
			} else {
				_UpdateCurrentDrawingRegion();
				BRegion region(fCurrentDrawingRegion);
				fCurrentView->ScreenToLocalTransform().Apply(&region);
				fLink.AttachRegion(region);
			}
			fLink.Flush();
 
			break;
		}
		case AS_VIEW_SET_CLIP_REGION:
		{
			int32 rectCount;
			status_t status = link.Read<int32>(&rectCount);
				// a negative count means no
				// region for the current draw state,
				// but an *empty* region is actually valid!
				// even if it means no drawing is allowed
 
			if (status < B_OK)
				break;
 
			if (rectCount >= 0) {
				// we are supposed to set the clipping region
				BRegion region;
				if (rectCount > 0 && link.ReadRegion(&region) < B_OK)
					break;
 
				DTRACE(("ServerWindow %s: Message AS_VIEW_SET_CLIP_REGION: "
					"View: %s -> rect count: %" B_PRId32 ", frame = "
					"BRect(%.1f, %.1f, %.1f, %.1f)\n",
					Title(), fCurrentView->Name(), rectCount,
					region.Frame().left, region.Frame().top,
					region.Frame().right, region.Frame().bottom));
 
				fCurrentView->SetUserClipping(&region);
			} else {
				// we are supposed to unset the clipping region
				// passing NULL sets this states region to that
				// of the previous state
 
				DTRACE(("ServerWindow %s: Message AS_VIEW_SET_CLIP_REGION: "
					"View: %s -> unset\n", Title(), fCurrentView->Name()));
 
				fCurrentView->SetUserClipping(NULL);
			}
			fCurrentDrawingRegionValid = false;
 
			break;
		}
 
		case AS_VIEW_CLIP_TO_RECT:
		{
			bool inverse;
			BRect rect;
 
			link.Read<bool>(&inverse);
			link.Read<BRect>(&rect);
 
			bool needDrawStateUpdate = fCurrentView->ClipToRect(
				rect, inverse);
			fCurrentDrawingRegionValid = false;
 
			if (needDrawStateUpdate)
				_UpdateDrawState(fCurrentView);
 
			_UpdateCurrentDrawingRegion();
 
			BRegion region(fCurrentDrawingRegion);
			fCurrentView->ScreenToLocalTransform().Apply(&region);
 
			break;
		}
 
		case AS_VIEW_CLIP_TO_SHAPE:
		{
			bool inverse;
			link.Read<bool>(&inverse);
 
			shape_data shape;
			link.Read<int32>(&shape.opCount);
			link.Read<int32>(&shape.ptCount);
			shape.opSize = shape.opCount * sizeof(uint32);
			shape.ptSize = shape.ptCount * sizeof(BPoint);
			shape.opList = new(nothrow) uint32[shape.opCount];
			shape.ptList = new(nothrow) BPoint[shape.ptCount];
			if (link.Read(shape.opList, shape.opSize) >= B_OK
				&& link.Read(shape.ptList, shape.ptSize) >= B_OK) {
				fCurrentView->ClipToShape(&shape, inverse);
				_UpdateDrawState(fCurrentView);
			}
 
			delete[] shape.opList;
			delete[] shape.ptList;
			break;
		}
 
		case AS_VIEW_INVALIDATE_RECT:
		{
			// NOTE: looks like this call is NOT affected by origin and scale
			// on R5 so this implementation is "correct"
			BRect invalidRect;
			if (link.Read<BRect>(&invalidRect) == B_OK) {
				DTRACE(("ServerWindow %s: Message AS_VIEW_INVALIDATE_RECT: "
					"View: %s -> BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
					fCurrentView->Name(), invalidRect.left, invalidRect.top,
					invalidRect.right, invalidRect.bottom));
 
				View* view = NULL;
				if (link.Read<View*>(&view) != B_OK)
					view = fCurrentView;
 
				// make sure the view is still available!
				if (view != fCurrentView
					&& !fWindow->TopView()->HasView(view))
					break;
 
				BRegion dirty(invalidRect);
				fWindow->InvalidateView(view, dirty);
			}
			break;
		}
 
		case AS_VIEW_DELAYED_INVALIDATE_RECT:
		{
			bigtime_t time = 0;
			BRect invalidRect;
			if (link.Read<bigtime_t>(&time) == B_OK
				&& link.Read<BRect>(&invalidRect) == B_OK) {
				DTRACE(("ServerWindow %s: Message "
					"AS_VIEW_DELAYED_INVALIDATE_RECT: "
					"View: %s -> BRect(%.1f, %.1f, %.1f, %.1f) at time %llu\n",
					Title(), fCurrentView->Name(), invalidRect.left,
					invalidRect.top, invalidRect.right, invalidRect.bottom,
					time));
 
				DelayedMessage delayed(AS_VIEW_INVALIDATE_RECT, time, true);
				delayed.AddTarget(MessagePort());
				delayed.SetMerge(DM_MERGE_DUPLICATES);
 
				if (delayed.Attach<BRect>(invalidRect) == B_OK
						&& delayed.Attach<View*>(fCurrentView) == B_OK)
					delayed.Flush();
			}
			break;
		}
 
		case AS_VIEW_INVALIDATE_REGION:
		{
			// NOTE: looks like this call is NOT affected by origin and scale
			// on R5 so this implementation is "correct"
			BRegion region;
			if (link.ReadRegion(&region) < B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_VIEW_INVALIDATE_REGION: "
					"View: %s -> rect count: %" B_PRId32 ", frame: BRect(%.1f, "
					"%.1f, %.1f, %.1f)\n", Title(),
					fCurrentView->Name(), region.CountRects(),
					region.Frame().left, region.Frame().top,
					region.Frame().right, region.Frame().bottom));
 
			fWindow->InvalidateView(fCurrentView, region);
			break;
		}
 
		case AS_VIEW_DRAG_IMAGE:
		{
			// TODO: flesh out AS_VIEW_DRAG_IMAGE
			DTRACE(("ServerWindow %s: Message AS_DRAG_IMAGE\n", Title()));
 
			int32 bitmapToken;
			drawing_mode dragMode;
			BPoint offset;
			int32 bufferSize;
 
			link.Read<int32>(&bitmapToken);
			link.Read<int32>((int32*)&dragMode);
			link.Read<BPoint>(&offset);
			link.Read<int32>(&bufferSize);
 
			if (bufferSize > 0) {
				char* buffer = new (nothrow) char[bufferSize];
				BMessage dragMessage;
				if (link.Read(buffer, bufferSize) == B_OK
					&& dragMessage.Unflatten(buffer) == B_OK) {
						ServerBitmap* bitmap
							= fServerApp->GetBitmap(bitmapToken);
						// TODO: possible deadlock
fDesktop->UnlockSingleWindow();
						fDesktop->EventDispatcher().SetDragMessage(dragMessage,
							bitmap, offset);
fDesktop->LockSingleWindow();
						if (bitmap != NULL)
							bitmap->ReleaseReference();
				}
				delete[] buffer;
			}
			// sync the client (it can now delete the bitmap)
			fLink.StartMessage(B_OK);
			fLink.Flush();
 
			break;
		}
		case AS_VIEW_DRAG_RECT:
		{
			// TODO: flesh out AS_VIEW_DRAG_RECT
			DTRACE(("ServerWindow %s: Message AS_DRAG_RECT\n", Title()));
 
			BRect dragRect;
			BPoint offset;
			int32 bufferSize;
 
			link.Read<BRect>(&dragRect);
			link.Read<BPoint>(&offset);
			link.Read<int32>(&bufferSize);
 
			if (bufferSize > 0) {
				char* buffer = new (nothrow) char[bufferSize];
				BMessage dragMessage;
				if (link.Read(buffer, bufferSize) == B_OK
					&& dragMessage.Unflatten(buffer) == B_OK) {
						// TODO: possible deadlock
fDesktop->UnlockSingleWindow();
						fDesktop->EventDispatcher().SetDragMessage(dragMessage,
							NULL /* should be dragRect */, offset);
fDesktop->LockSingleWindow();
				}
				delete[] buffer;
			}
			break;
		}
 
		case AS_VIEW_BEGIN_RECT_TRACK:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_RECT_TRACK\n",
				Title()));
			BRect dragRect;
			uint32 style;
 
			link.Read<BRect>(&dragRect);
			link.Read<uint32>(&style);
 
			// TODO: implement rect tracking (used sometimes for selecting
			// a group of things, also sometimes used to appear to drag
			// something, but without real drag message)
			break;
		}
		case AS_VIEW_END_RECT_TRACK:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_END_RECT_TRACK\n",
				Title()));
			// TODO: implement rect tracking
			break;
		}
 
		case AS_VIEW_BEGIN_PICTURE:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_PICTURE\n",
				Title()));
			ServerPicture* picture = App()->CreatePicture();
			if (picture != NULL) {
				picture->SyncState(fCurrentView);
				fCurrentView->SetPicture(picture);
			}
			break;
		}
 
		case AS_VIEW_APPEND_TO_PICTURE:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_APPEND_TO_PICTURE\n",
				Title()));
 
			int32 token;
			link.Read<int32>(&token);
 
			ServerPicture* picture = App()->GetPicture(token);
			if (picture != NULL)
				picture->SyncState(fCurrentView);
 
			fCurrentView->SetPicture(picture);
 
			if (picture != NULL)
				picture->ReleaseReference();
			break;
		}
 
		case AS_VIEW_END_PICTURE:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_END_PICTURE\n",
				Title()));
 
			ServerPicture* picture = fCurrentView->Picture();
			if (picture != NULL) {
				fCurrentView->SetPicture(NULL);
				fLink.StartMessage(B_OK);
				fLink.Attach<int32>(picture->Token());
			} else
				fLink.StartMessage(B_ERROR);
 
			fLink.Flush();
			break;
		}
 
		case AS_VIEW_BEGIN_LAYER:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_LAYER\n",
				Title()));
 
			uint8 opacity;
			link.Read<uint8>(&opacity);
 
			Layer* layer = new(std::nothrow) Layer(opacity);
			if (layer == NULL)
				break;
 
			if (opacity != 255) {
				fCurrentView->CurrentState()->SetDrawingMode(B_OP_ALPHA);
				fCurrentView->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA,
					B_ALPHA_COMPOSITE);
				fCurrentView->CurrentState()->SetDrawingModeLocked(true);
			}
 
			fCurrentView->SetPicture(layer);
			break;
		}
 
		default:
			_DispatchViewDrawingMessage(code, link);
			break;
	}
}
 
 
/*!	Dispatches all view drawing messages.
	The desktop clipping must be read locked when entering this method.
	Requires a valid fCurrentView.
*/
void
ServerWindow::_DispatchViewDrawingMessage(int32 code,
	BPrivate::LinkReceiver &link)
{
	if (!fCurrentView->IsVisible() || !fWindow->IsVisible()) {
		if (link.NeedsReply()) {
			debug_printf("ServerWindow::DispatchViewDrawingMessage() got "
				"message %" B_PRId32 " that needs a reply!\n", code);
			// the client is now blocking and waiting for a reply!
			fLink.StartMessage(B_ERROR);
			fLink.Flush();
		}
		return;
	}
 
	DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
	if (!drawingEngine) {
		// ?!?
		debug_printf("ServerWindow %s: no drawing engine!!\n", Title());
		if (link.NeedsReply()) {
			// the client is now blocking and waiting for a reply!
			fLink.StartMessage(B_ERROR);
			fLink.Flush();
		}
		return;
	}
 
	_UpdateCurrentDrawingRegion();
	if (fCurrentDrawingRegion.CountRects() <= 0 && code != AS_VIEW_END_LAYER) {
			// If the command is AS_VIEW_END_LAYER, then we continue even if
			// the clipping region is empty. The layer itself might set a valid
			// clipping while its contents are drawn, and even if it doesn't,
			// we must still play back its picture so that we don't leak
			// nested layer instances.
 
		DTRACE(("ServerWindow %s: _DispatchViewDrawingMessage(): View: %s, "
			"INVALID CLIPPING!\n", Title(), fCurrentView->Name()));
		if (link.NeedsReply()) {
			// the client is now blocking and waiting for a reply!
			fLink.StartMessage(B_ERROR);
			fLink.Flush();
		}
		return;
	}
 
	drawingEngine->LockParallelAccess();
	// NOTE: the region is not copied, Painter keeps a pointer,
	// that's why you need to use the clipping only for as long
	// as you have it locked
	drawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion);
 
	switch (code) {
		case AS_STROKE_LINE:
		{
			ViewStrokeLineInfo info;
			if (link.Read<ViewStrokeLineInfo>(&info) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_STROKE_LINE: View: %s -> "
				"BPoint(%.1f, %.1f) - BPoint(%.1f, %.1f)\n", Title(),
					fCurrentView->Name(),
					info.startPoint.x, info.startPoint.y,
					info.endPoint.x, info.endPoint.y));
 
			BPoint penPos = info.endPoint;
			const SimpleTransform transform =
				fCurrentView->PenToScreenTransform();
			transform.Apply(&info.startPoint);
			transform.Apply(&info.endPoint);
			drawingEngine->StrokeLine(info.startPoint, info.endPoint);
 
			// We update the pen here because many DrawingEngine calls which
			// do not update the pen position actually call StrokeLine
 
			// TODO: Decide where to put this, for example, it cannot be done
			// for DrawString(), also there needs to be a decision, if the pen
			// location is in View coordinates (I think it should be) or in
			// screen coordinates.
			fCurrentView->CurrentState()->SetPenLocation(penPos);
			break;
		}
		case AS_VIEW_INVERT_RECT:
		{
			BRect rect;
			if (link.Read<BRect>(&rect) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_INVERT_RECT: View: %s -> "
				"BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
				fCurrentView->Name(), rect.left, rect.top, rect.right,
				rect.bottom));
 
			fCurrentView->PenToScreenTransform().Apply(&rect);
			drawingEngine->InvertRect(rect);
			break;
		}
		case AS_STROKE_RECT:
		{
			BRect rect;
			if (link.Read<BRect>(&rect) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_STROKE_RECT: View: %s -> "
				"BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
				fCurrentView->Name(), rect.left, rect.top, rect.right,
				rect.bottom));
 
			fCurrentView->PenToScreenTransform().Apply(&rect);
			drawingEngine->StrokeRect(rect);
			break;
		}
		case AS_FILL_RECT:
		{
			BRect rect;
			if (link.Read<BRect>(&rect) != B_OK)
				break;
 
			DTRACE(("ServerWindow %s: Message AS_FILL_RECT: View: %s -> "
				"BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
				fCurrentView->Name(), rect.left, rect.top, rect.right,
				rect.bottom));
 
			fCurrentView->PenToScreenTransform().Apply(&rect);
			drawingEngine->FillRect(rect);
			break;
		}
		case AS_FILL_RECT_GRADIENT:
		{
			BRect rect;
			link.Read<BRect>(&rect);
			BGradient* gradient;
			if (link.ReadGradient(&gradient) != B_OK)
				break;
 
			GTRACE(("ServerWindow %s: Message AS_FILL_RECT_GRADIENT: View: %s "
				"-> BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
				fCurrentView->Name(), rect.left, rect.top, rect.right,
				rect.bottom));
 
			const SimpleTransform transform =
				fCurrentView->PenToScreenTransform();
			transform.Apply(&rect);
			transform.Apply(gradient);
			drawingEngine->FillRect(rect, *gradient);
			delete gradient;
			break;
		}
		case AS_VIEW_DRAW_BITMAP:
		{
			ViewDrawBitmapInfo info;
			if (link.Read<ViewDrawBitmapInfo>(&info) != B_OK)
				break;
 
#if 0
			if (strcmp(fServerApp->SignatureLeaf(), "x-vnd.videolan-vlc") == 0)
				info.options |= B_FILTER_BITMAP_BILINEAR;
#endif
 
			ServerBitmap* bitmap = fServerApp->GetBitmap(info.bitmapToken);
			if (bitmap != NULL) {
				DTRACE(("ServerWindow %s: Message AS_VIEW_DRAW_BITMAP: "
					"View: %s, bitmap: %" B_PRId32 " (size %" B_PRId32 " x "
					"%" B_PRId32 "), BRect(%.1f, %.1f, %.1f, %.1f) -> "
					"BRect(%.1f, %.1f, %.1f, %.1f)\n",
					fTitle, fCurrentView->Name(), info.bitmapToken,
					bitmap->Width(), bitmap->Height(),
					info.bitmapRect.left, info.bitmapRect.top,
					info.bitmapRect.right, info.bitmapRect.bottom,
					info.viewRect.left, info.viewRect.top,
					info.viewRect.right, info.viewRect.bottom));
 
				fCurrentView->PenToScreenTransform().Apply(&info.viewRect);
 
// TODO: Unbreak...
//				if ((info.options & B_WAIT_FOR_RETRACE) != 0)
//					fDesktop->HWInterface()->WaitForRetrace(20000);
 
				drawingEngine->DrawBitmap(bitmap, info.bitmapRect,
					info.viewRect, info.options);
 
				bitmap->ReleaseReference();
			}
			break;
		}
		case AS_STROKE_ARC:
		case AS_FILL_ARC:
		{
			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ARC\n", Title()));
 
			float angle, span;
			BRect r;
 
			link.Read<BRect>(&r);
			link.Read<float>(&angle);
			if (link.Read<float>(&span) != B_OK)
				break;
 
			fCurrentView->PenToScreenTransform().Apply(&r);
			drawingEngine->DrawArc(r, angle, span, code == AS_FILL_ARC);
			break;
		}
		case AS_FILL_ARC_GRADIENT:
		{
			GTRACE(("ServerWindow %s: Message AS_FILL_ARC_GRADIENT\n",
				Title()));
 
			float angle, span;
			BRect r;
			link.Read<BRect>(&r);
			link.Read<float>(&angle);
			link.Read<float>(&span);
			BGradient* gradient;
			if (link.ReadGradient(&gradient) != B_OK)
				break;
			const SimpleTransform transform =
				fCurrentView->PenToScreenTransform();
			transform.Apply(&r);
			transform.Apply(gradient);
			drawingEngine->FillArc(r, angle, span, *gradient);
			delete gradient;
			break;
		}
		case AS_STROKE_BEZIER:
		case AS_FILL_BEZIER:
		{
			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_BEZIER\n",
				Title()));
 
			const SimpleTransform transform =
				fCurrentView->PenToScreenTransform();
			BPoint pts[4];
			status_t status;
			for (int32 i = 0; i < 4; i++) {
				status = link.Read<BPoint>(&(pts[i]));
				transform.Apply(&pts[i]);
			}
			if (status != B_OK)
				break;
 
			drawingEngine->DrawBezier(pts, code == AS_FILL_BEZIER);
			break;
		}
		case AS_FILL_BEZIER_GRADIENT:
		{
			GTRACE(("ServerWindow %s: Message AS_FILL_BEZIER_GRADIENT\n",
				Title()));
 
			const SimpleTransform transform =
				fCurrentView->PenToScreenTransform();
			BPoint pts[4];
			for (int32 i = 0; i < 4; i++) {
				link.Read<BPoint>(&(pts[i]));
				transform.Apply(&pts[i]);
			}
			BGradient* gradient;
			if (link.ReadGradient(&gradient) != B_OK)
				break;
			transform.Apply(gradient);
			drawingEngine->FillBezier(pts, *gradient);
			delete gradient;
			break;
		}
		case AS_STROKE_ELLIPSE:
		case AS_FILL_ELLIPSE:
		{
			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ELLIPSE\n",
				Title()));
 
			BRect rect;
			if (link.Read<BRect>(&rect) != B_OK)
				break;
 
			fCurrentView->PenToScreenTransform().Apply(&rect);
			drawingEngine->DrawEllipse(rect, code == AS_FILL_ELLIPSE);
			break;
		}
		case AS_FILL_ELLIPSE_GRADIENT:
		{
			GTRACE(("ServerWindow %s: Message AS_FILL_ELLIPSE_GRADIENT\n",
				Title()));
 
			BRect rect;
			link.Read<BRect>(&rect);
			BGradient* gradient;
			if (link.ReadGradient(&gradient) != B_OK)
				break;
			const SimpleTransform transform =
				fCurrentView->PenToScreenTransform();
			transform.Apply(&rect);
			transform.Apply(gradient);
			drawingEngine->FillEllipse(rect, *gradient);
			delete gradient;
			break;
		}
		case AS_STROKE_ROUNDRECT:
		case AS_FILL_ROUNDRECT:
		{
			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ROUNDRECT\n",
				Title()));
 
			BRect rect;
			float xRadius;
			float yRadius;
			link.Read<BRect>(&rect);
			link.Read<float>(&xRadius);
			if (link.Read<float>(&yRadius) != B_OK)
				break;
 
			fCurrentView->PenToScreenTransform().Apply(&rect);
			float scale = fCurrentView->CurrentState()->CombinedScale();
			drawingEngine->DrawRoundRect(rect, xRadius * scale, yRadius * scale,
				code == AS_FILL_ROUNDRECT);
			break;
		}
		case AS_FILL_ROUNDRECT_GRADIENT:
		{
			GTRACE(("ServerWindow %s: Message AS_FILL_ROUNDRECT_GRADIENT\n",
				Title()));
 
			BRect rect;
			float xrad,yrad;
			link.Read<BRect>(&rect);
			link.Read<float>(&xrad);
			link.Read<float>(&yrad);
			BGradient* gradient;
			if (link.ReadGradient(&gradient) != B_OK)
				break;
			const SimpleTransform transform =
				fCurrentView->PenToScreenTransform();
			transform.Apply(&rect);
			transform.Apply(gradient);
			drawingEngine->FillRoundRect(rect, xrad, yrad, *gradient);
			delete gradient;
			break;
		}
		case AS_STROKE_TRIANGLE:
		case AS_FILL_TRIANGLE:
		{
			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_TRIANGLE\n",
				Title()));
 
			const SimpleTransform transform =
				fCurrentView->PenToScreenTransform();
			BPoint pts[3];
			BRect rect;
 
			for (int32 i = 0; i < 3; i++) {
				link.Read<BPoint>(&(pts[i]));
				transform.Apply(&pts[i]);
			}
 
			if (link.Read<BRect>(&rect) != B_OK)
				break;
 
			transform.Apply(&rect);
			drawingEngine->DrawTriangle(pts, rect, code == AS_FILL_TRIANGLE);
			break;
		}
		case AS_FILL_TRIANGLE_GRADIENT:
		{
			DTRACE(("ServerWindow %s: Message AS_FILL_TRIANGLE_GRADIENT\n",
				Title()));
 
			const SimpleTransform transform =
				fCurrentView->PenToScreenTransform();
			BPoint pts[3];
			BRect rect;
			for (int32 i = 0; i < 3; i++) {
				link.Read<BPoint>(&(pts[i]));
				transform.Apply(&pts[i]);
			}
			link.Read<BRect>(&rect);
			BGradient* gradient;
			if (link.ReadGradient(&gradient) != B_OK)
				break;
			transform.Apply(&rect);
			transform.Apply(gradient);
			drawingEngine->FillTriangle(pts, rect, *gradient);
			delete gradient;
			break;
		}
		case AS_STROKE_POLYGON:
		case AS_FILL_POLYGON:
		{
			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_POLYGON\n",
				Title()));
 
			BRect polyFrame;
			bool isClosed = true;
			int32 pointCount;
 
			link.Read<BRect>(&polyFrame);
			if (code == AS_STROKE_POLYGON)
				link.Read<bool>(&isClosed);
			link.Read<int32>(&pointCount);
 
			const SimpleTransform transform =
				fCurrentView->PenToScreenTransform();
			BPoint* pointList = new(nothrow) BPoint[pointCount];
			if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) {
				for (int32 i = 0; i < pointCount; i++)
					transform.Apply(&pointList[i]);
				transform.Apply(&polyFrame);
 
				drawingEngine->DrawPolygon(pointList, pointCount, polyFrame,
					code == AS_FILL_POLYGON, isClosed && pointCount > 2);
			}
			delete[] pointList;
			break;
		}
		case AS_FILL_POLYGON_GRADIENT:
		{
			DTRACE(("ServerWindow %s: Message AS_FILL_POLYGON_GRADIENT\n",
				Title()));
 
			BRect polyFrame;
			bool isClosed = true;
			int32 pointCount;
			link.Read<BRect>(&polyFrame);
			link.Read<int32>(&pointCount);
 
			const SimpleTransform transform =
				fCurrentView->PenToScreenTransform();
			BPoint* pointList = new(nothrow) BPoint[pointCount];
			BGradient* gradient;
			if (link.Read(pointList, pointCount * sizeof(BPoint)) == B_OK
				&& link.ReadGradient(&gradient) == B_OK) {
				for (int32 i = 0; i < pointCount; i++)
					transform.Apply(&pointList[i]);
				transform.Apply(&polyFrame);
				transform.Apply(gradient);
 
				drawingEngine->FillPolygon(pointList, pointCount,
					polyFrame, *gradient, isClosed && pointCount > 2);
				delete gradient;
			}
			delete[] pointList;
			break;
		}
		case AS_STROKE_SHAPE:
		case AS_FILL_SHAPE:
		{
			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_SHAPE\n",
				Title()));
 
			BRect shapeFrame;
			int32 opCount;
			int32 ptCount;
 
			link.Read<BRect>(&shapeFrame);
			link.Read<int32>(&opCount);
			link.Read<int32>(&ptCount);
 
			uint32* opList = new(nothrow) uint32[opCount];
			BPoint* ptList = new(nothrow) BPoint[ptCount];
			if (link.Read(opList, opCount * sizeof(uint32)) >= B_OK &&
				link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) {
 
				// this might seem a bit weird, but under R5, the shapes
				// are always offset by the current pen location
				BPoint screenOffset
					= fCurrentView->CurrentState()->PenLocation();
				shapeFrame.OffsetBy(screenOffset);
 
				const SimpleTransform transform =
					fCurrentView->PenToScreenTransform();
				transform.Apply(&screenOffset);
				transform.Apply(&shapeFrame);
 
				drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount,
					ptList, code == AS_FILL_SHAPE, screenOffset,
					fCurrentView->Scale());
			}
 
			delete[] opList;
			delete[] ptList;
			break;
		}
		case AS_FILL_SHAPE_GRADIENT:
		{
			DTRACE(("ServerWindow %s: Message AS_FILL_SHAPE_GRADIENT\n",
				Title()));
 
			BRect shapeFrame;
			int32 opCount;
			int32 ptCount;
 
			link.Read<BRect>(&shapeFrame);
			link.Read<int32>(&opCount);
			link.Read<int32>(&ptCount);
 
			uint32* opList = new(nothrow) uint32[opCount];
			BPoint* ptList = new(nothrow) BPoint[ptCount];
			BGradient* gradient;
			if (link.Read(opList, opCount * sizeof(uint32)) == B_OK
				&& link.Read(ptList, ptCount * sizeof(BPoint)) == B_OK
				&& link.ReadGradient(&gradient) == B_OK) {
 
				// this might seem a bit weird, but under R5, the shapes
				// are always offset by the current pen location
				BPoint screenOffset
					= fCurrentView->CurrentState()->PenLocation();
				shapeFrame.OffsetBy(screenOffset);
 
				const SimpleTransform transform =
					fCurrentView->PenToScreenTransform();
				transform.Apply(&screenOffset);
				transform.Apply(&shapeFrame);
				transform.Apply(gradient);
				drawingEngine->FillShape(shapeFrame, opCount, opList,
					ptCount, ptList, *gradient, screenOffset,
					fCurrentView->Scale());
				delete gradient;
			}
 
			delete[] opList;
			delete[] ptList;
			break;
		}
		case AS_FILL_REGION:
		{
			DTRACE(("ServerWindow %s: Message AS_FILL_REGION\n", Title()));
 
			BRegion region;
			if (link.ReadRegion(&region) < B_OK)
				break;
 
			fCurrentView->PenToScreenTransform().Apply(&region);
			drawingEngine->FillRegion(region);
 
			break;
		}
		case AS_FILL_REGION_GRADIENT:
		{
			DTRACE(("ServerWindow %s: Message AS_FILL_REGION_GRADIENT\n",
				Title()));
 
			BRegion region;
			link.ReadRegion(&region);
 
			BGradient* gradient;
			if (link.ReadGradient(&gradient) != B_OK)
				break;
 
			const SimpleTransform transform =
				fCurrentView->PenToScreenTransform();
			transform.Apply(&region);
			transform.Apply(gradient);
			drawingEngine->FillRegion(region, *gradient);
			delete gradient;
			break;
		}
		case AS_STROKE_LINEARRAY:
		{
			DTRACE(("ServerWindow %s: Message AS_STROKE_LINEARRAY\n",
				Title()));
 
			// Attached Data:
			// 1) int32 Number of lines in the array
			// 2) LineArrayData
 
			int32 lineCount;
			if (link.Read<int32>(&lineCount) != B_OK || lineCount <= 0)
				break;
 
			// To speed things up, try to use a stack allocation and only
			// fall back to the heap if there are enough lines...
			ViewLineArrayInfo* lineData;
			const int32 kStackBufferLineDataCount = 64;
			ViewLineArrayInfo lineDataStackBuffer[kStackBufferLineDataCount];
			if (lineCount > kStackBufferLineDataCount) {
				lineData = new(std::nothrow) ViewLineArrayInfo[lineCount];
				if (lineData == NULL)
					break;
			} else
				lineData = lineDataStackBuffer;
 
			// Read them all in one go
			size_t dataSize = lineCount * sizeof(ViewLineArrayInfo);
			if (link.Read(lineData, dataSize) != B_OK) {
				if (lineData != lineDataStackBuffer)
					delete[] lineData;
				break;
			}
 
			// Convert to screen coords and draw
			const SimpleTransform transform =
				fCurrentView->PenToScreenTransform();
			for (int32 i = 0; i < lineCount; i++) {
				transform.Apply(&lineData[i].startPoint);
				transform.Apply(&lineData[i].endPoint);
			}
			drawingEngine->StrokeLineArray(lineCount, lineData);
 
			if (lineData != lineDataStackBuffer)
				delete[] lineData;
			break;
		}
		case AS_DRAW_STRING:
		case AS_DRAW_STRING_WITH_DELTA:
		{
			ViewDrawStringInfo info;
			if (link.Read<ViewDrawStringInfo>(&info) != B_OK
				|| info.stringLength <= 0) {
				break;
			}
 
			const ssize_t kMaxStackStringSize = 4096;
			char stackString[kMaxStackStringSize];
			char* string = stackString;
			if (info.stringLength >= kMaxStackStringSize) {
				// NOTE: Careful, the + 1 is for termination!
				string = (char*)malloc((info.stringLength + 1 + 63) / 64 * 64);
				if (string == NULL)
					break;
			}
 
			escapement_delta* delta = NULL;
			if (code == AS_DRAW_STRING_WITH_DELTA) {
				// In this case, info.delta will contain valid values.
				delta = &info.delta;
			}
 
			if (link.Read(string, info.stringLength) != B_OK) {
				if (string != stackString)
					free(string);
				break;
			}
			// Terminate the string, if nothing else, it's important
			// for the DTRACE call below...
			string[info.stringLength] = '\0';
 
			DTRACE(("ServerWindow %s: Message AS_DRAW_STRING, View: %s "
				"-> %s\n", Title(), fCurrentView->Name(), string));
 
			fCurrentView->PenToScreenTransform().Apply(&info.location);
			BPoint penLocation = drawingEngine->DrawString(string,
				info.stringLength, info.location, delta);
 
			fCurrentView->ScreenToPenTransform().Apply(&penLocation);
			fCurrentView->CurrentState()->SetPenLocation(penLocation);
 
			if (string != stackString)
				free(string);
			break;
		}
		case AS_DRAW_STRING_WITH_OFFSETS:
		{
			int32 stringLength;
			if (link.Read<int32>(&stringLength) != B_OK || stringLength <= 0)
				break;
 
			int32 glyphCount;
			if (link.Read<int32>(&glyphCount) != B_OK || glyphCount <= 0)
				break;
 
			const ssize_t kMaxStackStringSize = 512;
			char stackString[kMaxStackStringSize];
			char* string = stackString;
			BPoint stackLocations[kMaxStackStringSize];
			BPoint* locations = stackLocations;
			MemoryDeleter stringDeleter;
			MemoryDeleter locationsDeleter;
			if (stringLength >= kMaxStackStringSize) {
				// NOTE: Careful, the + 1 is for termination!
				string = (char*)malloc((stringLength + 1 + 63) / 64 * 64);
				if (string == NULL)
					break;
				stringDeleter.SetTo(string);
			}
			if (glyphCount > kMaxStackStringSize) {
				locations = (BPoint*)malloc(
					((glyphCount * sizeof(BPoint)) + 63) / 64 * 64);
				if (locations == NULL)
					break;
				locationsDeleter.SetTo(locations);
			}
 
			if (link.Read(string, stringLength) != B_OK)
				break;
			// Count UTF8 glyphs and make sure we have enough locations
			if ((int32)UTF8CountChars(string, stringLength) > glyphCount)
				break;
			if (link.Read(locations, glyphCount * sizeof(BPoint)) != B_OK)
				break;
			// Terminate the string, if nothing else, it's important
			// for the DTRACE call below...
			string[stringLength] = '\0';
 
			DTRACE(("ServerWindow %s: Message AS_DRAW_STRING_WITH_OFFSETS, View: %s "
				"-> %s\n", Title(), fCurrentView->Name(), string));
 
			const SimpleTransform transform =
				fCurrentView->PenToScreenTransform();
			for (int32 i = 0; i < glyphCount; i++)
				transform.Apply(&locations[i]);
 
			BPoint penLocation = drawingEngine->DrawString(string,
				stringLength, locations);
 
			fCurrentView->ScreenToPenTransform().Apply(&penLocation);
			fCurrentView->CurrentState()->SetPenLocation(penLocation);
 
			break;
		}
 
		case AS_VIEW_DRAW_PICTURE:
		{
			int32 token;
			link.Read<int32>(&token);
 
			BPoint where;
			if (link.Read<BPoint>(&where) == B_OK) {
				ServerPicture* picture = App()->GetPicture(token);
				if (picture != NULL) {
					// Setting the drawing origin outside of the
					// state makes sure that everything the picture
					// does is relative to the global picture offset.
					fCurrentView->PushState();
					fCurrentView->SetDrawingOrigin(where);
 
					fCurrentView->PushState();
					picture->Play(fCurrentView);
					fCurrentView->PopState();
 
					fCurrentView->PopState();
 
					picture->ReleaseReference();
				}
			}
			break;
		}
 
		case AS_VIEW_END_LAYER:
		{
			DTRACE(("ServerWindow %s: Message AS_VIEW_END_LAYER\n",
				Title()));
 
			fCurrentView->BlendAllLayers();
			fCurrentView->SetPicture(NULL);
			fCurrentView->CurrentState()->SetDrawingModeLocked(false);
			break;
		}
 
		default:
			BString codeString;
			string_for_message_code(code, codeString);
			debug_printf("ServerWindow %s received unexpected code: %s\n",
				Title(), codeString.String());
 
			if (link.NeedsReply()) {
				// the client is now blocking and waiting for a reply!
				fLink.StartMessage(B_ERROR);
				fLink.Flush();
			}
			break;
	}
 
	drawingEngine->UnlockParallelAccess();
}
 
 
bool
ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link)
{
	ServerPicture* picture = fCurrentView->Picture();
	if (picture == NULL)
		return false;
 
	switch (code) {
		case AS_VIEW_SET_ORIGIN:
		{
			float x, y;
			link.Read<float>(&x);
			link.Read<float>(&y);
 
			picture->WriteSetOrigin(BPoint(x, y));
			break;
		}
 
		case AS_VIEW_INVERT_RECT:
		{
			BRect rect;
			link.Read<BRect>(&rect);
			picture->WriteInvertRect(rect);
			break;
		}
 
		case AS_VIEW_PUSH_STATE:
		{
			picture->WritePushState();
			break;
		}
 
		case AS_VIEW_POP_STATE:
		{
			picture->WritePopState();
			break;
		}
 
		case AS_VIEW_SET_DRAWING_MODE:
		{
			int8 drawingMode;
			link.Read<int8>(&drawingMode);
 
			picture->WriteSetDrawingMode((drawing_mode)drawingMode);
 
			fCurrentView->CurrentState()->SetDrawingMode(
				(drawing_mode)drawingMode);
			fWindow->GetDrawingEngine()->SetDrawingMode(
				(drawing_mode)drawingMode);
			break;
		}
 
		case AS_VIEW_SET_PEN_LOC:
		{
			BPoint location;
			link.Read<BPoint>(&location);
			picture->WriteSetPenLocation(location);
 
			fCurrentView->CurrentState()->SetPenLocation(location);
			break;
		}
 
		case AS_VIEW_SET_PEN_SIZE:
		{
			float penSize;
			link.Read<float>(&penSize);
			picture->WriteSetPenSize(penSize);
 
			fCurrentView->CurrentState()->SetPenSize(penSize);
			fWindow->GetDrawingEngine()->SetPenSize(
				fCurrentView->CurrentState()->PenSize());
			break;
		}
 
		case AS_VIEW_SET_LINE_MODE:
		{
 
			ViewSetLineModeInfo info;
			link.Read<ViewSetLineModeInfo>(&info);
 
			picture->WriteSetLineMode(info.lineCap, info.lineJoin,
				info.miterLimit);
 
			fCurrentView->CurrentState()->SetLineCapMode(info.lineCap);
			fCurrentView->CurrentState()->SetLineJoinMode(info.lineJoin);
			fCurrentView->CurrentState()->SetMiterLimit(info.miterLimit);
 
			fWindow->GetDrawingEngine()->SetStrokeMode(info.lineCap,
				info.lineJoin, info.miterLimit);
			break;
		}
		case AS_VIEW_SET_SCALE:
		{
			float scale;
			if (link.Read<float>(&scale) != B_OK)
				break;
 
			picture->WriteSetScale(scale);
 
			fCurrentView->SetScale(scale);
			_UpdateDrawState(fCurrentView);
			break;
		}
		case AS_VIEW_SET_TRANSFORM:
		{
			BAffineTransform transform;
			if (link.Read<BAffineTransform>(&transform) != B_OK)
				break;
 
			picture->WriteSetTransform(transform);
 
			fCurrentView->CurrentState()->SetTransform(transform);
			_UpdateDrawState(fCurrentView);
			break;
		}
 
		case AS_VIEW_AFFINE_TRANSLATE:
		{
			double x, y;
			link.Read<double>(&x);
			link.Read<double>(&y);
 
			picture->WriteTranslateBy(x, y);
 
			BAffineTransform current =
				fCurrentView->CurrentState()->Transform();
			current.PreTranslateBy(x, y);
			fCurrentView->CurrentState()->SetTransform(current);
			_UpdateDrawState(fCurrentView);
			break;
		}
 
		case AS_VIEW_AFFINE_SCALE:
		{
			double x, y;
			link.Read<double>(&x);
			link.Read<double>(&y);
 
			picture->WriteScaleBy(x, y);
 
			BAffineTransform current =
				fCurrentView->CurrentState()->Transform();
			current.PreScaleBy(x, y);
			fCurrentView->CurrentState()->SetTransform(current);
			_UpdateDrawState(fCurrentView);
			break;
		}
 
		case AS_VIEW_AFFINE_ROTATE:
		{
			double angleRadians;
			link.Read<double>(&angleRadians);
 
			picture->WriteRotateBy(angleRadians);
 
			BAffineTransform current =
				fCurrentView->CurrentState()->Transform();
			current.PreRotateBy(angleRadians);
			fCurrentView->CurrentState()->SetTransform(current);
			_UpdateDrawState(fCurrentView);
			break;
		}
 
 
		case AS_VIEW_SET_PATTERN:
		{
			pattern pat;
			link.Read(&pat, sizeof(pattern));
			picture->WriteSetPattern(pat);
			break;
		}
 
		case AS_VIEW_SET_FONT_STATE:
		{
			uint16 mask = fCurrentView->CurrentState()->ReadFontFromLink(link);
			fWindow->GetDrawingEngine()->SetFont(
				fCurrentView->CurrentState());
 
			picture->WriteFontState(fCurrentView->CurrentState()->Font(), mask);
			break;
		}
 
		case AS_FILL_RECT:
		case AS_STROKE_RECT:
		{
			BRect rect;
			link.Read<BRect>(&rect);
 
			picture->WriteDrawRect(rect, code == AS_FILL_RECT);
			break;
		}
 
		case AS_FILL_REGION:
		{
			// There is no B_PIC_FILL_REGION op, we have to
			// implement it using B_PIC_FILL_RECT
			BRegion region;
			if (link.ReadRegion(&region) < B_OK)
				break;
			for (int32 i = 0; i < region.CountRects(); i++)
				picture->WriteDrawRect(region.RectAt(i), true);
			break;
		}
 
		case AS_STROKE_ROUNDRECT:
		case AS_FILL_ROUNDRECT:
		{
			BRect rect;
			link.Read<BRect>(&rect);
 
			BPoint radii;
			link.Read<float>(&radii.x);
			link.Read<float>(&radii.y);
 
			picture->WriteDrawRoundRect(rect, radii, code == AS_FILL_ROUNDRECT);
			break;
		}
 
		case AS_STROKE_ELLIPSE:
		case AS_FILL_ELLIPSE:
		{
			BRect rect;
			link.Read<BRect>(&rect);
			picture->WriteDrawEllipse(rect, code == AS_FILL_ELLIPSE);
			break;
		}
 
		case AS_STROKE_ARC:
		case AS_FILL_ARC:
		{
			BRect rect;
			link.Read<BRect>(&rect);
			float startTheta, arcTheta;
			link.Read<float>(&startTheta);
			link.Read<float>(&arcTheta);
 
			BPoint radii((rect.Width() + 1) / 2, (rect.Height() + 1) / 2);
			BPoint center = rect.LeftTop() + radii;
 
			picture->WriteDrawArc(center, radii, startTheta, arcTheta,
				code == AS_FILL_ARC);
			break;
		}
 
		case AS_STROKE_TRIANGLE:
		case AS_FILL_TRIANGLE:
		{
			// There is no B_PIC_FILL/STROKE_TRIANGLE op,
			// we implement it using B_PIC_FILL/STROKE_POLYGON
			BPoint points[3];
 
			for (int32 i = 0; i < 3; i++) {
				link.Read<BPoint>(&(points[i]));
			}
 
			BRect rect;
			link.Read<BRect>(&rect);
 
			picture->WriteDrawPolygon(3, points,
					true, code == AS_FILL_TRIANGLE);
			break;
		}
		case AS_STROKE_POLYGON:
		case AS_FILL_POLYGON:
		{
			BRect polyFrame;
			bool isClosed = true;
			int32 pointCount;
			const bool fill = (code == AS_FILL_POLYGON);
 
			link.Read<BRect>(&polyFrame);
			if (code == AS_STROKE_POLYGON)
				link.Read<bool>(&isClosed);
			link.Read<int32>(&pointCount);
 
			BPoint* pointList = new(nothrow) BPoint[pointCount];
			if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) {
				picture->WriteDrawPolygon(pointCount, pointList,
					isClosed && pointCount > 2, fill);
			}
			delete[] pointList;
			break;
		}
 
		case AS_STROKE_BEZIER:
		case AS_FILL_BEZIER:
		{
			BPoint points[4];
			for (int32 i = 0; i < 4; i++) {
				link.Read<BPoint>(&(points[i]));
			}
			picture->WriteDrawBezier(points, code == AS_FILL_BEZIER);
			break;
		}
 
		case AS_STROKE_LINE:
		{
			ViewStrokeLineInfo info;
			link.Read<ViewStrokeLineInfo>(&info);
 
			picture->WriteStrokeLine(info.startPoint, info.endPoint);
 
			BPoint penPos = info.endPoint;
			const SimpleTransform transform =
				fCurrentView->PenToScreenTransform();
			transform.Apply(&info.endPoint);
			fCurrentView->CurrentState()->SetPenLocation(penPos);
			break;
		}
 
		case AS_STROKE_LINEARRAY:
		{
			int32 lineCount;
			if (link.Read<int32>(&lineCount) != B_OK || lineCount <= 0)
				break;
 
			// To speed things up, try to use a stack allocation and only
			// fall back to the heap if there are enough lines...
			ViewLineArrayInfo* lineData;
			const int32 kStackBufferLineDataCount = 64;
			ViewLineArrayInfo lineDataStackBuffer[kStackBufferLineDataCount];
			if (lineCount > kStackBufferLineDataCount) {
				lineData = new(std::nothrow) ViewLineArrayInfo[lineCount];
				if (lineData == NULL)
					break;
			} else
				lineData = lineDataStackBuffer;
 
			// Read them all in one go
			size_t dataSize = lineCount * sizeof(ViewLineArrayInfo);
			if (link.Read(lineData, dataSize) != B_OK) {
				if (lineData != lineDataStackBuffer)
					delete[] lineData;
				break;
			}
 
			picture->WritePushState();
 
			for (int32 i = 0; i < lineCount; i++) {
				picture->WriteSetHighColor(lineData[i].color);
				picture->WriteStrokeLine(lineData[i].startPoint,
					lineData[i].endPoint);
			}
 
			picture->WritePopState();
 
			if (lineData != lineDataStackBuffer)
				delete[] lineData;
			break;
		}
 
		case AS_VIEW_SET_LOW_COLOR:
		case AS_VIEW_SET_HIGH_COLOR:
		{
			rgb_color color;
			link.Read(&color, sizeof(rgb_color));
 
			if (code == AS_VIEW_SET_HIGH_COLOR) {
				picture->WriteSetHighColor(color);
				fCurrentView->CurrentState()->SetHighColor(color);
				fWindow->GetDrawingEngine()->SetHighColor(color);
			} else {
				picture->WriteSetLowColor(color);
				fCurrentView->CurrentState()->SetLowColor(color);
				fWindow->GetDrawingEngine()->SetLowColor(color);
			}
		}	break;
 
		case AS_DRAW_STRING:
		case AS_DRAW_STRING_WITH_DELTA:
		{
			ViewDrawStringInfo info;
			if (link.Read<ViewDrawStringInfo>(&info) != B_OK)
				break;
 
			char* string = (char*)malloc(info.stringLength + 1);
			if (string == NULL)
				break;
 
			if (code != AS_DRAW_STRING_WITH_DELTA) {
				// In this case, info.delta will NOT contain valid values.
				info.delta = (escapement_delta){ 0, 0 };
			}
 
			if (link.Read(string, info.stringLength) != B_OK) {
				free(string);
				break;
			}
			// Terminate the string
			string[info.stringLength] = '\0';
 
			picture->WriteDrawString(info.location, string, info.stringLength,
				info.delta);
 
			// We need to update the pen location
			fCurrentView->PenToScreenTransform().Apply(&info.location);
			BPoint penLocation = fWindow->GetDrawingEngine()->DrawStringDry(
				string, info.stringLength, info.location, &info.delta);
 
			fCurrentView->ScreenToPenTransform().Apply(&penLocation);
			fCurrentView->CurrentState()->SetPenLocation(penLocation);
 
			free(string);
			break;
		}
 
		case AS_DRAW_STRING_WITH_OFFSETS:
		{
			int32 stringLength;
			if (link.Read<int32>(&stringLength) != B_OK || stringLength <= 0)
				break;
 
			int32 glyphCount;
			if (link.Read<int32>(&glyphCount) != B_OK || glyphCount <= 0)
				break;
 
			const ssize_t kMaxStackStringSize = 512;
			char stackString[kMaxStackStringSize];
			char* string = stackString;
			BPoint stackLocations[kMaxStackStringSize];
			BPoint* locations = stackLocations;
			MemoryDeleter stringDeleter;
			MemoryDeleter locationsDeleter;
			if (stringLength >= kMaxStackStringSize) {
				// NOTE: Careful, the + 1 is for termination!
				string = (char*)malloc((stringLength + 1 + 63) / 64 * 64);
				if (string == NULL)
					break;
				stringDeleter.SetTo(string);
			}
			if (glyphCount > kMaxStackStringSize) {
				locations = (BPoint*)malloc(
					((glyphCount * sizeof(BPoint)) + 63) / 64 * 64);
				if (locations == NULL)
					break;
				locationsDeleter.SetTo(locations);
			}
 
			if (link.Read(string, stringLength) != B_OK)
				break;
			// Count UTF8 glyphs and make sure we have enough locations
			if ((int32)UTF8CountChars(string, stringLength) > glyphCount)
				break;
			if (link.Read(locations, glyphCount * sizeof(BPoint)) != B_OK)
				break;
			// Terminate the string
			string[stringLength] = '\0';
 
			const SimpleTransform transform =
				fCurrentView->PenToScreenTransform();
			for (int32 i = 0; i < glyphCount; i++)
				transform.Apply(&locations[i]);
 
			picture->WriteDrawString(string, stringLength, locations,
				glyphCount);
 
			// Update pen location
			BPoint penLocation = fWindow->GetDrawingEngine()->DrawStringDry(
				string, stringLength, locations);
 
			fCurrentView->ScreenToPenTransform().Apply(&penLocation);
			fCurrentView->CurrentState()->SetPenLocation(penLocation);
 
			break;
		}
 
		case AS_STROKE_SHAPE:
		case AS_FILL_SHAPE:
		{
			BRect shapeFrame;
			int32 opCount;
			int32 ptCount;
 
			link.Read<BRect>(&shapeFrame);
			link.Read<int32>(&opCount);
			link.Read<int32>(&ptCount);
 
			uint32* opList = new(std::nothrow) uint32[opCount];
			BPoint* ptList = new(std::nothrow) BPoint[ptCount];
			if (opList != NULL && ptList != NULL
				&& link.Read(opList, opCount * sizeof(uint32)) >= B_OK
				&& link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) {
				// This might seem a bit weird, but under BeOS, the shapes
				// are always offset by the current pen location
				BPoint penLocation
					= fCurrentView->CurrentState()->PenLocation();
				for (int32 i = 0; i < ptCount; i++) {
					ptList[i] += penLocation;
				}
				const bool fill = (code == AS_FILL_SHAPE);
				picture->WriteDrawShape(opCount, opList, ptCount, ptList, fill);
			}
 
			delete[] opList;
			delete[] ptList;
			break;
		}
 
		case AS_VIEW_DRAW_BITMAP:
		{
			ViewDrawBitmapInfo info;
			link.Read<ViewDrawBitmapInfo>(&info);
 
			ServerBitmap* bitmap = App()->GetBitmap(info.bitmapToken);
			if (bitmap == NULL)
				break;
 
			picture->WriteDrawBitmap(info.bitmapRect, info.viewRect,
				bitmap->Width(), bitmap->Height(), bitmap->BytesPerRow(),
				bitmap->ColorSpace(), info.options, bitmap->Bits(),
				bitmap->BitsLength());
 
			bitmap->ReleaseReference();
			break;
		}
 
		case AS_VIEW_DRAW_PICTURE:
		{
			int32 token;
			link.Read<int32>(&token);
 
			BPoint where;
			if (link.Read<BPoint>(&where) == B_OK) {
				ServerPicture* pictureToDraw = App()->GetPicture(token);
				if (pictureToDraw != NULL) {
					// We need to make a copy of the picture, since it can
					// change after it has been drawn
					ServerPicture* copy = App()->CreatePicture(pictureToDraw);
					picture->NestPicture(copy);
					picture->WriteDrawPicture(where, copy->Token());
 
					pictureToDraw->ReleaseReference();
				}
			}
			break;
		}
 
		case AS_VIEW_SET_CLIP_REGION:
		{
			int32 rectCount;
			status_t status = link.Read<int32>(&rectCount);
				// a negative count means no
				// region for the current draw state,
				// but an *empty* region is actually valid!
				// even if it means no drawing is allowed
 
			if (status < B_OK)
				break;
 
			if (rectCount >= 0) {
				// we are supposed to set the clipping region
				BRegion region;
				if (rectCount > 0 && link.ReadRegion(&region) < B_OK)
					break;
				picture->WriteSetClipping(region);
			} else {
				// we are supposed to clear the clipping region
				picture->WriteClearClipping();
			}
			break;
		}
 
		case AS_VIEW_CLIP_TO_PICTURE:
		{
			int32 pictureToken;
			BPoint where;
			bool inverse = false;
 
			link.Read<int32>(&pictureToken);
			if (pictureToken < 0)
				break;
 
			link.Read<BPoint>(&where);
			if (link.Read<bool>(&inverse) != B_OK)
				break;
 
			ServerPicture* pictureToClip = fServerApp->GetPicture(pictureToken);
			if (pictureToClip != NULL) {
				// We need to make a copy of the picture, since it can
				// change after it has been drawn
				ServerPicture* copy = App()->CreatePicture(pictureToClip);
				picture->NestPicture(copy);
				picture->WriteClipToPicture(copy->Token(), where, inverse);
 
				pictureToClip->ReleaseReference();
			}
			break;
		}
 
		case AS_VIEW_CLIP_TO_RECT:
		{
			bool inverse;
			BRect rect;
			link.Read<bool>(&inverse);
			link.Read<BRect>(&rect);
			picture->WriteClipToRect(rect, inverse);
 
			break;
		}
 
		case AS_VIEW_CLIP_TO_SHAPE:
		{
			bool inverse;
			link.Read<bool>(&inverse);
 
			shape_data shape;
			link.Read<int32>(&shape.opCount);
			link.Read<int32>(&shape.ptCount);
			shape.opSize = shape.opCount * sizeof(uint32);
			shape.ptSize = shape.ptCount * sizeof(BPoint);
			shape.opList = new(nothrow) uint32[shape.opCount];
			shape.ptList = new(nothrow) BPoint[shape.ptCount];
			if (link.Read(shape.opList, shape.opSize) >= B_OK
				&& link.Read(shape.ptList, shape.ptSize) >= B_OK) {
				picture->WriteClipToShape(shape.opCount, shape.opList,
					shape.ptCount, shape.ptList, inverse);
			}
 
			delete[] shape.opList;
			delete[] shape.ptList;
			break;
		}
 
		case AS_VIEW_BEGIN_PICTURE:
		{
			ServerPicture* newPicture = App()->CreatePicture();
			if (newPicture != NULL) {
				newPicture->PushPicture(picture);
				newPicture->SyncState(fCurrentView);
				fCurrentView->SetPicture(newPicture);
			}
			break;
		}
 
		case AS_VIEW_APPEND_TO_PICTURE:
		{
			int32 token;
			link.Read<int32>(&token);
 
			ServerPicture* appendPicture = App()->GetPicture(token);
			if (appendPicture != NULL) {
				//picture->SyncState(fCurrentView);
				appendPicture->AppendPicture(picture);
			}
 
			fCurrentView->SetPicture(appendPicture);
 
			if (appendPicture != NULL)
				appendPicture->ReleaseReference();
			break;
		}
 
		case AS_VIEW_END_PICTURE:
		{
			ServerPicture* poppedPicture = picture->PopPicture();
			fCurrentView->SetPicture(poppedPicture);
			if (poppedPicture != NULL)
				poppedPicture->ReleaseReference();
 
			fLink.StartMessage(B_OK);
			fLink.Attach<int32>(picture->Token());
			fLink.Flush();
			return true;
		}
 
		case AS_VIEW_BEGIN_LAYER:
		{
			uint8 opacity;
			link.Read<uint8>(&opacity);
 
			Layer* layer = dynamic_cast<Layer*>(picture);
			if (layer == NULL)
				break;
 
			Layer* nextLayer = new(std::nothrow) Layer(opacity);
			if (nextLayer == NULL)
				break;
 
			if (opacity != 255) {
				fCurrentView->CurrentState()->SetDrawingMode(B_OP_ALPHA);
				fCurrentView->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA,
					B_ALPHA_COMPOSITE);
				fCurrentView->CurrentState()->SetDrawingModeLocked(true);
			}
 
			nextLayer->PushLayer(layer);
			fCurrentView->SetPicture(nextLayer);
			break;
		}
 
		case AS_VIEW_END_LAYER:
		{
			Layer* layer = dynamic_cast<Layer*>(picture);
			if (layer == NULL)
				break;
 
			Layer* previousLayer = layer->PopLayer();
			if (previousLayer == NULL) {
				// End last layer
				return false;
			}
			fCurrentView->SetPicture(previousLayer);
 
			previousLayer->WriteBlendLayer(layer);
			break;
		}
 
/*
		case AS_VIEW_SET_BLENDING_MODE:
		{
			ViewBlendingModeInfo info;
			link.Read<ViewBlendingModeInfo>(&info);
 
			picture->BeginOp(B_PIC_SET_BLENDING_MODE);
			picture->AddInt16((int16)info.sourceAlpha);
			picture->AddInt16((int16)info.alphaFunction);
			picture->EndOp();
 
			fCurrentView->CurrentState()->SetBlendingMode(info.sourceAlpha,
				info.alphaFunction);
			fWindow->GetDrawingEngine()->SetBlendingMode(info.sourceAlpha,
				info.alphaFunction);
			break;
		}*/
		default:
			return false;
	}
 
	if (link.NeedsReply()) {
		fLink.StartMessage(B_ERROR);
		fLink.Flush();
	}
	return true;
}
 
 
/*!	\brief Message-dispatching loop for the ServerWindow
 
	Watches the ServerWindow's message port and dispatches as necessary
*/
void
ServerWindow::_MessageLooper()
{
	// Send a reply to our window - it is expecting fMessagePort
	// port and some other info.
 
	fLink.StartMessage(B_OK);
	fLink.Attach<port_id>(fMessagePort);
 
	int32 minWidth, maxWidth, minHeight, maxHeight;
	fWindow->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight);
 
	fLink.Attach<BRect>(fWindow->Frame());
	fLink.Attach<float>((float)minWidth);
	fLink.Attach<float>((float)maxWidth);
	fLink.Attach<float>((float)minHeight);
	fLink.Attach<float>((float)maxHeight);
	fLink.Flush();
 
	BPrivate::LinkReceiver& receiver = fLink.Receiver();
	bool quitLoop = false;
 
	while (!quitLoop) {
		//STRACE(("info: ServerWindow::MonitorWin listening on port %ld.\n",
		//	fMessagePort));
 
		int32 code;
		status_t status = receiver.GetNextMessage(code);
		if (status != B_OK) {
			// that shouldn't happen, it's our port
			printf("Someone deleted our message port!\n");
 
			// try to let our client die happily
			NotifyQuitRequested();
			break;
		}
 
#ifdef PROFILE_MESSAGE_LOOP
		bigtime_t start = system_time();
#endif
 
		Lock();
 
#ifdef PROFILE_MESSAGE_LOOP
		bigtime_t diff = system_time() - start;
		if (diff > 10000) {
			printf("ServerWindow %s: lock acquisition took %" B_PRId64 " usecs\n",
				Title(), diff);
		}
#endif
 
		int32 messagesProcessed = 0;
		bigtime_t processingStart = system_time();
		bool lockedDesktopSingleWindow = false;
 
		while (true) {
			if (code == AS_DELETE_WINDOW || code == kMsgQuitLooper) {
				// this means the client has been killed
				DTRACE(("ServerWindow %s received 'AS_DELETE_WINDOW' message "
					"code\n", Title()));
 
				if (code == AS_DELETE_WINDOW) {
					fLink.StartMessage(B_OK);
					fLink.Flush();
				}
 
				if (lockedDesktopSingleWindow)
					fDesktop->UnlockSingleWindow();
 
				quitLoop = true;
 
				// ServerWindow's destructor takes care of pulling this object
				// off the desktop.
				ASSERT(fWindow->IsHidden());
				break;
			}
 
			// Acquire the appropriate lock
			bool needsAllWindowsLocked = _MessageNeedsAllWindowsLocked(code);
			if (needsAllWindowsLocked) {
				// We may already still hold the read-lock from the previous
				// inner-loop iteration.
				if (lockedDesktopSingleWindow) {
					fDesktop->UnlockSingleWindow();
					lockedDesktopSingleWindow = false;
				}
				fDesktop->LockAllWindows();
			} else {
				// We never keep the write-lock across inner-loop iterations,
				// so there is nothing else to do besides read-locking unless
				// we already have the read-lock from the previous iteration.
				if (!lockedDesktopSingleWindow) {
					fDesktop->LockSingleWindow();
					lockedDesktopSingleWindow = true;
				}
			}
 
			if (atomic_and(&fRedrawRequested, 0) != 0) {
#ifdef PROFILE_MESSAGE_LOOP
				bigtime_t redrawStart = system_time();
#endif
				fWindow->RedrawDirtyRegion();
#ifdef PROFILE_MESSAGE_LOOP
				diff = system_time() - redrawStart;
				atomic_add(&sRedrawProcessingTime.count, 1);
# ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
				atomic_add64(&sRedrawProcessingTime.time, diff);
# else
				sRedrawProcessingTime.time += diff;
# endif
#endif
			}
 
#ifdef PROFILE_MESSAGE_LOOP
			bigtime_t dispatchStart = system_time();
#endif
			_DispatchMessage(code, receiver);
 
#ifdef PROFILE_MESSAGE_LOOP
			if (code >= 0 && code < AS_LAST_CODE) {
				diff = system_time() - dispatchStart;
				atomic_add(&sMessageProfile[code].count, 1);
#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
				atomic_add64(&sMessageProfile[code].time, diff);
#else
				sMessageProfile[code].time += diff;
#endif
				if (diff > 10000) {
					printf("ServerWindow %s: message %" B_PRId32 " took %"
						B_PRId64 " usecs\n", Title(), code, diff);
				}
			}
#endif
 
			if (needsAllWindowsLocked)
				fDesktop->UnlockAllWindows();
 
			// Only process up to 70 waiting messages at once (we have the
			// Desktop locked), but don't hold the lock longer than 10 ms
			if (!receiver.HasMessages() || ++messagesProcessed > 70
				|| system_time() - processingStart > 10000) {
				if (lockedDesktopSingleWindow)
					fDesktop->UnlockSingleWindow();
				break;
			}
 
			// next message
			status_t status = receiver.GetNextMessage(code);
			if (status != B_OK) {
				// that shouldn't happen, it's our port
				printf("Someone deleted our message port!\n");
				if (lockedDesktopSingleWindow)
					fDesktop->UnlockSingleWindow();
 
				// try to let our client die happily
				NotifyQuitRequested();
				break;
			}
		}
 
		Unlock();
	}
 
	// We were asked to quit the message loop - either on request or because of
	// an error.
	Quit();
		// does not return
}
 
 
void
ServerWindow::ScreenChanged(const BMessage* message)
{
	SendMessageToClient(message);
 
	if (fDirectWindowInfo != NULL && fDirectWindowInfo->IsFullScreen())
		_ResizeToFullScreen();
}
 
 
status_t
ServerWindow::SendMessageToClient(const BMessage* msg, int32 target) const
{
	if (target == B_NULL_TOKEN)
		target = fClientToken;
 
	BMessenger reply;
	BMessage::Private messagePrivate((BMessage*)msg);
	return messagePrivate.SendMessage(fClientLooperPort, fClientTeam, target,
		0, false, reply);
}
 
 
Window*
ServerWindow::MakeWindow(BRect frame, const char* name,
	window_look look, window_feel feel, uint32 flags, uint32 workspace)
{
	// The non-offscreen ServerWindow uses the DrawingEngine instance from
	// the desktop.
	return new(std::nothrow) ::Window(frame, name, look, feel, flags,
		workspace, this, fDesktop->HWInterface()->CreateDrawingEngine());
}
 
 
void
ServerWindow::HandleDirectConnection(int32 bufferState, int32 driverState)
{
	ASSERT_MULTI_LOCKED(fDesktop->WindowLocker());
 
	if (fDirectWindowInfo == NULL)
		return;
 
	STRACE(("HandleDirectConnection(bufferState = %" B_PRId32 ", driverState = "
		"%" B_PRId32 ")\n", bufferState, driverState));
 
	status_t status = fDirectWindowInfo->SetState(
		(direct_buffer_state)bufferState, (direct_driver_state)driverState,
		fDesktop->HWInterface()->FrontBuffer(), fWindow->Frame(),
		fWindow->VisibleContentRegion());
 
	if (status != B_OK) {
		char errorString[256];
		snprintf(errorString, sizeof(errorString),
			"%s killed for a problem in DirectConnected(): %s",
			App()->Signature(), strerror(status));
		syslog(LOG_ERR, errorString);
 
		// The client application didn't release the semaphore
		// within the given timeout. Or something else went wrong.
		// Deleting this member should make it crash.
		delete fDirectWindowInfo;
		fDirectWindowInfo = NULL;
	} else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_START)
		fIsDirectlyAccessing = true;
	else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_STOP)
		fIsDirectlyAccessing = false;
}
 
 
void
ServerWindow::_SetCurrentView(View* view)
{
	if (fCurrentView == view)
		return;
 
	fCurrentView = view;
	fCurrentDrawingRegionValid = false;
	_UpdateDrawState(fCurrentView);
 
#if 0
#if DELAYED_BACKGROUND_CLEARING
	if (fCurrentView && fCurrentView->IsBackgroundDirty()
		&& fWindow->InUpdate()) {
		DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
		if (drawingEngine->LockParallelAccess()) {
			fWindow->GetEffectiveDrawingRegion(fCurrentView,
				fCurrentDrawingRegion);
			fCurrentDrawingRegionValid = true;
			BRegion dirty(fCurrentDrawingRegion);
 
			BRegion content;
			fWindow->GetContentRegion(&content);
 
			fCurrentView->Draw(drawingEngine, &dirty, &content, false);
 
			drawingEngine->UnlockParallelAccess();
		}
	}
#endif
#endif // 0
}
 
 
void
ServerWindow::_UpdateDrawState(View* view)
{
	// switch the drawing state
	// TODO: is it possible to scroll a view while it
	// is being drawn? probably not... otherwise the
	// "offsets" passed below would need to be updated again
	DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
	if (view != NULL && drawingEngine != NULL) {
		BPoint leftTop(0, 0);
		if (view->GetAlphaMask() != NULL) {
			view->LocalToScreenTransform().Apply(&leftTop);
			view->GetAlphaMask()->SetCanvasGeometry(leftTop, view->Bounds());
			leftTop = BPoint(0, 0);
		}
		view->PenToScreenTransform().Apply(&leftTop);
		drawingEngine->SetDrawState(view->CurrentState(), leftTop.x, leftTop.y);
	}
}
 
 
void
ServerWindow::_UpdateCurrentDrawingRegion()
{
	if (!fCurrentDrawingRegionValid
		|| fWindow->DrawingRegionChanged(fCurrentView)) {
		fWindow->GetEffectiveDrawingRegion(fCurrentView, fCurrentDrawingRegion);
		fCurrentDrawingRegionValid = true;
	}
}
 
 
bool
ServerWindow::_MessageNeedsAllWindowsLocked(uint32 code) const
{
	switch (code) {
		case AS_SET_WINDOW_TITLE:
		case AS_ADD_TO_SUBSET:
		case AS_REMOVE_FROM_SUBSET:
		case AS_VIEW_CREATE_ROOT:
		case AS_VIEW_CREATE:
		case AS_SEND_BEHIND:
		case AS_SET_LOOK:
		case AS_SET_FEEL:
		case AS_SET_FLAGS:
		case AS_SET_WORKSPACES:
		case AS_WINDOW_MOVE:
		case AS_WINDOW_RESIZE:
		case AS_SET_SIZE_LIMITS:
		case AS_SYSTEM_FONT_CHANGED:
		case AS_SET_DECORATOR_SETTINGS:
		case AS_GET_MOUSE:
		case AS_DIRECT_WINDOW_SET_FULLSCREEN:
//		case AS_VIEW_SET_EVENT_MASK:
//		case AS_VIEW_SET_MOUSE_EVENT_MASK:
		case AS_TALK_TO_DESKTOP_LISTENER:
			return true;
		default:
			return false;
	}
}
 
 
void
ServerWindow::_ResizeToFullScreen()
{
	BRect screenFrame;
 
	{
		AutoReadLocker _(fDesktop->ScreenLocker());
		const Screen* screen = fWindow->Screen();
		if (screen == NULL)
			return;
 
		screenFrame = fWindow->Screen()->Frame();
	}
 
	fDesktop->MoveWindowBy(fWindow,
		screenFrame.left - fWindow->Frame().left,
		screenFrame.top - fWindow->Frame().top);
	fDesktop->ResizeWindowBy(fWindow,
		screenFrame.Width() - fWindow->Frame().Width(),
		screenFrame.Height() - fWindow->Frame().Height());
}
 
 
status_t
ServerWindow::_EnableDirectWindowMode()
{
	if (fDirectWindowInfo != NULL) {
		// already in direct window mode
		return B_ERROR;
	}
 
	if (fDesktop->HWInterface()->FrontBuffer() == NULL) {
		// direct window mode not supported
		return B_UNSUPPORTED;
	}
 
	fDirectWindowInfo = new(std::nothrow) DirectWindowInfo;
	if (fDirectWindowInfo == NULL)
		return B_NO_MEMORY;
 
	status_t status = fDirectWindowInfo->InitCheck();
	if (status != B_OK) {
		delete fDirectWindowInfo;
		fDirectWindowInfo = NULL;
 
		return status;
	}
 
	return B_OK;
}
 
 
void
ServerWindow::_DirectWindowSetFullScreen(bool enable)
{
	window_feel feel = kWindowScreenFeel;
 
	if (enable) {
		fDesktop->HWInterface()->SetCursorVisible(false);
 
		fDirectWindowInfo->EnableFullScreen(fWindow->Frame(), fWindow->Feel());
		_ResizeToFullScreen();
	} else {
		const BRect& originalFrame = fDirectWindowInfo->OriginalFrame();
 
		fDirectWindowInfo->DisableFullScreen();
 
		// Resize window back to its original size
		fDesktop->MoveWindowBy(fWindow,
			originalFrame.left - fWindow->Frame().left,
			originalFrame.top - fWindow->Frame().top);
		fDesktop->ResizeWindowBy(fWindow,
			originalFrame.Width() - fWindow->Frame().Width(),
			originalFrame.Height() - fWindow->Frame().Height());
 
		fDesktop->HWInterface()->SetCursorVisible(true);
	}
 
	fDesktop->SetWindowFeel(fWindow, feel);
}

V630 The 'malloc' function is used to allocate memory for an array of objects which are classes containing constructors.

V630 The 'malloc' function is used to allocate memory for an array of objects which are classes containing constructors.