/* Copyright (C) 1992 by Gustaf Neumann, Stefan Nusser

 *      Wirtschaftsuniversitaet Wien, 
 *      Abteilung fuer Wirtschaftsinformatik
 *      Augasse 2-6, 
 *      A-1090 Vienna, Austria
 *      neumann@wu-wien.ac.at, nusser@wu-wien.ac.at

 * 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 appears in all copies and that both that
 * copyright notice and this permission notice appear in all supporting
 * documentation.  This software is provided "as is" without expressed or
 * implied warranty.

 * Creation: Sun Jun  5 18:42:07 GMT 1994 on mohegan
 * Author: genc
 * Version: 0.96999999999999997335


 */
#define RDD_C
#include <wafe.h>
#ifdef RDD

/* 
 * ******* begin required file <rdd.inc> *******
 */
/* -*- c -*- */
#include "rdd.h"
#include <X11/Shell.h>
#include <X11/Xaw/SimpleMenu.h>

extern void rddSetDragPixmap (
#if NeedFunctionPrototypes
     Pixmap, int, int
#endif
);


extern void rddSetDragCursorOffset(
#if NeedFunctionPrototypes
	int, int
#endif
);

/*
 *  The following command is used to access the Drag'n Drop library
 */


static void
rddDropCallbackProc(w, command, info)
Widget   w;
char     *command;
RddCallbackStruct   *info;
    {
    char *message;

    message = (char *)XtMalloc(info->len + 1);
    strncpy(message, info->data, info->len);
    *(message + info->len) = '\0';

    Tcl_SetVar(wafeInterpreter, "DROP", message, TCL_GLOBAL_ONLY);
    XtFree(message);

    (void) wafeEval(wafeInterpreter, command, "rddDropCallback");
    }



/* RDD myStartAction */
static void
myStartAction (w, event, args, nargs)
Widget w;
XButtonEvent *event;
String *args;
int *nargs;
    {
    static Pixmap pixmap = (Pixmap)NULL;
    Display *dpy = XtDisplay(w);
    Dimension width, height;
    Position  x,y, xRoot, yRoot;
    static GC gc = NULL;

    XtVaGetValues(w,
		  XtNx,&x,
		  XtNy,&y,
		  XtNwidth, &width,
		  XtNheight, &height,
		  NULL);
    XtTranslateCoords(w,x,y,&xRoot,&yRoot);

    if (pixmap && pixmap != XtUnspecifiedPixmap)
	XFreePixmap(dpy, pixmap);

    /* fprintf(stderr,"nargs=%d\n",*nargs);*/


    if (*nargs == 1)
	{
	XrmValue input,output;
	unsigned int depth, border_width, ww, hh;
	int x, y;

	input.addr = *args;	/* Name of bitmap/pixmap */
	input.size = strlen(*args)+1;
	output.addr =  NULL;

	XtConvert(w, "String", &input, "Pixmap", &output);
	if (output.addr)
	    {
	    Window junkWindow;
	    pixmap = *(Pixmap *) output.addr;

	    /*fprintf(stderr,"received pixmap=%d\n",pixmap); */
	    XGetGeometry(dpy, pixmap, &junkWindow, &x, &y,
			 &ww, &hh, &border_width, &depth);
	    /*fprintf(stderr,"survived xgetgeometry w=%u, h=%u\n",ww,hh); */
	    height= hh; width = ww;
	    }
	else
	    {
	    pixmap = XtUnspecifiedPixmap;
	    height = width = 20;
	    }
	}
    else
	{
	/*fprintf(stderr,"nargs=%d\n",*nargs);*/
	/* get pixmap of widget */
	if (!gc)		/* probleme mit multiscreen und diff depth */
	    {
	    XGCValues gcv;
	    gcv.subwindow_mode = IncludeInferiors;
	    gc = XCreateGC (dpy, XtWindow(w), GCSubwindowMode, &gcv);
	    }

	pixmap = XCreatePixmap (dpy, RootWindow(dpy,0),
				width, height, XDefaultDepth(dpy,0));

	/* Create a pixmap of the widget */

	XCopyArea(dpy, XtWindow(w), pixmap, gc, 0,0, width, height, 0,0);
	/*          XCopyArea(dpy, RootWindow(dpy,0), pixmap, gc, x,y, width, height, 0,0);*/
	}

    /* Will take care of global vars: savePixmap, dragPixmap, pixmapwid, pixmaphgt */
    rddSetDragPixmap (pixmap, width, height);

    /* Will take care of global vars: xcursoff, ycursoff */
    rddSetDragCursorOffset(event->x, event->y);

    /* Will take care of global vars bx by */
    rddStartAction (w, event, args, nargs);


    fprintf(stderr,"DONE\n");
    }

/*
 * Yet another set of rdd-actions
 * This time we'll be using a popup shell with a pixmap
 */


static Widget  sh        = NULL;
static Widget  pixShell  = NULL;
static int     shXoffset = 0;
static int     shYoffset = 0;

#define RDD_UNDEF    0
#define RDD_PIXMAP   1
#define RDD_USRSHELL 2
#define RDD_CURSOR   3

static void
rddShStartAction (w, event, args, nargs)
Widget         w;
XButtonEvent  *event;
String        *args;
int           *nargs;
    {
    XrmValue      inVal;
    XrmValue      outVal;
    Window        rootWin;
    Pixmap        shPixmap;
    int           x, y;
    unsigned int  width, height, bw, depth;
    int           mode = RDD_UNDEF;

    sh = NULL;

    if (*nargs == 0)
	{
	fprintf(stderr, "rddShStartAction: Need at least name of pixmap\n");
	return;
	}

    if (*nargs == 1)
	mode = RDD_PIXMAP;
    else
    if (*nargs == 2)
	{
	if (!strcmp(*args,"pixmap"))
	    {
	    mode = RDD_PIXMAP;
	    args++;
	    }
	else
	if (!strcmp(*args,"shell"))
	    {
	    mode = RDD_USRSHELL;
	    args++;
	    }
	else
	    {
	    fprintf(stderr, "rddShStartAction: wrong type <%s>\n", *args);
	    return;
	    }
	}

    if (mode == RDD_PIXMAP)
	{
	if (!pixShell)
	    {
	    pixShell = XtVaCreatePopupShell("rddSh",
					    overrideShellWidgetClass, w,
					    XtNmappedWhenManaged, False,
					    XtNwidth, 10,
					    XtNheight, 10,
					    NULL);

	    /* Window has to be created right away in
	       order to apply a shape mask... */
	    XtRealizeWidget(pixShell);
	    }

	inVal.addr = *args;
	inVal.size = strlen (*args) + 1;
	XtConvert(pixShell, "String", &inVal, "Pixmap", &outVal);

	if (!outVal.addr)
	    return;

	shPixmap =  *(Pixmap *)outVal.addr;
	XGetGeometry(XtDisplay(pixShell), shPixmap,
		     &rootWin, &x, &y, &width, &height, &bw, &depth);

	shXoffset = width/2;
	shYoffset = height/2;

	XtVaSetValues(pixShell,
		      XtNbackgroundPixmap, shPixmap,
		      XtNwidth,            width,
		      XtNheight,           height,
		      XtNx,                event->x_root - shXoffset,
		      XtNy,                event->y_root - shYoffset,
		      NULL);
	sh = pixShell;
	}
    else if (mode == RDD_USRSHELL)
	{
	Dimension w, h;

	sh = name2Widget(*args);
	if (!sh)
	    {
	    fprintf(stderr, "rddShStartAction: no such shell <%s>\n", *args);
	    return;
	    }

	XtRealizeWidget(sh);
	XtVaGetValues(sh,
		      XtNwidth,  &w,
		      XtNheight, &h,
		      NULL);

	shXoffset = w/2;
	shYoffset = h/2;

	XtVaSetValues(sh,
		      XtNx, event->x_root - shXoffset,
		      XtNy, event->y_root - shYoffset,
		      NULL);
	}

    XtPopup(sh, XtGrabNone);
    }


static void
rddShDragAction (w, event, args, nargs)
Widget        w;
XMotionEvent *event;
String       *args;
int          *nargs;
    {
    Position x_root = event->x_root;
    Position y_root = event->y_root;

    if (!sh) return;

    /* the following loop makes dragging on slow displays jumpy
     * but avoids long event queues in the server...
     */
    if (XtAppPending(wafeAppContext))
       {
       XEvent pEvent;
       XMotionEvent *mPtr = (XMotionEvent *)&pEvent;
       XtAppNextEvent(wafeAppContext,&pEvent);
       while ((pEvent.type == MotionNotify) &&
              XtAppPending(wafeAppContext)
	     )
          {
          x_root = mPtr->x_root;
          y_root = mPtr->y_root;
          XtAppNextEvent(wafeAppContext,&pEvent);
          }
       if (pEvent.type != MotionNotify)
	   XtDispatchEvent(&pEvent);

       }

    XMoveWindow(XtDisplay(sh), XtWindow(sh),
		x_root - shXoffset,
		y_root - shYoffset);

    }

static void
rddShDropAction (w, event, args, nargs)
Widget w;
XButtonEvent *event;
String *args;
int *nargs;
    {
    if (!sh) return;

    XtPopdown(sh);
    rddSendDropEvent(w, (XEvent*)event);
    }


/*
 * End of popup-shell rdd-actions.
 */




void
rddWafeInit()
    {
    static XtActionsRec actions[] = {
	{"rddDropAction", (XtActionProc)rddDropAction},
	{"wStartAction", (XtActionProc)myStartAction},
	{"rddStartAction", (XtActionProc)rddStartAction},
	{"rddWafeStartAction", (XtActionProc)rddShStartAction},
	{"rddWafeDragAction", (XtActionProc)rddShDragAction},
	{"rddWafeDropAction", (XtActionProc)rddShDropAction},
	{NULL, NULL},
      };
    XtAppAddActions(wafeAppContext, actions, XtNumber(actions));
    rddInit(wafeTopLevel, wafeAppContext);
    }









/* 
 * ******* end required file <rdd.inc> *******
 */
/* 
 * void
 * rddSetDropData
 * 	in: XtNewString(String)   	# message string
 * 	const: strlen(argv[1])
 */

static int 
cmd_rddSetDropData(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {

     DBUG_ENTER("rddSetDropData");  

     if (argc != 2) 
	 {
	 wafeArgcError("rddSetDropData","",1,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

    /* no need to assign  << localVar1 = argv[1] >>  */ 

     rddSetDropData(XtNewString(argv[1]),strlen(argv[1]));

     DBUG_RETURN (TCL_OK);
     }     


/* 
 * void
 * rddAddDropHandler
 * 	in: Widget		 	# widget	
 * 	const: (XtCallbackProc)rddDropCallbackProc
 * 	in: XtNewString(String)   	# message

 */

static int 
cmd_rddAddDropHandler(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {
     Widget localVar1;

     DBUG_ENTER("rddAddDropHandler");  

     if (argc != 3) 
	 {
	 wafeArgcError("rddAddDropHandler","",2,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

     if (!(localVar1 = (Widget) name2Widget(argv[1])))
          {
          wafeConvError("rddAddDropHandler","1",argv[1],"Widget");
          DBUG_RETURN (TCL_ERROR);
          }

    /* no need to assign  << localVar2 = argv[2] >>  */ 

     rddAddDropHandler(localVar1,(XtCallbackProc)rddDropCallbackProc,XtNewString(argv[2]));

     DBUG_RETURN (TCL_OK);
     }     


#else
#endif

void
wafeInitialize_rddGen()
{
#ifdef RDD
#ifdef RDD
 Tcl_SetVar(wafeInterpreter,"PACKAGES","RDD",TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
#endif
 rddWafeInit();
 Tcl_CreateCommand(wafeInterpreter, "rddSetDropData", cmd_rddSetDropData, NULL, NULL);
 Tcl_CreateCommand(wafeInterpreter, "rddAddDropHandler", cmd_rddAddDropHandler, NULL, NULL);

#else
#endif
}
