#include <vncviewer.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>

extern IMAGEINFO *iinfo[];
extern GdkImage *gdkimage[];
extern GdkImage *smallimage[];
GdkGC *gdkGC;
GdkGC *gdksrcGC, *gdkdstGC;
//GdkCursor *gdkdotCursor;
static XShmSegmentInfo shminfo;
static Bool needShmCleanup = False;

void
DesktopInitForClient()
{
  GdkGCValues gdkgcv;

  gdkimage[0] = NULL;
  smallimage[0] = NULL;
  if (gdkimage[0] == NULL) {
    gdkimage[0] = gdk_image_new(GDK_IMAGE_FASTEST, gdkvis,
			        client_CB.serverInitMsg.framebufferWidth, client_CB.serverInitMsg.framebufferHeight);
  }
  if (smallimage[0] == NULL) {
    smallimage[0] = gdk_image_new(GDK_IMAGE_FASTEST, gdkvis,
			          client_CB.serverInitMsg.framebufferWidth, client_CB.serverInitMsg.framebufferHeight);
  }

  gdkGC = gdk_gc_new(drawingarea[0][0]->window);

  gdkgcv.function = GDK_XOR;
  gdkgcv.foreground.pixel = 0x0f0f0f0f;
  gdksrcGC = gdk_gc_new_with_values(drawingarea[0][0]->window, &gdkgcv, GDK_GC_FOREGROUND|GDK_GC_FUNCTION);
  gdkgcv.foreground.pixel = 0xf0f0f0f0;
  gdkdstGC = gdk_gc_new_with_values(drawingarea[0][0]->window, &gdkgcv, GDK_GC_FOREGROUND|GDK_GC_FUNCTION);
}


void
PrintPixelFormat(format)
	    rfbPixelFormat *format;
{
  if (format->bitsPerPixel == 1) {
    fprintf(stderr,"  Single bit per pixel.\n");
      fprintf(stderr,
	      "  %s significant bit in each byte is leftmost on the screen.\n",
	      (format->bigEndian ? "Most" : "Least"));
  } else {
    fprintf(stderr,"  %d bits per pixel.\n",format->bitsPerPixel);
    if (format->bitsPerPixel != 8) {
      fprintf(stderr,"  %s significant byte first in each pixel.\n",
	      (format->bigEndian ? "Most" : "Least"));
    }
    if (format->trueColour) {
      fprintf(stderr,"  True colour: max red %d green %d blue %d",
	      format->redMax, format->greenMax, format->blueMax);
      fprintf(stderr,", shift red %d green %d blue %d\n",
	      format->redShift, format->greenShift, format->blueShift);
    } else {
      fprintf(stderr,"  Colour map (not true colour).\n");
    }
  }
}

void CreateImageInfoForClient()
{
  int srcW, srcH, dstW, dstH;

  if ((drawingarea[0][0]->allocation.width < client_CB.serverInitMsg.framebufferWidth) &&
    (drawingarea[0][0]->allocation.height < client_CB.serverInitMsg.framebufferHeight)) {
    reducedWindowWidth = dstW = drawingarea[0][0]->allocation.width;
    reducedWindowHeight = dstH = drawingarea[0][0]->allocation.height;
  } else {
    reducedWindowWidth = dstW = client_CB.serverInitMsg.framebufferWidth;
    reducedWindowHeight = dstH = client_CB.serverInitMsg.framebufferHeight;
  }
  srcW = client_CB.serverInitMsg.framebufferWidth;
  srcH = client_CB.serverInitMsg.framebufferHeight;

  if (!iinfo[0]) {
    if ((iinfo[0] = malloc (sizeof(IMAGEINFO))) == NULL) {
      fprintf(stderr, "small image infomation malloc failed\n");
      exit(1);
    }
  }

  if (!srcW | !srcH | !dstW | !dstH) exit (-1);
  iinfo[0]->widthSrcToDst = ( dstW << SHIFTVAL ) / srcW;
  iinfo[0]->widthDstToSrc = ( srcW << SHIFTVAL ) / dstW;
  iinfo[0]->heightSrcToDst = ( dstH << SHIFTVAL ) / srcH;
  iinfo[0]->heightDstToSrc = ( srcH << SHIFTVAL ) / dstH;

  return;
}

void
CopyDataToScreenForClient(char *buf, int x, int y, int width, int height)
{
  int h;
  int widthInBytes = width * myFormat.bitsPerPixel / 8;
  int scrWidthInBytes = client_CB.serverInitMsg.framebufferWidth * myFormat.bitsPerPixel / 8;

  char *scr = (gdkimage[0]->mem + y * scrWidthInBytes + x * myFormat.bitsPerPixel / 8);

  for (h = 0; h < height; h++) {
    memcpy((char *)scr, buf, widthInBytes);
    buf += widthInBytes;
    scr += scrWidthInBytes;
  }
  draw_image(gdkpixmap[0][0], gdkGC, gdkimage[0], x, y, x, y, width, height);
}

void window_copy_area_for_client( GdkWindow *window, GdkGC *gc, gint x, gint y,
		                  GdkWindow *source_window, gint source_x, gint source_y,
			          gint width, gint height )
{
  char *buf;
  buf = malloc( myFormat.bitsPerPixel * width * height );
  CopyDataFromScreen( buf, source_x, source_y, width, height );
  CopyDataToScreenForClient( buf, x, y, width, height );
  free( buf );
  return;
}

void draw_rectangle_for_client( GdkDrawable *drawable, GdkGC *gc, gint filled,
		                     gint x, gint y, gint width, gint height, int color )
{
  GdkImage *image = gdkimage[0];
  int bpp;

  if ((drawable == NULL) || (gc == NULL) || (image == NULL)) return;
  bpp = myFormat.bitsPerPixel;
  FillRectangle( color, x, y, width, height, bpp, image );
  draw_image( drawable, gc, image, x, y, x, y, width, height );
  return;
}


void
ShmCleanup()
{
  fprintf(stderr,"ShmCleanup called\n");
  if (needShmCleanup) {
    shmdt(shminfo.shmaddr);
    shmctl(shminfo.shmid, IPC_RMID, 0);
    needShmCleanup = False;
  }
}

