#include "tcl.h"
#include "tk.h"
#include <X11/Xlib.h>
#include <X11/X.h>

/*
 * Define DND Cursors...
 */

/* No Drop Cursor... */
#define noDropCursorWidth  20
#define noDropCursorHeight 20
#define noDropCursorX      10
#define noDropCursorY      10
static unsigned char noDropCurBits[] = {
 0x00,0x00,0x00,0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xf0,0x00,0x38,0xc0,0x01,
 0x7c,0x80,0x03,0xec,0x00,0x03,0xce,0x01,0x07,0x86,0x03,0x06,0x06,0x07,0x06,
 0x06,0x0e,0x06,0x06,0x1c,0x06,0x0e,0x38,0x07,0x0c,0x70,0x03,0x1c,0xe0,0x03,
 0x38,0xc0,0x01,0xf0,0xe0,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00,0x00,0x00,0x00};

static unsigned char noDropCurMask[] = {
 0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xff,0x00,0xf8,0xff,0x01,0xfc,0xf0,0x03,
 0xfe,0xc0,0x07,0xfe,0x81,0x07,0xff,0x83,0x0f,0xcf,0x07,0x0f,0x8f,0x0f,0x0f,
 0x0f,0x1f,0x0f,0x0f,0x3e,0x0f,0x1f,0xfc,0x0f,0x1e,0xf8,0x07,0x3e,0xf0,0x07,
 0xfc,0xe0,0x03,0xf8,0xff,0x01,0xf0,0xff,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00};
 
/* Copy Cursor... */
#define CopyCursorWidth  29
#define CopyCursorHeight 25
#define CopyCursorX      10
#define CopyCursorY      10
static unsigned char CopyCurBits[] =
{
  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x02, 0x00, 0x08, 0x01,
  0x02, 0x00, 0x08, 0x01, 0x02, 0x00, 0x08, 0x01, 0x02, 0x00, 0xe8, 0x0f,
  0x02, 0x00, 0x08, 0x01, 0x02, 0x00, 0x08, 0x01, 0x02, 0x00, 0x08, 0x01,
  0x02, 0x00, 0x08, 0x00, 0x02, 0x04, 0x08, 0x00, 0x02, 0x0c, 0x08, 0x00,
  0x02, 0x1c, 0x08, 0x00, 0x02, 0x3c, 0x08, 0x00, 0x02, 0x7c, 0x08, 0x00,
  0x02, 0xfc, 0x08, 0x00, 0x02, 0xfc, 0x09, 0x00, 0x02, 0xfc, 0x0b, 0x00,
  0x02, 0x7c, 0x08, 0x00, 0xfe, 0x6d, 0x0f, 0x00, 0x00, 0xc4, 0x00, 0x00,
  0x00, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
  0x00, 0x00, 0x00, 0x00};

static unsigned char CopyCurMask[] =
{
  0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0x1f,
  0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f,
  0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f,
  0x07, 0x06, 0xfc, 0x1f, 0x07, 0x0e, 0xfc, 0x1f, 0x07, 0x1e, 0x1c, 0x00,
  0x07, 0x3e, 0x1c, 0x00, 0x07, 0x7e, 0x1c, 0x00, 0x07, 0xfe, 0x1c, 0x00,
  0x07, 0xfe, 0x1d, 0x00, 0x07, 0xfe, 0x1f, 0x00, 0x07, 0xfe, 0x1f, 0x00,
  0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0x1e, 0x00, 0xff, 0xef, 0x1f, 0x00,
  0x00, 0xe6, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
  0x00, 0x80, 0x01, 0x00};

/* Move Cursor... */
#define MoveCursorWidth  21
#define MoveCursorHeight 25
#define MoveCursorX      10
#define MoveCursorY      10
static unsigned char MoveCurBits[] =
{
  0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08,
  0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08,
  0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x04, 0x08, 0x02, 0x0c, 0x08,
  0x02, 0x1c, 0x08, 0x02, 0x3c, 0x08, 0x02, 0x7c, 0x08, 0x02, 0xfc, 0x08,
  0x02, 0xfc, 0x09, 0x02, 0xfc, 0x0b, 0x02, 0x7c, 0x08, 0xfe, 0x6d, 0x0f,
  0x00, 0xc4, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01,
  0x00, 0x00, 0x00};

static unsigned char MoveCurMask[] =
{
  0xff, 0xff, 0x1f, 0xff, 0xff, 0x1f, 0xff, 0xff, 0x1f, 0x07, 0x00, 0x1c,
  0x07, 0x00, 0x1c, 0x07, 0x00, 0x1c, 0x07, 0x00, 0x1c, 0x07, 0x00, 0x1c,
  0x07, 0x00, 0x1c, 0x07, 0x06, 0x1c, 0x07, 0x0e, 0x1c, 0x07, 0x1e, 0x1c,
  0x07, 0x3e, 0x1c, 0x07, 0x7e, 0x1c, 0x07, 0xfe, 0x1c, 0x07, 0xfe, 0x1d,
  0x07, 0xfe, 0x1f, 0x07, 0xfe, 0x1f, 0xff, 0xff, 0x1f, 0xff, 0xff, 0x1e,
  0xff, 0xef, 0x1f, 0x00, 0xe6, 0x01, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03,
  0x00, 0x80, 0x01};

/* Link Cursor... */
#define LinkCursorWidth  29
#define LinkCursorHeight 25
#define LinkCursorX      10
#define LinkCursorY      10
static unsigned char LinkCurBits[] =
{
  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x02, 0x00, 0x08, 0x01,
  0x02, 0x00, 0x88, 0x00, 0x02, 0x00, 0x48, 0x00, 0x02, 0x00, 0xe8, 0x0f,
  0x02, 0x00, 0x48, 0x00, 0x02, 0x00, 0x88, 0x00, 0x02, 0x00, 0x08, 0x01,
  0x02, 0x00, 0x08, 0x00, 0x02, 0x04, 0x08, 0x00, 0x02, 0x0c, 0x08, 0x00,
  0x02, 0x1c, 0x08, 0x00, 0x02, 0x3c, 0x08, 0x00, 0x02, 0x7c, 0x08, 0x00,
  0x02, 0xfc, 0x08, 0x00, 0x02, 0xfc, 0x09, 0x00, 0x02, 0xfc, 0x0b, 0x00,
  0x02, 0x7c, 0x08, 0x00, 0xfe, 0x6d, 0x0f, 0x00, 0x00, 0xc4, 0x00, 0x00,
  0x00, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
  0x00, 0x00, 0x00, 0x00};

static unsigned char LinkCurMask[] =
{
  0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0x1f,
  0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f,
  0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f,
  0x07, 0x06, 0xfc, 0x1f, 0x07, 0x0e, 0xfc, 0x1f, 0x07, 0x1e, 0x1c, 0x00,
  0x07, 0x3e, 0x1c, 0x00, 0x07, 0x7e, 0x1c, 0x00, 0x07, 0xfe, 0x1c, 0x00,
  0x07, 0xfe, 0x1d, 0x00, 0x07, 0xfe, 0x1f, 0x00, 0x07, 0xfe, 0x1f, 0x00,
  0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0x1e, 0x00, 0xff, 0xef, 0x1f, 0x00,
  0x00, 0xe6, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
  0x00, 0x80, 0x01, 0x00};

/* Ask Cursor... */
#define AskCursorWidth  29
#define AskCursorHeight 25
#define AskCursorX      10
#define AskCursorY      10
static unsigned char AskCurBits[] =
{
  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x02, 0x00, 0x88, 0x03,
  0x02, 0x00, 0x48, 0x04, 0x02, 0x00, 0x08, 0x04, 0x02, 0x00, 0x08, 0x02,
  0x02, 0x00, 0x08, 0x01, 0x02, 0x00, 0x08, 0x01, 0x02, 0x00, 0x08, 0x00,
  0x02, 0x00, 0x08, 0x01, 0x02, 0x04, 0x08, 0x00, 0x02, 0x0c, 0x08, 0x00,
  0x02, 0x1c, 0x08, 0x00, 0x02, 0x3c, 0x08, 0x00, 0x02, 0x7c, 0x08, 0x00,
  0x02, 0xfc, 0x08, 0x00, 0x02, 0xfc, 0x09, 0x00, 0x02, 0xfc, 0x0b, 0x00,
  0x02, 0x7c, 0x08, 0x00, 0xfe, 0x6d, 0x0f, 0x00, 0x00, 0xc4, 0x00, 0x00,
  0x00, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
  0x00, 0x00, 0x00, 0x00};

static unsigned char AskCurMask[] =
{
  0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0x1f,
  0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f,
  0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f,
  0x07, 0x06, 0xfc, 0x1f, 0x07, 0x0e, 0xfc, 0x1f, 0x07, 0x1e, 0x1c, 0x00,
  0x07, 0x3e, 0x1c, 0x00, 0x07, 0x7e, 0x1c, 0x00, 0x07, 0xfe, 0x1c, 0x00,
  0x07, 0xfe, 0x1d, 0x00, 0x07, 0xfe, 0x1f, 0x00, 0x07, 0xfe, 0x1f, 0x00,
  0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0x1e, 0x00, 0xff, 0xef, 0x1f, 0x00,
  0x00, 0xe6, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
  0x00, 0x80, 0x01, 0x00};

static Cursor noDropCursor = 0,
              moveCursor   = 0,
              copyCursor   = 0,
              linkCursor   = 0,
              askCursor    = 0;


void TkDND_InitialiseCursors(Tcl_Interp *interp) {
  XColor black, white;
  Pixmap image_pixmap, mask_pixmap;
  Tk_Window main_window;
  Display *display;
  Window RootWindow;

  if (!interp) return;
  main_window   = Tk_MainWindow(interp);
  Tk_MakeWindowExist(main_window);
  display       = Tk_Display(main_window);
  RootWindow    = DefaultRootWindow(display);
  
  black.pixel = BlackPixel(display, DefaultScreen(display));
  white.pixel = WhitePixel(display, DefaultScreen(display));
  XQueryColor(display, DefaultColormap(display, 
          DefaultScreen(display)), &black);
  XQueryColor(display, DefaultColormap(display,
          DefaultScreen(display)), &white);
  /* No Drop Cursor */
  if (!noDropCursor) {
    image_pixmap = XCreateBitmapFromData(display, RootWindow,
            (char *) noDropCurBits, noDropCursorWidth, noDropCursorHeight);
    mask_pixmap  = XCreateBitmapFromData(display, RootWindow,
            (char *) noDropCurMask, noDropCursorWidth, noDropCursorHeight);
    noDropCursor = XCreatePixmapCursor (display, image_pixmap,
            mask_pixmap, &black, &white, noDropCursorX, noDropCursorY);
    XFreePixmap (display, image_pixmap);
    XFreePixmap (display, mask_pixmap);
  }
  /* Copy Cursor */
  if (!copyCursor) {
    image_pixmap = XCreateBitmapFromData(display, RootWindow,
            (char *) CopyCurBits, CopyCursorWidth, CopyCursorHeight);
    mask_pixmap  = XCreateBitmapFromData(display, RootWindow,
            (char *) CopyCurMask, CopyCursorWidth, CopyCursorHeight);
    copyCursor   = XCreatePixmapCursor (display, image_pixmap,
            mask_pixmap, &black, &white, CopyCursorX, CopyCursorY);
    XFreePixmap (display, image_pixmap);
    XFreePixmap (display, mask_pixmap);
  }
  /* Move Cursor */
  if (!moveCursor) {
    image_pixmap = XCreateBitmapFromData(display, RootWindow,
            (char *) MoveCurBits, MoveCursorWidth, MoveCursorHeight);
    mask_pixmap  = XCreateBitmapFromData(display, RootWindow,
            (char *) MoveCurMask, MoveCursorWidth, MoveCursorHeight);
    moveCursor   = XCreatePixmapCursor (display, image_pixmap,
            mask_pixmap, &black, &white, MoveCursorX, MoveCursorY);
    XFreePixmap (display, image_pixmap);
    XFreePixmap (display, mask_pixmap);
  }
  /* Link Cursor */
  if (!linkCursor) {
    image_pixmap = XCreateBitmapFromData(display, RootWindow,
            (char *) LinkCurBits, LinkCursorWidth, LinkCursorHeight);
    mask_pixmap  = XCreateBitmapFromData(display, RootWindow,
            (char *) LinkCurMask, LinkCursorWidth, LinkCursorHeight);
    linkCursor   = XCreatePixmapCursor (display, image_pixmap,
            mask_pixmap, &black, &white, LinkCursorX, LinkCursorY);
    XFreePixmap (display, image_pixmap);
    XFreePixmap (display, mask_pixmap);
  }
  /* Ask Cursor */
  if (!askCursor) {
    image_pixmap = XCreateBitmapFromData(display, RootWindow,
            (char *) AskCurBits, AskCursorWidth, AskCursorHeight);
    mask_pixmap  = XCreateBitmapFromData(display, RootWindow,
            (char *) AskCurMask, AskCursorWidth, AskCursorHeight);
    askCursor    = XCreatePixmapCursor (display, image_pixmap,
            mask_pixmap, &black, &white, AskCursorX, AskCursorY);
    XFreePixmap (display, image_pixmap);
    XFreePixmap (display, mask_pixmap);
  }
  /* Register Cursors... */
}; /* TkDND_InitialiseCursors */

Tk_Cursor TkDND_GetCursor(Tcl_Interp *interp, Tcl_Obj *name) {
  static char *DropActions[] = {
    "copy", "move", "link", "ask",  "private", "refuse_drop", "default",
    (char *) NULL
  };
  enum dropactions {
    ActionCopy, ActionMove, ActionLink, ActionAsk, ActionPrivate,
    refuse_drop, ActionDefault
  };
  int status, index;
  Tk_Cursor cursor;

  status = Tcl_GetIndexFromObj(interp, name, (const char **) DropActions,
                              "dropactions", 0, &index);
  if (status == TCL_OK) {
    switch ((enum dropactions) index) {
      case ActionDefault:
      case ActionCopy:    return (Tk_Cursor) copyCursor;
      case ActionMove:    return (Tk_Cursor) moveCursor;
      case ActionLink:    return (Tk_Cursor) linkCursor;
      case ActionAsk:     return (Tk_Cursor) askCursor;
      case ActionPrivate: return (Tk_Cursor) askCursor;
      case refuse_drop:   return (Tk_Cursor) noDropCursor;
    }
  }
  /* The name is not an action. Try Tk cursors... */
  cursor = Tk_AllocCursorFromObj(interp, Tk_MainWindow(interp), name);
  if (cursor == None) {
    Tcl_SetResult(interp, "invalid cursor name", TCL_STATIC);
    return (Tk_Cursor) None;
  }
  return cursor;
}; /* TkDND_GetCursor */
