/***********************************************************
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
and the Massachusetts Institute of Technology, Cambridge, Massachusetts.

                        All Rights Reserved

Permission to use, copy, modify, and distribute this software and its 
documentation for any purpose and without fee is hereby granted, 
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in 
supporting documentation, and that the names of Digital or MIT not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.  

DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

******************************************************************/
#include <stdio.h>

#include "X.h"
#define  NEED←EVENTS
#include "Xproto.h"
#include "scrnintstr.h"
#include "cursorstr.h"
#include "pixmap.h"
#include "input.h"
#include "windowstr.h"
#include "regionstr.h"
#include "opaque.h"

#include "mfb.h"
#include "mi.h"
#include "os.h"

extern void SetInputCheck();
extern void InitXeroxMap();

mesa long System←PulsesToMicroseconds();
struct driverEvent {
    unsigned short x,y;
    long time;
    short type;
    short key;
    };

struct ptrs {
    int **p1, **p2
    };

mesa struct driverEvent *XEventQ←DeQEvent();
mesa struct ptrs XEventQ←EventQPointers();
mesa void XEventQ←FreeEvent();
mesa void XMKDriver←setMouseInterest();
mesa void XMKDriver←setMouseConstraint();
mesa void XMKDriver←setCursor();
mesa void XMKDriver←setCursorPosition();
mesa long XMKDriver←getLastEventTime();
mesa void XMKDriver←setLastEventTime();
mesa long XMKDriver←getTimeInMillis();
mesa void XMKDriver←enableMouseEvents();
mesa void XMKDriver←enableKeyboardEvents();
mesa void XMKDriver←blinkDisplay();
mesa int *XMKDriver←displayInit();
mesa void XMKDriver←displayClose();
mesa void XMKDriver←displayOn();
mesa void XMKDriver←displayOff();

Bool xeroxRealizeCursor(), xeroxUnrealizeCursor(), xeroxDisplayCursor();
Bool xeroxSetCursorPosition();
void xeroxCursorLimits();
void xeroxPointerNonInterestBox();
void xeroxConstrainCursor();
Bool xeroxScreenClose();
void xeroxQueryBestSize();

extern void miRecolorCursor();
extern int  xeroxGetMotionEvents();
extern void xeroxChangePointerControl(), xeroxChangeKeyboardControl(), xeroxBell();
extern long GetTimeInMillis();

int isItTimeToYield;

static DevicePtr	xeroxKeyboard;
static DevicePtr	xeroxPointer;
static int *bitmap;
static int hotX, hotY;
static BoxRec constraintBox;

static Bool
xeroxSaveScreen(pScreen, on)
    ScreenPtr pScreen;
    int on;
{
    if (on == SCREEN←SAVER←FORCER)
    {
        XMKDriver←setLastEventTime(GetTimeInMillis());	
	return TRUE;
    }
    else
        return FALSE;
}


Bool
xeroxScreenInit(index, pScreen, argc, argv)
    int index;
    ScreenPtr pScreen;
    int argc;		/* these two may NOT be changed */
    char **argv;
{
    register PixmapPtr pPixmap;
    Bool retval;

    bitmap = XMKDriver←displayInit();
    retval = mfbScreenInit(index, pScreen, (char *)bitmap, 1024, 808, 72);
    pScreen->CloseScreen = xeroxScreenClose;
    pScreen->SaveScreen = xeroxSaveScreen;
    pScreen->RealizeCursor = xeroxRealizeCursor;
    pScreen->UnrealizeCursor = xeroxUnrealizeCursor;
    pScreen->DisplayCursor = xeroxDisplayCursor;
    pScreen->SetCursorPosition = xeroxSetCursorPosition;
    pScreen->CursorLimits = xeroxCursorLimits;
    pScreen->PointerNonInterestBox = xeroxPointerNonInterestBox;
    pScreen->ConstrainCursor = xeroxConstrainCursor;
    pScreen->RecolorCursor = miRecolorCursor;
    pScreen->QueryBestSize = xeroxQueryBestSize;

    return(retval);
}

static Bool
xeroxScreenClose(index, pScreen)
    int index;
    ScreenPtr pScreen;

{
    XMKDriver←displayClose();
    return (TRUE);
}

int
xeroxMouseProc(pDev, onoff, argc, argv)
    DevicePtr pDev;
    int onoff;
    int argc;
    char **argv;
{
    int     i;
    struct ptrs qptrs;
    BYTE map[4];

    switch (onoff)
    {
	case DEVICE←INIT: 
	    xeroxPointer = pDev;
	    pDev->devicePrivate = (pointer) NULL;
	    map[1] = 1;
	    map[2] = 2;
	    map[3] = 3;
	    InitPointerDeviceStruct(
		xeroxPointer, map, 3, xeroxGetMotionEvents, xeroxChangePointerControl);
	    qptrs = XEventQ←EventQPointers();
	    /*SetInputCheck(qptrs.p1, qptrs.p2);*/
	    break;
	case DEVICE←ON: 
	    pDev->on = TRUE;
	    hotX = hotY = 0;
	    XMKDriver←enableMouseEvents(TRUE);
	    break;
	case DEVICE←OFF: 
	    pDev->on = FALSE;
	    XMKDriver←enableMouseEvents(FALSE);
/*	RemoveEnabledDevice(fdQVSS);   */
	    break;
	case DEVICE←CLOSE: 
	    XMKDriver←enableMouseEvents(FALSE);
	    break;
    }
    return Success;

}

int
xeroxKeybdProc(pDev, onoff, argc, argv)
    DevicePtr pDev;
    int onoff;
    int argc;
    char **argv;
{
    BYTE map[MAP←LENGTH];
    KeySymsRec keySyms;
    ModifierMapRec modMap;

    switch (onoff)
    {
	case DEVICE←INIT: 
	    xeroxKeyboard = pDev;
	    pDev->devicePrivate = (pointer) NULL;
	    InitXeroxMap(&keySyms, &modMap);
	    InitKeyboardDeviceStruct(
		    xeroxKeyboard, &keySyms, &modMap, xeroxBell,
		    xeroxChangeKeyboardControl);
	    Xfree(keySyms.map);
	    break;
	case DEVICE←ON: 
	    pDev->on = TRUE;
	    XMKDriver←enableKeyboardEvents(TRUE);
	    break;
	case DEVICE←OFF: 
	    pDev->on = FALSE;
	    XMKDriver←enableKeyboardEvents(FALSE);
/*	    RemoveEnabledDevice(fdQVSS);  */
	    break;
	case DEVICE←CLOSE: 
	    XMKDriver←enableKeyboardEvents(FALSE);
	    break;
    }
    return Success;
}


/*****************
 * ProcessInputEvents:
 *    processes all the pending input events
 *****************/

extern int screenIsSaved;

void
ProcessInputEvents()
{
    struct driverEvent *event;

    xEvent	x;

    while ( ( event = XEventQ←DeQEvent() ) != NULL )
	{
	x.u.u.type = event->type;
	x.u.u.detail = event->key;
	x.u.keyButtonPointer.time = System←PulsesToMicroseconds(event->time)/1000L;
	x.u.keyButtonPointer.rootX = event->x + hotX;
	x.u.keyButtonPointer.rootY = event->y + hotY;
	XEventQ←FreeEvent(&event);
	switch(x.u.u.type)
	    {
	    case KeyPress:
	    case KeyRelease:
		(*xeroxKeyboard->processInputProc)(&x, xeroxKeyboard);
		break;
	    case ButtonPress:
	    case ButtonRelease:
	    case MotionNotify:
		(*xeroxPointer->processInputProc)(&x, xeroxPointer);
		break;
	    }
	}
}


TimeSinceLastInputEvent()
{
    if (XMKDriver←getLastEventTime() == 0)
	XMKDriver←setLastEventTime(GetTimeInMillis());
    return GetTimeInMillis() - XMKDriver←getLastEventTime();
}

static void
xeroxChangeKeyboardControl(pDevice, ctrl)
    DevicePtr pDevice;
    KeybdCtrl *ctrl;
{
}

static void
xeroxBell(loud, pDevice)
    int loud;
    DevicePtr pDevice;
{
	XMKDriver←blinkDisplay();
}

static void
xeroxChangePointerControl(pDevice, ctrl)
    DevicePtr pDevice;
    PtrCtrl   *ctrl;
{
}

static int
xeroxGetMotionEvents(buff, start, stop)
    CARD32 start, stop;
    xTimecoord *buff;
{
    return 0;
}

static Bool
xeroxSetCursorPosition( pScr, newx, newy)
    ScreenPtr	pScr;
    unsigned int	newx;
    unsigned int	newy;
{
    XMKDriver←setCursorPosition(newx - hotX,newy - hotY);
    return (TRUE);
}

static Bool
xeroxDisplayCursor( pScr, pCurs, x, y)
    ScreenPtr	pScr;
    CursorPtr	pCurs;
    int x,y;
{
    int i;
    if((hotX != pCurs->xhot) || (hotY != pCurs->yhot))
	{
	hotX = pCurs->xhot;
	hotY = pCurs->yhot;
	xeroxSetCursorPosition(pScr, x, y);
	/*xeroxConstrainCursor(pScr, & constraintBox);*/
	}

    XMKDriver←setCursor((short *)pCurs->devPriv[pScr->myNum]);
}


static void
xeroxPointerNonInterestBox( pScr, pBox)
    ScreenPtr	pScr;
    BoxPtr	pBox;
{
	XMKDriver←setMouseInterest(*pBox);
}

static void
xeroxConstrainCursor( pScr, pBox)
    ScreenPtr	pScr;
    BoxPtr	pBox;
{
	XMKDriver←setMouseConstraint(*pBox);
}

static void
xeroxCursorLimits( pScr, pCurs, pHotBox, pTopLeftBox)
    ScreenPtr	pScr;
    CursorPtr	pCurs;
    BoxPtr	pHotBox;
    BoxPtr	pTopLeftBox;	/* return value */
{
    pTopLeftBox->x1 = max( pHotBox->x1, 0);
    pTopLeftBox->y1 = max( pHotBox->y1, 0);
    pTopLeftBox->x2 = min( pHotBox->x2, 1023);
    pTopLeftBox->y2 = min( pHotBox->y2, 807);
}

Bool
xeroxRealizeCursor( pScr, pCurs)
    ScreenPtr pScr;
    CursorPtr	pCurs;	/* a SERVER-DEPENDENT cursor */
{
    short *	phardbits;	/* qvss-defined */
    short *	pservimbits;	/* server-defined */
				/* assumes severscanlinepad = sizeof(int) */
    int *	pservmskbits;	/* server-defined */
    int		i;

    pCurs->devPriv[pScr->myNum] = (pointer)Xalloc( 16*sizeof(short));
    bzero((char *)pCurs->devPriv[pScr->myNum], 16*sizeof(short));

    /*
     * munge the SERVER-DEPENDENT, device-independent cursor bits into
     * what the device wants, which appears to be 16 contiguous shorts.
     *
     * xerox cursor is brain-damaged, so only look at "image" bits
     */
/* XXX assumes that the DIX cursor format is padded to int boundaries */
    for ( i=0,
	  phardbits = (short *)pCurs->devPriv[ pScr->myNum],
	  pservimbits = (int *)pCurs->source;

	  i < ((pCurs->height < 16) ? pCurs->height : 16);

	  i++)
	*phardbits++ = *pservimbits++;	/* effectively clip off last 16 bits */
}

Bool
xeroxUnrealizeCursor( pScr, pCurs)
    ScreenPtr	pScr;
    CursorPtr	pCurs;
{
    Xfree( pCurs->devPriv[ pScr->myNum]);
    return TRUE;
}


void xeroxQueryBestSize(class, pwidth, pheight)
int class;
short *pwidth;
short *pheight;
{
    unsigned width, test;

    switch(class)
    {
      case CursorShape:
	  *pwidth = 16;
	  *pheight = 16;
	  break;
      case TileShape:
      case StippleShape:
	  width = *pwidth;
	  /* Return the closes power of two not less than what they gave me */
	  test = 0x80000000;
	  /* Find the highest 1 bit in the width given */
	  while(!(test & width))
	     test >>= 1;
	  /* If their number is greater than that, bump up to the next
	   *  power of two */
	  if((test - 1) & width)
	     test <<= 1;
	  *pwidth = test;
	  /* We don't care what height they use */
	  break;
    }
}