root/src/servers/app/ServerWindow.cpp
/*
 * 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 <StackOrHeapArray.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),
        fWindowAddedToDesktop(false),

        fClientTeam(app->ClientTeam()),

        fMessagePort(-1),
        fClientReplyPort(clientPort),
        fClientLooperPort(looperPort),

        fClientToken(clientToken),

        fCurrentView(NULL),
        fCurrentDrawingRegion(),
        fCurrentDrawingRegionValid(false),

        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));

        BPrivate::gDefaultTokens.RemoveToken(fServerToken);

        if (!fWindow->IsOffscreenWindow()) {
                fWindowAddedToDesktop = false;
                fDesktop->RemoveWindow(fWindow.Get());
                fDesktop = NULL;
        }

        if (App() != NULL) {
                App()->RemoveWindow(this);
                fServerApp = NULL;
        }

        fWindow.Unset(); // TODO: is it really needed?

        free(fTitle);
        delete_port(fMessagePort);

        fDirectWindowInfo.Unset(); // TODO: is it really needed?
        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);

        int32 count = profiles.CountItems();
        for (int32 i = 0; i < count; i++) {
                profile* p = (profile*)profiles.ItemAtFast(i);
                printf("[%s] called %" B_PRId32 " times, %g secs (%" B_PRId64 " usecs "
                        "per call)\n", string_for_message_code(p->code), 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.SetTo(MakeWindow(frame, fTitle, look, feel, flags, workspace));
        if (!fWindow.IsSet() || fWindow->InitCheck() != B_OK) {
                fWindow.Unset();
                return B_NO_MEMORY;
        }

        if (!fWindow->IsOffscreenWindow()) {
                fDesktop->AddWindow(fWindow.Get());
                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.Get();
}


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.Get());
        if (fDirectWindowInfo.IsSet() && 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.Get());
        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.IsSet())
                fDesktop->SetWindowTitle(fWindow.Get(), 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.Get(), 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.Get());
                        else
                                fDesktop->SendWindowBehind(fWindow.Get(), 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.Get(), 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.Get(), 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.Get(), 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.Get(), (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.Get(), (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.Get(), 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.Get();
                        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.Get(), 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.Get(),
                                        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.Get(),
                                        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.Get(), 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.IsSet() && 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.Get(), 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.Get());
                        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.IsSet())
                                _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.Get(), 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) {
                                debug_printf("ServerWindow %s received unexpected code - "
                                        "message '%s' before top_view attached.\n",
                                        Title(), string_for_message_code(code));
                                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,
                                fServerApp->FontManager());
                        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.Get());
                                        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, expose;
                        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, expose);
                        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, expose;
                        fCurrentView->ResizeBy(deltaWidth, deltaHeight, &dirty);

                        // TODO: see above
                        if (View* parent = fCurrentView->Parent())
                                parent->RebuildClipping(false);

                        fWindow->MarkContentDirty(dirty, expose);
                        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.ReadAffineTransform(&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.AttachAffineTransform(transform);
                        fLink.Flush();
                        break;
                }
                case AS_VIEW_GET_PARENT_COMPOSITE:
                {
                        DrawState* state = fCurrentView->CurrentState()->PreviousState();

                        fLink.StartMessage(B_OK);
                        if (state != NULL) {
                                fLink.AttachAffineTransform(state->CombinedTransform());
                                fLink.Attach<float>(state->CombinedScale());
                                fLink.Attach<BPoint>(state->CombinedOrigin());
                        } else {
                                fLink.AttachAffineTransform(BAffineTransform());
                                fLink.Attach<float>(1.0f);
                                fLink.Attach<BPoint>(B_ORIGIN);
                        }
                        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) {
                                BReference<ServerBitmap> bitmap(fServerApp->GetBitmap(bitmapToken), true);
                                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();
                                        }
                                } 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;

                        BReference<ServerPicture> picture(fServerApp->GetPicture(pictureToken), true);
                        if (picture == NULL)
                                break;

                        BReference<AlphaMask> const mask(new(std::nothrow) PictureAlphaMask(
                                fCurrentView->GetAlphaMask(), picture,
                                *fCurrentView->CurrentState(), where, inverse), true);
                        fCurrentView->SetAlphaMask(mask);

                        _UpdateDrawState(fCurrentView);
                        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:
                {
                        bool hasClipRegion;
                        status_t status = link.Read<bool>(&hasClipRegion);

                        if (status < B_OK)
                                break;

                        if (hasClipRegion) {
                                // we are supposed to set the clipping region
                                BRegion region;
                                if (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) {
                                                BReference<ServerBitmap> bitmap(
                                                        fServerApp->GetBitmap(bitmapToken), true);
                                                // TODO: possible deadlock
fDesktop->UnlockSingleWindow();
                                                fDesktop->EventDispatcher().SetDragMessage(dragMessage,
                                                        bitmap, offset);
fDesktop->LockSingleWindow();
                                }
                                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()));
                        BReference<ServerPicture> picture(App()->CreatePicture(), true);
                        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);

                        BReference<ServerPicture> picture(App()->GetPicture(token), true);
                        if (picture != NULL)
                                picture->SyncState(fCurrentView);

                        fCurrentView->SetPicture(picture);

                        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:
                        // The drawing code handles allocation failures using exceptions;
                        // so we need to account for that here.
                        try {
                                _DispatchViewDrawingMessage(code, link);
                        } catch (std::bad_alloc&) {
                                // Cancel any message we were in the middle of sending.
                                fLink.CancelMessage();

                                if (link.NeedsReply()) {
                                        // As done in _DispatchViewDrawingMessage, send just a
                                        // single status_t as the reply.
                                        fLink.StartMessage(B_NO_MEMORY);
                                        fLink.Flush();
                                }
                        }
                        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_STROKE_LINE_GRADIENT:
                {
                        ViewStrokeLineInfo info;
                        if (link.Read<ViewStrokeLineInfo>(&info) != B_OK)
                                break;

                        BGradient* gradient;
                        if (link.ReadGradient(&gradient) != B_OK)
                                break;

                        ObjectDeleter<BGradient> gradientDeleter(gradient);

                        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, *gradient);

                        // 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_STROKE_RECT_GRADIENT:
                {
                        BRect rect;
                        link.Read<BRect>(&rect);
                        BGradient* gradient;
                        if (link.ReadGradient(&gradient) != B_OK)
                                break;

                        GTRACE(("ServerWindow %s: Message AS_STROKE_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->StrokeRect(rect, *gradient);
                        delete gradient;
                        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

                        BReference<ServerBitmap> bitmap(fServerApp->GetBitmap(info.bitmapToken), true);
                        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);
                        }
                        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_STROKE_ARC_GRADIENT:
                case AS_FILL_ARC_GRADIENT:
                {
                        GTRACE(("ServerWindow %s: Message AS_STROKE/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->DrawArc(r, angle, span, code == AS_FILL_ARC_GRADIENT, *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_STROKE_BEZIER_GRADIENT:
                case AS_FILL_BEZIER_GRADIENT:
                {
                        GTRACE(("ServerWindow %s: Message AS_STROKE/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->DrawBezier(pts, code == AS_FILL_BEZIER_GRADIENT, *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_STROKE_ELLIPSE_GRADIENT:
                case AS_FILL_ELLIPSE_GRADIENT:
                {
                        GTRACE(("ServerWindow %s: Message AS_STROKE/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->DrawEllipse(rect, code == AS_FILL_ELLIPSE_GRADIENT, *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_STROKE_ROUNDRECT_GRADIENT:
                case AS_FILL_ROUNDRECT_GRADIENT:
                {
                        GTRACE(("ServerWindow %s: Message AS_FILL_STROKE/FILL_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->DrawRoundRect(rect, xrad, yrad, code == AS_FILL_ROUNDRECT_GRADIENT,
                                *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_STROKE_TRIANGLE_GRADIENT:
                case AS_FILL_TRIANGLE_GRADIENT:
                {
                        DTRACE(("ServerWindow %s: Message AS_STROKE/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->DrawTriangle(pts, rect, code == AS_FILL_TRIANGLE_GRADIENT, *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_STROKE_POLYGON_GRADIENT:
                case AS_FILL_POLYGON_GRADIENT:
                {
                        DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_POLYGON_GRADIENT\n",
                                Title()));

                        BRect polyFrame;
                        bool isClosed = true;
                        int32 pointCount;
                        link.Read<BRect>(&polyFrame);
                        if (code == AS_STROKE_POLYGON_GRADIENT)
                                link.Read<bool>(&isClosed);
                        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->DrawPolygon(pointList, pointCount,
                                        polyFrame, code == AS_FILL_POLYGON_GRADIENT, isClosed && pointCount > 2,
                                        *gradient);
                                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_STROKE_SHAPE_GRADIENT:
                case AS_FILL_SHAPE_GRADIENT:
                {
                        DTRACE(("ServerWindow %s: Message AS_STROKE/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->DrawShape(shapeFrame, opCount, opList,
                                        ptCount, ptList, code == AS_FILL_SHAPE_GRADIENT, *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;
                        }

                        // NOTE: Careful, the + 1 is for termination!
                        BStackOrHeapArray<char, 4096> string(
                                (info.stringLength + 1 + 63) / 64 * 64);
                        if (!string.IsValid())
                                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)
                                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);

                        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;

                        // NOTE: Careful, the + 1 is for termination!
                        BStackOrHeapArray<char, 512> string(
                                (stringLength + 1 + 63) / 64 * 64);
                        BStackOrHeapArray<BPoint, 512> locations(glyphCount);
                        if (!string.IsValid() || !locations.IsValid())
                                break;

                        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) {
                                BReference<ServerPicture> picture(App()->GetPicture(token), true);
                                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();
                                }
                        }
                        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:
                        debug_printf("ServerWindow %s received unexpected code: %s\n",
                                Title(), string_for_message_code(code));

                        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);

                        fCurrentView->SetDrawingOrigin(BPoint(x, 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:
                {
                        fCurrentView->PushState();
                        picture->WritePushState();
                        break;
                }

                case AS_VIEW_POP_STATE:
                {
                        fCurrentView->PopState();
                        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_FILL_RULE:
                {
                        int32 fillRule;
                        if (link.Read<int32>(&fillRule) != B_OK)
                                break;

                        picture->WriteSetFillRule(fillRule);

                        fCurrentView->CurrentState()->SetFillRule(fillRule);
                        fWindow->GetDrawingEngine()->SetFillRule(fillRule);

                        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.ReadAffineTransform(&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_RECT_GRADIENT:
                case AS_FILL_RECT_GRADIENT:
                {
                        BRect rect;
                        link.Read<BRect>(&rect);
                        BGradient* gradient;
                        if (link.ReadGradient(&gradient) != B_OK)
                                break;
                        ObjectDeleter<BGradient> gradientDeleter(gradient);

                        picture->WriteDrawRectGradient(rect, *gradient, code == AS_FILL_RECT_GRADIENT);
                        break;
                }

                case AS_STROKE_ARC_GRADIENT:
                case AS_FILL_ARC_GRADIENT:
                {
                        BRect rect;
                        link.Read<BRect>(&rect);
                        float startTheta, arcTheta;
                        link.Read<float>(&startTheta);
                        link.Read<float>(&arcTheta);
                        BGradient* gradient;
                        if (link.ReadGradient(&gradient) != B_OK)
                                break;
                        ObjectDeleter<BGradient> gradientDeleter(gradient);

                        BPoint radii((rect.Width() + 1) / 2, (rect.Height() + 1) / 2);
                        BPoint center = rect.LeftTop() + radii;

                        picture->WriteDrawArcGradient(center, radii, startTheta, arcTheta, *gradient,
                                code == AS_FILL_ARC_GRADIENT);
                        break;
                }

                case AS_STROKE_BEZIER_GRADIENT:
                case AS_FILL_BEZIER_GRADIENT:
                {
                        BPoint points[4];
                        for (int32 i = 0; i < 4; i++) {
                                link.Read<BPoint>(&(points[i]));
                        }
                        BGradient* gradient;
                        if (link.ReadGradient(&gradient) != B_OK)
                                break;
                        ObjectDeleter<BGradient> gradientDeleter(gradient);

                        picture->WriteDrawBezierGradient(points, *gradient, code == AS_FILL_BEZIER_GRADIENT);
                        break;
                }

                case AS_STROKE_ELLIPSE_GRADIENT:
                case AS_FILL_ELLIPSE_GRADIENT:
                {
                        BRect rect;
                        link.Read<BRect>(&rect);
                        BGradient* gradient;
                        if (link.ReadGradient(&gradient) != B_OK)
                                break;
                        ObjectDeleter<BGradient> gradientDeleter(gradient);

                        picture->WriteDrawEllipseGradient(rect, *gradient, code == AS_FILL_ELLIPSE_GRADIENT);
                        break;
                }

                case AS_STROKE_ROUNDRECT_GRADIENT:
                case AS_FILL_ROUNDRECT_GRADIENT:
                {
                        BRect rect;
                        link.Read<BRect>(&rect);

                        BPoint radii;
                        link.Read<float>(&radii.x);
                        link.Read<float>(&radii.y);
                        BGradient* gradient;
                        if (link.ReadGradient(&gradient) != B_OK)
                                break;
                        ObjectDeleter<BGradient> gradientDeleter(gradient);

                        picture->WriteDrawRoundRectGradient(rect, radii, *gradient, code == AS_FILL_ROUNDRECT_GRADIENT);
                        break;
                }

                case AS_STROKE_TRIANGLE_GRADIENT:
                case AS_FILL_TRIANGLE_GRADIENT:
                {
                        // 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);
                        BGradient* gradient;
                        if (link.ReadGradient(&gradient) != B_OK)
                                break;
                        ObjectDeleter<BGradient> gradientDeleter(gradient);

                        picture->WriteDrawPolygonGradient(3, points,
                                        true, *gradient, code == AS_FILL_TRIANGLE_GRADIENT);
                        break;
                }

                case AS_STROKE_POLYGON_GRADIENT:
                case AS_FILL_POLYGON_GRADIENT:
                {
                        BRect polyFrame;
                        bool isClosed = true;
                        int32 pointCount;
                        const bool fill = (code == AS_FILL_POLYGON_GRADIENT);

                        link.Read<BRect>(&polyFrame);
                        if (code == AS_STROKE_POLYGON_GRADIENT)
                                link.Read<bool>(&isClosed);
                        link.Read<int32>(&pointCount);

                        ArrayDeleter<BPoint> pointList(new(nothrow) BPoint[pointCount]);
                        if (link.Read(pointList.Get(), pointCount * sizeof(BPoint)) != B_OK)
                                break;

                        BGradient* gradient;
                        if (link.ReadGradient(&gradient) != B_OK)
                                break;
                        ObjectDeleter<BGradient> gradientDeleter(gradient);

                        picture->WriteDrawPolygonGradient(pointCount, pointList.Get(),
                                isClosed && pointCount > 2, *gradient, fill);
                        break;
                }

                case AS_STROKE_SHAPE_GRADIENT:
                case AS_FILL_SHAPE_GRADIENT:
                {
                        BRect shapeFrame;
                        int32 opCount;
                        int32 ptCount;

                        link.Read<BRect>(&shapeFrame);
                        link.Read<int32>(&opCount);
                        link.Read<int32>(&ptCount);

                        ArrayDeleter<uint32> opList(new(std::nothrow) uint32[opCount]);
                        ArrayDeleter<BPoint> ptList(new(std::nothrow) BPoint[ptCount]);
                        if (!opList.IsSet() || !ptList.IsSet()
                                || link.Read(opList.Get(), opCount * sizeof(uint32)) != B_OK
                                || link.Read(ptList.Get(), ptCount * sizeof(BPoint)) != B_OK)
                                break;

                        BGradient* gradient;
                        if (link.ReadGradient(&gradient) != B_OK)
                                break;
                        ObjectDeleter<BGradient> gradientDeleter(gradient);

                        // 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.Get()[i] += penLocation;
                        }
                        const bool fill = (code == AS_FILL_SHAPE_GRADIENT);
                        picture->WriteDrawShapeGradient(opCount, opList.Get(), ptCount, ptList.Get(), *gradient, fill);

                        break;
                }

                case AS_FILL_REGION_GRADIENT:
                {
                        // 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;

                        BGradient* gradient;
                        if (link.ReadGradient(&gradient) != B_OK)
                                break;
                        ObjectDeleter<BGradient> gradientDeleter(gradient);

                        for (int32 i = 0; i < region.CountRects(); i++)
                                picture->WriteDrawRectGradient(region.RectAt(i), *gradient, true);
                        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_LINE_GRADIENT:
                {
                        ViewStrokeLineInfo info;
                        link.Read<ViewStrokeLineInfo>(&info);

                        BGradient* gradient;
                        if (link.ReadGradient(&gradient) != B_OK)
                                break;
                        ObjectDeleter<BGradient> gradientDeleter(gradient);

                        picture->WriteStrokeLineGradient(info.startPoint, info.endPoint, *gradient);

                        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);
                        DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
                        if (drawingEngine->LockParallelAccess()) {
                                BPoint penLocation = drawingEngine->DrawStringDry(
                                        string, info.stringLength, info.location, &info.delta);

                                fCurrentView->ScreenToPenTransform().Apply(&penLocation);
                                fCurrentView->CurrentState()->SetPenLocation(penLocation);

                                drawingEngine->UnlockParallelAccess();
                        }

                        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;

                        // NOTE: Careful, the + 1 is for termination!
                        BStackOrHeapArray<char, 512> string(
                                (stringLength + 1 + 63) / 64 * 64);
                        BStackOrHeapArray<BPoint, 512> locations(glyphCount);
                        if (!string.IsValid() || !locations.IsValid())
                                break;

                        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);

                        DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
                        if (drawingEngine->LockParallelAccess()) {
                                // Update pen location
                                BPoint penLocation = drawingEngine->DrawStringDry(
                                        string, stringLength, locations);

                                fCurrentView->ScreenToPenTransform().Apply(&penLocation);
                                fCurrentView->CurrentState()->SetPenLocation(penLocation);

                                drawingEngine->UnlockParallelAccess();
                        }

                        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);

                        BStackOrHeapArray<uint32, 512> opList(opCount);
                        BStackOrHeapArray<BPoint, 512> ptList(ptCount);
                        if (!opList.IsValid() || !ptList.IsValid()
                                || link.Read(opList, opCount * sizeof(uint32)) < B_OK
                                || link.Read(ptList, ptCount * sizeof(BPoint)) < B_OK) {
                                break;
                        }
                        picture->WriteDrawShape(opCount, opList, ptCount,
                                ptList, code == AS_FILL_SHAPE);

                        break;
                }

                case AS_VIEW_DRAW_BITMAP:
                {
                        ViewDrawBitmapInfo info;
                        link.Read<ViewDrawBitmapInfo>(&info);

                        BReference<ServerBitmap> bitmap(App()->GetBitmap(info.bitmapToken), true);
                        if (bitmap == NULL)
                                break;

                        picture->WriteDrawBitmap(info.bitmapRect, info.viewRect,
                                bitmap->Width(), bitmap->Height(), bitmap->BytesPerRow(),
                                bitmap->ColorSpace(), info.options, bitmap->Bits(),
                                bitmap->BitsLength());

                        break;
                }

                case AS_VIEW_DRAW_PICTURE:
                {
                        int32 token;
                        link.Read<int32>(&token);

                        BPoint where;
                        if (link.Read<BPoint>(&where) == B_OK) {
                                BReference<ServerPicture> pictureToDraw(App()->GetPicture(token), true);
                                if (pictureToDraw != NULL) {
                                        // We need to make a copy of the picture, since it can
                                        // change after it has been drawn
                                        BReference<ServerPicture> copy(App()->CreatePicture(pictureToDraw), true);
                                        int32 subPictureIndex = picture->NestPicture(copy);
                                        if (subPictureIndex >= 0)
                                                picture->WriteDrawPicture(where, subPictureIndex);
                                }
                        }
                        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;

                        BReference<ServerPicture> pictureToClip(fServerApp->GetPicture(pictureToken), true);
                        if (pictureToClip != NULL) {
                                // We need to make a copy of the picture, since it can
                                // change after it has been drawn
                                BReference<ServerPicture> copy(App()->CreatePicture(pictureToClip), true);
                                int32 subPictureIndex = picture->NestPicture(copy);
                                if (subPictureIndex >= 0)
                                        picture->WriteClipToPicture(subPictureIndex, where, inverse);
                        }
                        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:
                {
                        BReference <ServerPicture> newPicture(App()->CreatePicture(), true);
                        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);

                        BReference<ServerPicture> appendPicture(App()->GetPicture(token), true);
                        if (appendPicture != NULL) {
                                //picture->SyncState(fCurrentView);
                                appendPicture->AppendPicture(picture);
                        }

                        fCurrentView->SetPicture(appendPicture);

                        break;
                }

                case AS_VIEW_END_PICTURE:
                {
                        BReference<ServerPicture> poppedPicture(picture->PopPicture(), true);
                        fCurrentView->SetPicture(poppedPicture);

                        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;

                        BReference<Layer> previousLayer(layer->PopLayer(), true);
                        if (previousLayer == NULL) {
                                // End last layer
                                return false;
                        }
                        fCurrentView->SetPicture(previousLayer);

                        previousLayer->WriteBlendLayer(layer);
                        break;
                }

// TODO: disabled without explanation in hrev19264. investigate problem and enable
#if 0
                case AS_VIEW_SET_BLENDING_MODE:
                {
                        ViewBlendingModeInfo info;
                        link.Read<ViewBlendingModeInfo>(&info);

                        picture->WriteSetBlendingMode(info.sourceAlpha, info.alphaFunction);

                        fCurrentView->CurrentState()->SetBlendingMode(info.sourceAlpha,
                                info.alphaFunction);
                        fWindow->GetDrawingEngine()->SetBlendingMode(info.sourceAlpha,
                                info.alphaFunction);
                        break;
                }
#endif
                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.IsSet() && 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.IsSet())
                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.
                fDirectWindowInfo.Unset();
        } 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.Get(),
                screenFrame.left - fWindow->Frame().left,
                screenFrame.top - fWindow->Frame().top);
        fDesktop->ResizeWindowBy(fWindow.Get(),
                screenFrame.Width() - fWindow->Frame().Width(),
                screenFrame.Height() - fWindow->Frame().Height());
}


status_t
ServerWindow::_EnableDirectWindowMode()
{
        if (fDirectWindowInfo.IsSet()) {
                // already in direct window mode
                return B_ERROR;
        }

        if (fDesktop->HWInterface()->FrontBuffer() == NULL) {
                // direct window mode not supported
                return B_UNSUPPORTED;
        }

        fDirectWindowInfo.SetTo(new(std::nothrow) DirectWindowInfo);
        if (!fDirectWindowInfo.IsSet())
                return B_NO_MEMORY;

        status_t status = fDirectWindowInfo->InitCheck();
        if (status != B_OK) {
                fDirectWindowInfo.Unset();

                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.Get(),
                        originalFrame.left - fWindow->Frame().left,
                        originalFrame.top - fWindow->Frame().top);
                fDesktop->ResizeWindowBy(fWindow.Get(),
                        originalFrame.Width() - fWindow->Frame().Width(),
                        originalFrame.Height() - fWindow->Frame().Height());

                fDesktop->HWInterface()->SetCursorVisible(true);
        }

        fDesktop->SetWindowFeel(fWindow.Get(), feel);
}