/****************************************************************************/
/*              Beebem - (c) David Alan Gilbert 1994                        */
/*              ------------------------------------                        */
/* This program may be distributed freely within the following restrictions:*/
/*                                                                          */
/* 1) You may not charge for this program or for any part of it.            */
/* 2) This copyright message must be distributed with all copies.           */
/* 3) This program must be distributed complete with source code.  Binary   */
/*    only distribution is not permitted.                                   */
/* 4) The author offers no warrenties, or guarentees etc. - you use it at   */
/*    your own risk.  If it messes something up or destroys your computer   */
/*    thats YOUR problem.                                                   */
/* 5) You may use small sections of code from this program in your own      */
/*    applications - but you must acknowledge its use.  If you plan to use  */
/*    large sections then please ask the author.                            */
/*                                                                          */
/* If you do not agree with any of the above then please do not use this    */
/* program.                                                                 */
/* Please report any problems to the author at gilbertd@cs.man.ac.uk        */
/****************************************************************************/
/* The window which the beeb emulator displays stuff in */
/* David Alan Gilbert 6/11/94 */

#include <string.h>

#include "X11/X.h"
#include "X11/Xlib.h"
#include "X11/Xutil.h"
#include "X11/keysym.h"

#include "dagXCL/DispServerConnection.h"
#include "dagXCL/XErr.h"
#include "dagXCL/shmImage.h"

#include "6502core.h"
#include "beebwin.h"
#include "disc8271.h"
#include "sysvia.h"

typedef enum {
  Same,
  ForceOn,
  ForceOff
} shiftHackType;

struct BeebKeyTrans {
  KeySym sym;
  int row;
  int col;
  shiftHackType shiftHack;
};

#include "keytable_2"

/* Takes x keycode and turns into row and col - -1 if not found,
   also returns row as result for easy testing */
static int DoKeyTrans(XKeyEvent xkey, int& row, int& col) {
  struct BeebKeyTrans *present=transTable;
  KeySym sym;

  /* We always use the unshifted version for lookup - we can't
     rely on shifting since its likely to be different from the
     beeb */
  sym=XLookupKeysym(&xkey,0);

  for(;((present->row!=-1) && (present->sym!=sym));present++);

  if (present->row==-1) {
    cerr << "-ve key trans row=" << row << "col=" << col << "sym=" << sym << "\n";
  };
  row=present->row;
  col=present->col;
  return(row);
}; /* DoKeyTrans */

BeebWin::BeebWin() : TopWin("Beeb Emulator",100,100,640,256,1,CopyFromParent,InputOutput, CopyFromParent,0,NULL),
                     si(ZPixmap,8,640,256),OldAutoRepeat(-1) {
  int col;
  XColor mycol;
  XGCValues tmpval;
  XWindowAttributes attribs;
  SetEventTypeMask(ExposureMask | VisibilityChangeMask | FocusChangeMask | KeyPressMask | KeyReleaseMask);
  Map();

  XGetWindowAttributes(myDisplay,myHandle,&attribs);
  colormap=DefaultColormapOfScreen(myScreen);

  mycol.flags=0;
  for(col=0;col<8;col++) {
    mycol.red=(col &1)?65535:0;
    mycol.green=(col &2)?65535:0;
    mycol.blue=(col &4)?65535:0;
    if (XAllocColor(myDisplay,colormap,&mycol)==0) throw dagXErr("Couldn't alloc colour\n");
    cols[col]=mycol.pixel;
  };

  Background(cols[0]);
  tmpval.function=GXcopy;
  gc=XCreateGC(myDisplay,myHandle,GCFunction,&tmpval);
  XCopyGC(myDisplay,_primaryDisplay->defaultGC(),GCPlaneMask|GCSubwindowMode,gc);
  DataSize=640*256;
}; /* BeebWin */

BeebWin::~BeebWin() {
  XFreeGC(myDisplay,gc);
  XFreeColormap(myDisplay,colormap);
}; /* Destructor */

void BeebWin::eventKeyDown(XKeyEvent xkey) {
  int row,col;

  if (DoKeyTrans(xkey, row, col)>=0) {
    BeebKeyDown(row,col);
  } else {
    if (row!=-2) dagXWindow::eventKeyDown(xkey);
  }
}; /* eventKeyDown */

void BeebWin::eventKeyUp(XKeyEvent xkey) {
  int row,col;

  if (DoKeyTrans(xkey, row, col)>=0) {
    BeebKeyUp(row,col);
  } else {
    if (row==-2) {
      /* Its upto us to do a reset! Should reset peripherals as well */
      Init6502core();
      Disc8271_reset();
    } else {
      dagXWindow::eventKeyDown(xkey);
    };
  }
}; /* eventKeyUp */

void BeebWin::eventExpose(XExposeEvent xexpose) {
  si.put(this,gc,xexpose.x,xexpose.y,xexpose.x,xexpose.y,xexpose.width,
      xexpose.height,0);
}; /* eventExpose */

void BeebWin::eventFocusIn(XFocusChangeEvent xfocus) {
  XKeyboardState tmpstate;
  /* We want to turn auto repeat off -  but first we store the
  current auto repeat state */
  XGetKeyboardControl(myDisplay,&tmpstate);
  OldAutoRepeat=tmpstate.global_auto_repeat;
  XAutoRepeatOff(myDisplay);
}; /* eventFocusIn */

void BeebWin::eventFocusOut(XFocusChangeEvent xfocus) {
  /* Restore auto repeat */
  if (OldAutoRepeat==1) XAutoRepeatOn(myDisplay);
}; /* eventFocusOut */

void BeebWin::updateLines(int starty, int nlines) {
  if (starty<256) {
    if ((starty+nlines-1)>255) nlines=255-starty;
    si.put(this,gc,0,starty,0,starty,640,nlines,0);
  };
}; /* BeebWin::updateLines */

EightUChars *BeebWin::GetLinePtr(int y) {
  if (y>255) y=255;
  return((EightUChars *)(si.imageData()+y*si.ximage->bytes_per_line));
};

SixteenUChars *BeebWin::GetLinePtr16(int y) {
  if (y>255) y=255;
  return((SixteenUChars *)(si.imageData()+y*si.ximage->bytes_per_line));
};

int BeebWin::bytesPerLine() {
  return(si.ximage->bytes_per_line);
}; /* BeebWin::bytesPerLine */

char *BeebWin::imageData() {
  return(si.imageData());
}; /* BeebWin::imageData */
