/*
 *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
 *
 *  This is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This software is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this software; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 *  USA.
 */

/*
 * desktop.c - functions to deal with "desktop" window.
 */

#include "vncviewer.h"
#include <X11/Xaw/Viewport.h>
#include <X11/Xmu/Converters.h>
#ifdef MITSHM
#include <X11/extensions/XShm.h>
#endif
#include <gtk/gtk.h>

GdkGC *gdkGC;
GdkGC *gdksrcGC, *gdkdstGC;
GdkCursor *gdkdotCursor;
GdkImage *gdkimage[MAXCLIENT];
GdkImage *smallimage[MAXCLIENT];

Window desktopWin;
Widget form, viewport, desktop;

static GdkCursor *CreateDotCursor();
static void CopyBGR233ToScreen(CARD8 *buf, int x, int y, int width,int height);

static XtResource desktopBackingStoreResources[] = {
  {
    XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof(int), 0,
    XtRImmediate, (XtPointer) Always,
  },
};


/*
 * DesktopInitAfterRealization does things which require the X windows to
 * exist.  It creates some GCs and sets the dot cursor.
 */

void
DesktopInitAfterRealization()
{
  unsigned long valuemask = 0;
  GdkGCValues gdkgcv;
  GdkWindowAttr gdkattr;

  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);

  if (!appData.useX11Cursor) {
    gdkdotCursor = CreateDotCursor();
    gdkattr.cursor = gdkdotCursor;
    valuemask = GDK_WA_CURSOR;
#if 0
    dotCursor = CreateDotCursor();
    attr.cursor = dotCursor;
    valuemask = CWCursor;
#endif
  }

  /* カーソルをドットにするには... 
    gdk_window_set_cursor(drawingarea[page][da_num]->window, CreateDotCursor());
  */
}


/*
 * SendRFBEvent is an action which sends an RFB event.  It can be used in two
 * ways.  Without any parameters it simply sends an RFB event corresponding to
 * the X event which caused it to be called.  With parameters, it generates a
 * "fake" RFB event based on those parameters.  The first parameter is the
 * event type, either "fbupdate", "ptr", "keydown", "keyup" or "key"
 * (down&up).  The "fbupdate" event requests full framebuffer update. For a
 * "key" event the second parameter is simply a keysym string as understood by
 * XStringToKeysym().  For a "ptr" event, the following three parameters are
 * just X, Y and the button mask (0 for all up, 1 for button1 down, 2 for
 * button2 down, 3 for both, etc).
 */

void
SendRFBEvent(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
}


/*
 * CreateDotCursor.
 */
static GdkCursor *
CreateDotCursor()
{
  GdkCursor *gdkcursor;
  GdkPixmap *gdksrc, *gdkmsk;
  GdkColor gdkfg, gdkbg;
  static char srcBits[] = { 0, 14,14,14, 0 };
  static char mskBits[] = { 14,31,31,31,14 };

  gdksrc = gdk_bitmap_create_from_data(drawingarea[0][0]->window, srcBits, 5, 5);
  gdkmsk = gdk_bitmap_create_from_data(drawingarea[0][0]->window, mskBits, 5, 5);
  gdk_color_black(gdk_colormap_get_system(), &gdkfg);
  gdk_color_white(gdk_colormap_get_system(), &gdkbg);
  gdkcursor = gdk_cursor_new_from_pixmap(gdksrc, gdkmsk, &gdkfg, &gdkbg, 2, 2);
  gdk_pixmap_unref(gdksrc);
  gdk_pixmap_unref(gdkmsk);

  return gdkcursor;
}


/*
 * CopyDataToScreen.
 */

void
CopyDataToScreen(char *buf, int x, int y, int width, int height)
{
  int h;

  if (appData.rawDelay != 0) {
    draw_rectangle(gdkpixmap[page][da_num], gdkGC, TRUE, x, y, width, height, 0);

    XSync(dpy,False);
    usleep(appData.rawDelay * 1000);
  }

  if (!appData.useBGR233) {
    int widthInBytes = width * myFormat.bitsPerPixel / 8;
    int scrWidthInBytes = server_CB.client_grp[clientNum]->serverInitMsg.framebufferWidth * myFormat.bitsPerPixel / 8;
    char *scr = (gdkimage[clientNum]->mem + y * scrWidthInBytes
		 + x * myFormat.bitsPerPixel / 8);

    for (h = 0; h < height; h++) {
      memcpy((char *)scr, buf, widthInBytes);
      buf += widthInBytes;
      scr += scrWidthInBytes;
    }
  } else {
    CopyBGR233ToScreen((CARD8 *)buf, x, y, width, height);
  }
  draw_image(gdkpixmap[page][da_num], gdkGC, gdkimage[clientNum], x, y, x, y, width, height);
  if (GETVIEW(clientNum))
    draw_image(pixmap_ex, gdkGC, gdkimage[clientNum], x, y, x, y, width, height);
}


/*
 * CopyBGR233ToScreen.
 */

static void
CopyBGR233ToScreen(CARD8 *buf, int x, int y, int width, int height)
{
  int p, q;
  int xoff = 7 - (x & 7);
  int xcur;
  int fbwb = server_CB.client_grp[clientNum]->serverInitMsg.framebufferWidth / 8;

  CARD8 *scr1 = ((CARD8 *)gdkimage[clientNum]->mem) + y * fbwb + x / 8;
  CARD8 *scrt;
  CARD8 *scr8 = ((CARD8 *)gdkimage[clientNum]->mem) + y * server_CB.client_grp[clientNum]->serverInitMsg.framebufferWidth + x;
  CARD16 *scr16 = ((CARD16 *)gdkimage[clientNum]->mem) + y * server_CB.client_grp[clientNum]->serverInitMsg.framebufferWidth + x;
  CARD32 *scr32 = ((CARD32 *)gdkimage[clientNum]->mem) + y * server_CB.client_grp[clientNum]->serverInitMsg.framebufferWidth + x;

  switch (gdkvisbpp) {
    /* thanks to Chris Hooper for single bpp support */

  case 1:
    for (q = 0; q < height; q++) {
      xcur = xoff;
      scrt = scr1;
      for (p = 0; p < width; p++) {
	*scrt = ((*scrt & ~(1 << xcur))
		 | (BGR233ToPixel[*(buf++)] << xcur));

	if (xcur-- == 0) {
	  xcur = 7;
	  scrt++;
	}
      }
      scr1 += fbwb;
    }
    break;

  case 8:
    for (q = 0; q < height; q++) {
      for (p = 0; p < width; p++) {
	*(scr8++) = BGR233ToPixel[*(buf++)];
      }
      scr8 += server_CB.client_grp[clientNum]->serverInitMsg.framebufferWidth - width;
    }
    break;

  case 16:
    for (q = 0; q < height; q++) {
      for (p = 0; p < width; p++) {
	*(scr16++) = BGR233ToPixel[*(buf++)];
      }
      scr16 += server_CB.client_grp[clientNum]->serverInitMsg.framebufferWidth - width;
    }
    break;

  case 32:
    for (q = 0; q < height; q++) {
      for (p = 0; p < width; p++) {
	*(scr32++) = BGR233ToPixel[*(buf++)];
      }
      scr32 += server_CB.client_grp[clientNum]->serverInitMsg.framebufferWidth - width;
    }
    break;
  }
}

void
CopyDataFromScreen( char *buf, int x, int y, int width, int height )
{
  int widthInBytes = width * myFormat.bitsPerPixel / 8;
  //int scrWidthInBytes = server_CB.client_grp[clientNum]->serverInitMsg.framebufferWidth * myFormat.bitsPerPixel / 8;
  int scrWidthInBytes = si.framebufferWidth * myFormat.bitsPerPixel / 8;
  char *scr = gdkimage[clientNum]->mem + y * scrWidthInBytes + x * myFormat.bitsPerPixel / 8;
  int h;
  for( h = 0; h < height; h++ ){
    memcpy( buf, scr, widthInBytes );
    scr += scrWidthInBytes;
    buf += widthInBytes;
  }
  return;
}
