/*-
 * amigaCursor.c --
 *	Functions for maintaining the Sun software cursor...
 *
 */

#define NEED_EVENTS
#include    "amiga.h"
#include    <windowstr.h>
#include    <regionstr.h>
#include    <dix.h>
#include    <dixstruct.h>
#include    <opaque.h>

#include    <servermd.h>
#include    "mipointer.h"
#include    "cursorstr.h"

#ifdef FBIOGCURMAX  /* has hardware cursor kernel support */
#define CURSOR_PAD  8

#define GetCursorPrivate(s) (&(GetScreenPrivate(s)->hardwareCursor))
#define SetupCursor(s)	    amigaCursorPtr pCurPriv = GetCursorPrivate(s)
#define CursorByteWidth(w)  (((w) + CURSOR_PAD - 1) / CURSOR_PAD)

static void
Repad (in, out, sc, w, h)
    char	    *in, *out;
    amigaCursorPtr    sc;
    int		    w, h;
{
    int	    x, y;
    char    *a, *b;
    int	    inwidth, outwidth;
    char    mask;

    inwidth = (w + BITMAP_SCANLINE_PAD - 1) / 8;
    mask = w & 7;
#if BITMAP_BIT_ORDER == MSBFirst
    if (mask == 0)
	mask = 0xff;
    else
	mask = 0xff << (8-mask);
#else
    mask = 0xff >> mask;
#endif
    outwidth = CursorByteWidth(sc->width);
    for (y = 0; y < h; y++) {
	a = in;
	b = out;
	in += inwidth;
	out += outwidth;
	for (x = 0; x < inwidth; x++)
	    *b++ = *a++;
	if (inwidth)
	    b[-1] &= mask;
	for (; x < outwidth; x++)
	    *b++ = '\0';
    }
    for (; y < sc->height; y++)
    {
	for (x = 0; x < outwidth; x++)
	    *b++ = '\0';
    }
}

static Bool
amigaRealizeCursor (pScreen, pCursor)
    ScreenPtr	pScreen;
    CursorPtr	pCursor;
{
    return TRUE;
}

static Bool
amigaUnrealizeCursor (pScreen, pCursor)
    ScreenPtr	pScreen;
    CursorPtr	pCursor;
{
    return TRUE;
}

static void
amigaLoadCursor (pScreen, pCursor, x, y)
    ScreenPtr	pScreen;
    CursorPtr	pCursor;
    int		x, y;
{
    SetupCursor(pScreen);
    struct fbcursor fbcursor;
    int	w, h;
    unsigned char   r[2], g[2], b[2];

    w = pCursor->bits->width;
    h = pCursor->bits->height;
    fbcursor.set = FB_CUR_SETALL;
    fbcursor.enable = 1;
    fbcursor.pos.x = x;
    fbcursor.pos.y = y;
    fbcursor.hot.x = pCursor->bits->xhot;
    fbcursor.hot.y = pCursor->bits->yhot;
    r[0] = pCursor->backRed >> 8;
    g[0] = pCursor->backGreen >> 8;
    b[0] = pCursor->backBlue >> 8;
    r[1] = pCursor->foreRed >> 8;
    g[1] = pCursor->foreGreen >> 8;
    b[1] = pCursor->foreBlue >> 8;
    fbcursor.cmap.index = 0;
    fbcursor.cmap.count = 2;
    fbcursor.cmap.red = r;
    fbcursor.cmap.green = g;
    fbcursor.cmap.blue = b;
    fbcursor.image = (char *) pCursor->bits->source;
    fbcursor.mask = (char *) pCursor->bits->mask;
    if (w > pCurPriv->width)
    {
	while (fbcursor.hot.x > pCurPriv->width && w >= 8)
	{
	    fbcursor.hot.x -= 8;
	    fbcursor.image++;
	    fbcursor.mask++;
	    w -= 8;
	}
	if (w > pCurPriv->width)
	    w = pCurPriv->width;
    }
    if (h > pCurPriv->height)
    {
	while (fbcursor.hot.y > pCurPriv->height && h >= 8)
	{
	    fbcursor.hot.y -= 8;
	    fbcursor.image += PixmapBytePad (pCursor->bits->width, 1);
	    fbcursor.mask +=  PixmapBytePad (pCursor->bits->width, 1);
	    h -= 8;
	}
	if (h > pCurPriv->height)
	    h = pCurPriv->height;
    }
    fbcursor.size.x = w;
    fbcursor.size.y = h;
    (void) ioctl (amigaFbs[pScreen->myNum].fd, FBIOSCURSOR, &fbcursor);
}

static void
amigaSetCursor (pScreen, pCursor, x, y)
    ScreenPtr	pScreen;
    CursorPtr	pCursor;
    int		x, y;
{
    SetupCursor(pScreen);

    if (pCursor)
    	amigaLoadCursor (pScreen, pCursor, x, y);
    else
	amigaDisableCursor (pScreen);
}

static void
amigaMoveCursor (pScreen, x, y)
    ScreenPtr	pScreen;
    int		x, y;
{
    SetupCursor(pScreen);
    struct fbcursor fbcursor;
    struct fbcurpos pos;

    pos.x = x;
    pos.y = y;
    ioctl (amigaFbs[pScreen->myNum].fd, FBIOSCURPOS, &pos);
}

miPointerSpriteFuncRec amigaPointerSpriteFuncs = {
    amigaRealizeCursor,
    amigaUnrealizeCursor,
    amigaSetCursor,
    amigaMoveCursor,
};

static void
amigaQueryBestSize (class, pwidth, pheight, pScreen)
    int	class;
    short   *pwidth, *pheight;
    ScreenPtr	pScreen;
{
    SetupCursor (pScreen);

    switch (class)
    {
    case CursorShape:
	if (*pwidth > pCurPriv->width)
	    *pwidth = pCurPriv->width;
	if (*pheight > pCurPriv->height)
	    *pheight = pCurPriv->height;
	if (*pwidth > pScreen->width)
	    *pwidth = pScreen->width;
	if (*pheight > pScreen->height)
	    *pheight = pScreen->height;
	break;
    default:
	mfbQueryBestSize (class, pwidth, pheight, pScreen);
	break;
    }
}

extern miPointerScreenFuncRec	amigaPointerScreenFuncs;

#endif

Bool
amigaCursorInitialize (pScreen)
    ScreenPtr	pScreen;
{
#ifdef FBIOGCURMAX
    SetupCursor (pScreen);
    int	    fd;
    struct fbcursor fbcursor;
    struct fbcurpos maxsize;
    char    *source, *mask;
    int	    h, w;
    int	    size;

    pCurPriv->has_cursor = FALSE;
    if (ioctl (amigaFbs[pScreen->myNum].fd, FBIOGCURMAX, &maxsize) == -1)
	return FALSE;
    pCurPriv->width = maxsize.x;
    pCurPriv->height= maxsize.y;
    pScreen->QueryBestSize = amigaQueryBestSize;
    miPointerInitialize (pScreen,
			 &amigaPointerSpriteFuncs,
			 &amigaPointerScreenFuncs,
			 FALSE);
    pCurPriv->has_cursor = TRUE;
#else
    return FALSE;
#endif
}

amigaDisableCursor (pScreen)
    ScreenPtr	pScreen;
{
#ifdef FBIOGCURMAX
    SetupCursor (pScreen);
    struct fbcursor fbcursor;

    if (pCurPriv->has_cursor)
    {
    	fbcursor.set = FB_CUR_SETCUR;
    	fbcursor.enable = 0;
    	(void) ioctl (amigaFbs[pScreen->myNum].fd, FBIOSCURSOR, &fbcursor);
    }
#endif
}

/*
 * The following struct is from win_cursor.h.  This file can't be included 
 * directly, because it drags in all of the SunView attribute stuff along 
 * with it.
 */

void
amigaInitCursor ()
{
    if ( amigaUseSunWindows() ) {
    }
}
