/*
 * 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.
 *
 * Date: Mon, Apr 13 1992
 * Author: Stefan Nusser, Gustaf Neumann
 * Version: 0.9
 */

/*
 *             ACTIONSCB.C
 *
 *             This file contains all commands dealing with actions,
 *             callbacks, accelerators, etc and all related functions:
 *
 *             wafePositionCursorCallbackProc
 *             wafePositionCallbackProc
 *             wafeExecActionProc
 */

#define ACTIONSCB_C

#include "wafe.h"

#ifdef ATHENA
#include<X11/Xaw/AsciiText.h>
#ifdef XEDW
#include "Xedw/XedwList.h"
#endif
#endif


/*
 * Additionally, we need the following handler procedures, which are located in the
 * files list.c and scrollbar.c.
 */


#ifdef XEDW
extern void edwListCallbackProc(
#if NeedFunctionPrototypes
     Widget, XtPointer, XtPointer
#endif
);
#endif

typedef struct {
        Widget widget;
        int xoffset;
        int yoffset;
} widgetAndOffset;


void
wafeExecActionProc(w, event, argv, argc)
Widget     w;
XEvent    *event;
char     **argv;
Cardinal  *argc;
    {
    char   assembled[500];        /* Concat the arguments */
    char   command[500];          /* Do % substitution    */
    int    i;
    char  *input = assembled;
    char  *output = command;
    char   buffer[50];
    char  *ptr;
    KeySym dummy;

    DBUG_ENTER("execActionProc");

    wafeCurrentEvent = event;

    assembled[0] = '\0';

    for (i = 0; i < *argc; i++)
	{
	strcat(assembled, argv[i]);
	strcat(assembled, " ");
	}

    DBUG_PRINT("action", ("Assembled command: %s", assembled));

/*    fprintf(stderr,"event type=%d\n",event->type);*/

    for (; *input != '\0'; input++)
	{
	if (*input == '%')
	    {
	    switch (*(++input))
		{
	        case 't':
		   switch (event->type)
		       {
		       case ButtonPress:
		           strcpy(output, "ButtonPress");
			   output += strlen("ButtonPress");
			   break;

		       case ButtonRelease:
			   strcpy(output, "ButtonRelease");
			   output += strlen("ButtonRelease");
			   break;

		       case MotionNotify:
		           strcpy(output, "MotionNotify");
			   output += strlen("MotionNotify");
			   break;

		       case KeyPress:
			   strcpy(output, "KeyPress");
			   output += strlen("KeyPress");
			   break;

		       case KeyRelease:
			   strcpy(output, "KeyRelease");
			   output += strlen("KeyRelease");
			   break;

		       case EnterNotify:
			   strcpy(output, "EnterNotify");
			   output += strlen("EnterNotify");
			   break;

		       case LeaveNotify:
			   strcpy(output, "LeaveNotify");
			   output += strlen("LeaveNotify");
			   break;

		       case ClientMessage:
			   strcpy(output, "ClientMessage");
			   output += strlen("ClientMessage");
			   break;

		       default:
			   strcpy(output, "Unknown");
			   output += strlen("Unknown");
			   break;
			   }
		   break;

	       case 'w':
		   strcpy(output, XtName(w));
		   output += strlen(output);
		   break;

	       case 'W':
                   sprintf(output, "%ld", (long)w);
                   output += strlen(output);
		   break;

	       case 'x':
		   sprintf(output, "%d", event->xbutton.x);
		   output += strlen(output);
		   break;

	       case 'y':
		   sprintf(output, "%d", event->xbutton.y);
		   output += strlen(output);
		   break;

	       case 'X':
		   sprintf(output, "%d", event->xbutton.x_root);
		   output += strlen(output);
		   break;

	       case 'Y':
		   sprintf(output, "%d", event->xbutton.y_root);
		   output += strlen(output);
		   break;

	       case 'a':
		   if (event->type == KeyPress || event->type == KeyRelease)
		       {
		       i = XLookupString((XKeyEvent *)event,
					 output, 50, &dummy, NULL);
		       output += i;
		       break;
		       }

	       case 'b':
		   if (event->type == ButtonPress || event->type == ButtonRelease)
		       {
		       sprintf(output, "%d", event->xbutton.button);
		       output += strlen(output);
		       break;
		       }

	       case 'k':
		   if (event->type == KeyPress || event->type == KeyRelease)
		       {
		       sprintf(output, "%d", event->xkey.keycode);
		       output += strlen(output);
		       break;
		       }


	       case 'p':
		   if (event->type == ClientMessage)
		       {
		       char *p =
			   XGetAtomName(((XClientMessageEvent*)event)->display,
					((XClientMessageEvent*)event)->data.l[0]);
		       if (!p) p = "UNKNOWN";
		       strcpy(output, p);
		       output += strlen(p);
		       break;
		       }

	       case 's':
		   if (event->type == KeyPress || event->type == KeyRelease)
		       {
		       XLookupString((XKeyEvent *)event, buffer, 50,
				     &dummy, NULL);
		       ptr = XKeysymToString(dummy);
		       strcpy(output, ptr);
		       output += strlen(ptr);
		       break;
		       }
	       case 'S':
		   if (event->type == ButtonPress || event->type == ButtonRelease ||
		       event->type == KeyPress || event->type == KeyRelease ||
		       event->type == MotionNotify
		       )
		       {
		       sprintf(output, "%d", event->xbutton.state);
		       output += strlen(output);
		       break;
		       }


	       default:
		   *output++ = '%';
		   *output++ = *input;
		   break;
		   }
	    }
	else
	    *output++ = *input;
	}

    *output = '\0';

    DBUG_PRINT("action", ("command:<<%s>>", command));
    (void) wafeEval(wafeInterpreter, command, "execActionProc");
    wafeCurrentEvent = NULL;
    DBUG_VOID_RETURN;
    }

#define gt0(a) (((a) > 0) ? (a) : 0)

void
wafePositionCallbackProc(w, clientData, callData)
Widget     w;
XtPointer  clientData, callData;
     {
     Position  x,y, xRoot,yRoot, X,Y;
     widgetAndOffset *wao;

     DBUG_ENTER("positionCallbackProc");

     wao = (widgetAndOffset *)clientData;
     XtVaGetValues(wao->widget,
                   XtNx, &x,
                   XtNy, &y,
                   NULL);
     XtTranslateCoords(wafeTopLevel, x, y, &xRoot, &yRoot);
     X = xRoot+(wao->xoffset);
     Y = yRoot+(wao->yoffset);
     XtVaSetValues(w, XtNx, gt0(X), XtNy, gt0(Y), NULL);

     DBUG_VOID_RETURN;
     }


void
wafePositionCursorCallbackProc(w, clientData, callData)
Widget     w;
XtPointer  clientData, callData;
     {
     Window root, child;
     int  x, y, win_x,win_y;
     unsigned int mask;
     int offset = (int)clientData;
     Position X,Y;

     DBUG_ENTER("positionCursorCallbackProc");

     (void) XQueryPointer(XtDisplay(w), XtWindow(wafeTopLevel),
                         &root, &child,
                         &x, &y, &win_x, &win_y,
                         &mask);

     if (offset)
         {
	 X = x-offset;
	 Y = y-offset;
	 XtVaSetValues(w, XtNx, gt0(X), XtNy, gt0(Y), NULL);
         }
      else
	 {
	 Boolean mappedWhenManaged;
	 Dimension width, height;
	 Screen *screen = XtScreen(w);

	 XtVaGetValues(w, XtNmappedWhenManaged, &mappedWhenManaged, NULL);
	 if (mappedWhenManaged)
	     XtVaSetValues(w, XtNmappedWhenManaged, False, NULL);

	 XtRealizeWidget(w);
	 XtVaGetValues(w, XtNwidth, &width,
                          XtNheight, &height,
                          NULL);
	 X = x-width/2;
	 Y = y-height/2;

	 if ((X+width) > WidthOfScreen(screen)) 
	   X = WidthOfScreen(screen) - width;
	 if ((Y+height) > HeightOfScreen(screen)) 
	   Y = HeightOfScreen(screen) - height;

	 if (X < 0) X = 0;
	 if (Y < 0) Y = 0;

	 XtVaSetValues(w, XtNx, X, XtNy, Y,
		       XtNmappedWhenManaged, mappedWhenManaged,
		       NULL);
	 }

     DBUG_VOID_RETURN;
     }

/*
 *  FUNCTION: wafeCallback
 *  Arguments:
 *            Widget - Widget whose attribute is to be set
 *            char * - Name of attribute
 *            proc   - Name of callback procedure to use
 *            arg    - clientData argument
 *
 *  This function is called by the genereated callback procedure (XtGen) and
 *  cares for the special callData handling with list and scrollbar Widgets as
 *  well as for the clientData argument of the XtPopdown callback (a so
 *  called XtPopdownID).
 */

void
wafeCallbackCmd(w, cbAttribute, proc, arg)
Widget w;
String cbAttribute;
XtCallbackProc proc;
String arg;
    {
    Widget pop;

    if (proc == wafePositionCursorCallbackProc)   /* Additional argument is offset... */
	{
	int offset;

	if (!sscanf(arg, "%d", &offset))
	    {
	    wafeConvError("callback", "4", arg, "int");
	    XtFree(arg);
	    return;
	    }

	XtAddCallback(w, cbAttribute, wafePositionCursorCallbackProc,
		      (XtPointer)offset);
	XtFree(arg);
	}
    else
    if (proc == wafePositionCallbackProc)   /* Additional argument is widget/offset */
	{
	widgetAndOffset *wao;
	char *colon, *slash;

	wao = (widgetAndOffset *)XtMalloc(sizeof(widgetAndOffset));
	if ((colon = (char*)strrchr(arg,':')))
	    {
	    *colon = '\0'; colon ++;
	    if ((slash = (char*)strrchr(colon,'/')))
		{
		*slash = '\0'; slash ++;
		if (!sscanf(slash, "%d", &(wao->yoffset)))
		    {
		    wafeConvError("callback", "4", arg,
				  "Widget:xoffset/yoffset");
	            XtFree(arg);
		    return;
		    }
		}

	    if (!sscanf(colon, "%d", &(wao->xoffset)))
		{
		wafeConvError("callback", "4", arg, "Widget:xoffset/yoffset");
	        XtFree(arg);
		return;
		}
	    if (!slash) wao->yoffset = wao->xoffset;
	    }
	else
	    {
	    wao->xoffset = 50;
	    wao->yoffset = 50;
	    }
	if (!(wao->widget = name2Widget(arg)))
	    {
	    wafeConvError("callback", "4", arg, "Widget:xoffset/yoffset");
	    XtFree(arg);
	    return;
	    }

	XtAddCallback(w, cbAttribute, wafePositionCallbackProc, (XtPointer)wao);
	XtFree(arg);
	}
    else
    if (proc == XtCallbackPopdown)   /* Build up XtPopdownID... */
	{
	XtPopdownID      pdPtr;
	pdPtr = (XtPopdownID)XtMalloc(sizeof(XtPopdownIDRec));

	if (!(pdPtr->shell_widget = name2Widget(strtok(arg, " "))))
	    {
	    wafeConvError("callback-popdown", "4", arg, "Widget");
	    XtFree(arg);
	    return;
	    }

	if (!(pdPtr->enable_widget = name2Widget(strtok(NULL, " "))))
	    {
	    wafeConvError("callback-popdown", "4", arg, "Widget");
	    XtFree(arg);
	    return;
	    }
	XtAddCallback(w, cbAttribute, XtCallbackPopdown, pdPtr);

	XtFree(arg);
	}
    else if (proc == wafeExecCallbackProc)
        {
	XtAddCallback(w, cbAttribute, proc, arg);
	XtFree(arg);
        }
    else
	{
	if (!(pop = name2Widget(arg)))  /* For all other callbacks: arg is a Widget */
	    {
	    wafeConvError("callback", "4", arg, "Widget");
	    XtFree(arg);
	    return;
	    }
	XtAddCallback(w, cbAttribute, proc, (XtPointer)pop);
	XtFree(arg);
	}
    return;
    }


