root/src/kits/app/Cursor.cpp
/*
 * Copyright 2001-2006, Haiku.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *              Frans van Nispen (xlr8@tref.nl)
 *              Gabe Yoder (gyoder@stny.rr.com)
 *              Axel Dörfler, axeld@pinc-software.de
 */

/**     BCursor describes a view-wide or application-wide cursor. */


#include <AppDefs.h>
#include <Bitmap.h>
#include <Cursor.h>

#include <AppServerLink.h>
#include <ServerProtocol.h>


const BCursor *B_CURSOR_SYSTEM_DEFAULT;
const BCursor *B_CURSOR_I_BEAM;
        // these are initialized in BApplication::InitData()

BCursor::BCursor(const void *cursorData)
        :
        fServerToken(-1),
        fNeedToFree(false)
{
        const uint8 *data = (const uint8 *)cursorData;

        if (data == B_HAND_CURSOR || data == B_I_BEAM_CURSOR) {
                // just use the default cursors from the app_server
                fServerToken = data == B_HAND_CURSOR ?
                        B_CURSOR_ID_SYSTEM_DEFAULT : B_CURSOR_ID_I_BEAM;
                return;
        }

        // Create a new cursor in the app_server

        if (data == NULL
                || data[0] != 16        // size
                || data[1] != 1         // depth
                || data[2] >= 16 || data[3] >= 16)      // hot-spot
                return;

        // Send data directly to server
        BPrivate::AppServerLink link;
        link.StartMessage(AS_CREATE_CURSOR);
        link.Attach(cursorData, 68);

        status_t status;
        if (link.FlushWithReply(status) == B_OK && status == B_OK) {
                link.Read<int32>(&fServerToken);
                fNeedToFree = true;
        }
}


BCursor::BCursor(BCursorID id)
        :
        fServerToken(id),
        fNeedToFree(false)
{
}


BCursor::BCursor(const BCursor& other)
        :
        fServerToken(-1),
        fNeedToFree(false)
{
        *this = other;
}


BCursor::BCursor(BMessage *data)
{
        // undefined on BeOS
        fServerToken = -1;
        fNeedToFree = false;
}


BCursor::BCursor(const BBitmap* bitmap, const BPoint& hotspot)
        :
        fServerToken(-1),
        fNeedToFree(false)
{
        if (bitmap == NULL)
                return;

        BRect bounds = bitmap->Bounds();
        color_space colorspace = bitmap->ColorSpace();
        void* bits = bitmap->Bits();
        int32 size = bitmap->BitsLength();
        if (bits == NULL || size <= 0)
                return;

        // Send data directly to server
        BPrivate::AppServerLink link;
        link.StartMessage(AS_CREATE_CURSOR_BITMAP);
        link.Attach<BRect>(bounds);
        link.Attach<BPoint>(hotspot);
        link.Attach<color_space>(colorspace);
        link.Attach<int32>(bitmap->BytesPerRow());
        link.Attach<int32>(size);
        link.Attach(bits, size);

        status_t status;
        if (link.FlushWithReply(status) == B_OK) {
                if (status == B_OK) {
                        link.Read<int32>(&fServerToken);
                        fNeedToFree = true;
                } else
                        fServerToken = status;
        }
}


BCursor::~BCursor()
{
        _FreeCursorData();
}


status_t
BCursor::InitCheck() const
{
        return fServerToken >= 0 ? B_OK : fServerToken;
}


status_t
BCursor::Archive(BMessage *into, bool deep) const
{
        // not implemented on BeOS
        return B_OK;
}


BArchivable     *
BCursor::Instantiate(BMessage *data)
{
        // not implemented on BeOS
        return NULL;
}


BCursor&
BCursor::operator=(const BCursor& other)
{
        if (&other != this && other != *this) {
                _FreeCursorData();

                fServerToken = other.fServerToken;

                if (other.fNeedToFree) {
                        BPrivate::AppServerLink link;
                        link.StartMessage(AS_CLONE_CURSOR);
                        link.Attach<int32>(other.fServerToken);

                        status_t status;
                        if (link.FlushWithReply(status) == B_OK) {
                                if (status == B_OK) {
                                        link.Read<int32>(&fServerToken);
                                        fNeedToFree = true;
                                } else
                                        fServerToken = status;
                        }
                }
        }
        return *this;
}


bool
BCursor::operator==(const BCursor& other) const
{
        return fServerToken == other.fServerToken;
}


bool
BCursor::operator!=(const BCursor& other) const
{
        return fServerToken != other.fServerToken;
}


status_t
BCursor::Perform(perform_code d, void *arg)
{
        return B_OK;
}


void BCursor::_ReservedCursor1() {}
void BCursor::_ReservedCursor2() {}
void BCursor::_ReservedCursor3() {}
void BCursor::_ReservedCursor4() {}


void
BCursor::_FreeCursorData()
{
        // Notify server to deallocate server-side objects for this cursor
        if (fNeedToFree) {
                BPrivate::AppServerLink link;
                link.StartMessage(AS_DELETE_CURSOR);
                link.Attach<int32>(fServerToken);
                link.Flush();
        }
}