/* 
 * main.c --
 *
 *	A simple program to test the toolkit facilities.
 *
 * Copyright 1990 Regents of the University of California.
 * 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 appear in all copies.  The University of California
 * makes no representations about the suitability of this
 * software for any purpose.  It is provided "as is" without
 * express or implied warranty.
 */

#ifndef lint
static char rcsid[] = "$Header: /user6/ouster/wish/RCS/main.c,v 1.59 91/10/31 11:40:15 ouster Exp $ SPRITE (Berkeley)";
#endif

#include "tkConfig.h"
#include "tkInt.h"

/*
 * Declarations for library procedures:
 */

extern int isatty();

Tk_Window w;			/* NULL means window has been deleted. */
Tk_TimerToken timeToken = 0;
int idleHandler = 0;
Tcl_Interp *interp;
int x, y;
Tcl_CmdBuf buffer;
int tty;

/*
 * Information for testing out command-line options:
 */

int synchronize = 0;
char *file = NULL;
char *name = NULL;
char *display = NULL;
char *geometry = NULL;

Tk_ArgvInfo argTable[] = {
    {"-file", TK_ARGV_STRING, (char *) NULL, (char *) &file,
	"File from which to read commands"},
    {"-geometry", TK_ARGV_STRING, (char *) NULL, (char *) &geometry,
	"Initial geometry for window"},
    {"-display", TK_ARGV_STRING, (char *) NULL, (char *) &display,
	"Display to use"},
    {"-name", TK_ARGV_STRING, (char *) NULL, (char *) &name,
	"Name to use for application"},
    {"-sync", TK_ARGV_CONSTANT, (char *) 1, (char *) &synchronize,
	"Use synchronous mode for display server"},
    {(char *) NULL, TK_ARGV_END, (char *) NULL, (char *) NULL,
	(char *) NULL}
};

    /* ARGSUSED */
void
StdinProc(clientData, mask)
    ClientData clientData;		/* Not used. */
    int mask;
{
    char line[200];
    static int gotPartial = 0;
    char *cmd;
    int result;

    if (mask & TK_READABLE) {
	if (fgets(line, 200, stdin) == NULL) {
	    if (!gotPartial) {
		if (tty) {
		    Tcl_Eval(interp, "destroy .", 0, (char **) NULL);
		    exit(0);
		} else {
		    Tk_DeleteFileHandler(0);
		}
		return;
	    } else {
		line[0] = 0;
	    }
	}
	cmd = Tcl_AssembleCmd(buffer, line);
	if (cmd == NULL) {
	    gotPartial = 1;
	    return;
	}
	gotPartial = 0;
	result = Tcl_RecordAndEval(interp, cmd, 0);
	if (*interp->result != 0) {
	    if ((result != TCL_OK) || (tty)) {
		printf("%s\n", interp->result);
	    }
	}
	if (tty) {
	    printf("wish: ");
	    fflush(stdout);
	}
    }
}

	/* ARGSUSED */
static void
StructureProc(clientData, eventPtr)
    ClientData clientData;	/* Information about window. */
    XEvent *eventPtr;		/* Information about event. */
{
    if (eventPtr->type == DestroyNotify) {
	w = NULL;
    }
}

	/* ARGSUSED */
int
GeometryCmd(tkwin, interp, argc, argv)
    Tk_Window tkwin;			/* Application window. */
    Tcl_Interp *interp;			/* Current interpreter. */
    int argc;				/* Number of arguments. */
    char **argv;			/* Argument strings. */
{
    Tk_Window window;
    int width, height;

    if (argc != 4) {
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		" window width height\"", (char *) NULL);
	return TCL_ERROR;
    }
    window = Tk_NameToWindow(interp, argv[1], tkwin);
    if (window == NULL) {
	return TCL_ERROR;
    }
    width = atoi(argv[2]);
    height = atoi(argv[3]);
    Tk_GeometryRequest(window, width, height);
    return TCL_OK;
}

	/* ARGSUSED */
int
ResizeCmd(tkwin, interp, argc, argv)
    Tk_Window tkwin;			/* Application window. */
    Tcl_Interp *interp;			/* Current interpreter. */
    int argc;				/* Number of arguments. */
    char **argv;			/* Argument strings. */
{
    Tk_Window window;
    unsigned int width, height;

    if (argc != 4) {
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		" window width height\"", (char *) NULL);
	return TCL_ERROR;
    }
    window = Tk_NameToWindow(interp, argv[1], tkwin);
    if (window == NULL) {
	return TCL_ERROR;
    }
    width = atoi(argv[2]);
    height = atoi(argv[3]);
    Tk_ResizeWindow(window, width, height);
    return TCL_OK;
}

	/* ARGSUSED */
int
MapCmd(tkwin, interp, argc, argv)
    Tk_Window tkwin;			/* Application window. */
    Tcl_Interp *interp;			/* Current interpreter. */
    int argc;				/* Number of arguments. */
    char **argv;			/* Argument strings. */
{
    Tk_Window window;

    if (argc != 2) {
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		" window\"", (char *) NULL);
	return TCL_ERROR;
    }
    window = Tk_NameToWindow(interp, argv[1], tkwin);
    if (window == NULL) {
	return TCL_ERROR;
    }
    Tk_MapWindow(window);
    return TCL_OK;
}

	/* ARGSUSED */
int
MoveCmd(tkwin, interp, argc, argv)
    Tk_Window tkwin;			/* Application window. */
    Tcl_Interp *interp;			/* Current interpreter. */
    int argc;				/* Number of arguments. */
    char **argv;			/* Argument strings. */
{
    Tk_Window window;
    int x, y;

    if (argc != 4) {
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		" window x y\"", (char *) NULL);
	return TCL_ERROR;
    }
    window = Tk_NameToWindow(interp, argv[1], tkwin);
    if (window == NULL) {
	return TCL_ERROR;
    }
    x = atoi(argv[2]);
    y = atoi(argv[3]);
    Tk_MoveWindow(window, x, y);
    return TCL_OK;
}

	/* ARGSUSED */
int
DotCmd(dummy, interp, argc, argv)
    ClientData dummy;			/* Not used. */
    Tcl_Interp *interp;			/* Current interpreter. */
    int argc;				/* Number of arguments. */
    char **argv;			/* Argument strings. */
{
    int x, y;

    if (argc != 3) {
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		" x y\"", (char *) NULL);
	return TCL_ERROR;
    }
    x = strtol(argv[1], (char **) NULL, 0);
    y = strtol(argv[2], (char **) NULL, 0);
    Tk_MakeWindowExist(w);
    XDrawPoint(Tk_Display(w), Tk_WindowId(w),
	    DefaultGCOfScreen(Tk_Screen(w)), x, y);
    return TCL_OK;
}

	/* ARGSUSED */
int
MovetoCmd(dummy, interp, argc, argv)
    ClientData dummy;			/* Not used. */
    Tcl_Interp *interp;			/* Current interpreter. */
    int argc;				/* Number of arguments. */
    char **argv;			/* Argument strings. */
{
    if (argc != 3) {
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		" x y\"", (char *) NULL);
	return TCL_ERROR;
    }
    x = strtol(argv[1], (char **) NULL, 0);
    y = strtol(argv[2], (char **) NULL, 0);
    return TCL_OK;
}
	/* ARGSUSED */
int
LinetoCmd(dummy, interp, argc, argv)
    ClientData dummy;			/* Not used. */
    Tcl_Interp *interp;			/* Current interpreter. */
    int argc;				/* Number of arguments. */
    char **argv;			/* Argument strings. */
{
    int newX, newY;

    if (argc != 3) {
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		" x y\"", (char *) NULL);
	return TCL_ERROR;
    }
    newX = strtol(argv[1], (char **) NULL, 0);
    newY = strtol(argv[2], (char **) NULL, 0);
    Tk_MakeWindowExist(w);
    XDrawLine(Tk_Display(w), Tk_WindowId(w),
	    DefaultGCOfScreen(Tk_Screen(w)), x, y, newX, newY);
    x = newX;
    y = newY;
    return TCL_OK;
}

	/* ARGSUSED */
int
PolyCmd(tkwin, interp, argc, argv)
    Tk_Window tkwin;			/* Not used. */
    Tcl_Interp *interp;			/* Current interpreter. */
    int argc;				/* Number of arguments. */
    char **argv;			/* Argument strings. */
{
    GC gc;
    XColor *colorPtr;
    XGCValues values;
    Tk_3DBorder border;
    XPoint points[50], *pointPtr;
    int i, numPoints, width, foo;
    Tk_Window tkwin2;

    if ((argc < 8) || (argc > 50) || (argc & 01)) {
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		" window color width x1 y1 x2 y2 ...\"", (char *) NULL);
	return TCL_ERROR;
    }
    tkwin2 = Tk_NameToWindow(interp, argv[1], tkwin);
    if (tkwin2 == NULL) {
	return TCL_ERROR;
    }
    colorPtr = Tk_GetColor(interp, tkwin2, (Colormap) None,
	    Tk_GetUid(argv[2]));
    if (colorPtr == NULL) {
	return TCL_ERROR;
    }
    values.foreground = colorPtr->pixel;
    gc = Tk_GetGC(tkwin2, GCForeground, &values);
    border = Tk_Get3DBorder(interp, tkwin2, (Colormap) None,
	    Tk_GetUid(argv[2]));
    if (border == NULL) {
	return TCL_ERROR;
    }
    if (Tcl_GetInt(interp, argv[3], &width) != TCL_OK) {
	return TCL_ERROR;
    }
    for (i = 4, pointPtr = points; i < argc; i += 2, pointPtr++) {
	if (Tcl_GetInt(interp, argv[i], &foo) != TCL_OK) {
	    return TCL_ERROR;
	}
	pointPtr->x = foo;
	if (Tcl_GetInt(interp, argv[i+1], &foo) != TCL_OK) {
	    return TCL_ERROR;
	}
	pointPtr->y = foo;
    }
    numPoints = (argc-4)/2;
    Tk_MakeWindowExist(tkwin2);
    XFillPolygon(Tk_Display(tkwin2), Tk_WindowId(tkwin2), gc, points,
	    numPoints, Nonconvex, CoordModeOrigin);
    Tk_Draw3DPolygon(Tk_Display(tkwin2), Tk_WindowId(tkwin2), border,
	    points, numPoints, width, 1);
    return TCL_OK;
}

int
main(argc, argv)
    int argc;
    char **argv;
{
    char *args, *p;
    char buf[20];
    int result;
    Tk_3DBorder border;

    interp = Tcl_CreateInterp();
    if (Tk_ParseArgv(interp, (Tk_Window) NULL, &argc, argv, argTable, 0)
	    != TCL_OK) {
	fprintf(stderr, "%s\n", interp->result);
	exit(1);
    }
    if (name == NULL) {
	if (file != NULL) {
	    p = file;
	} else {
	    p = argv[0];
	}
	name = strrchr(p, '/');
	if (name != NULL) {
	    name++;
	} else {
	    name = p;
	}
    }
    w = Tk_CreateMainWindow(interp, display, name);
    if (w == NULL) {
	fprintf(stderr, "%s\n", interp->result);
	exit(1);
    }
    Tk_SetClass(w, "Tk");
    Tk_CreateEventHandler(w, StructureNotifyMask, StructureProc,
	    (ClientData) NULL);
    tty = isatty(0);

    args = Tcl_Merge(argc-1, argv+1);
    Tcl_SetVar(interp, "argv", args, TCL_GLOBAL_ONLY);
    ckfree(args);
    sprintf(buf, "%d", argc-1);
    Tcl_SetVar(interp, "argc", buf, TCL_GLOBAL_ONLY);

    if (synchronize) {
	XSynchronize(Tk_Display(w), True);
    }
    Tk_GeometryRequest(w, 200, 200);
    border = Tk_Get3DBorder(interp, w, None, "#4eee94");
    if (border == NULL) {
	Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
	Tk_SetWindowBackground(w, WhitePixelOfScreen(Tk_Screen(w)));
    } else {
	Tk_SetBackgroundFromBorder(w, border);
    }
    init_cdplayCmds(interp);
    XSetForeground(Tk_Display(w), DefaultGCOfScreen(Tk_Screen(w)),
	    BlackPixelOfScreen(Tk_Screen(w)));
    Tcl_CreateCommand(interp, "dot", DotCmd, (ClientData) w,
	    (void (*)()) NULL);
    Tcl_CreateCommand(interp, "geometry", GeometryCmd, (ClientData) w,
	    (void (*)()) NULL);
    Tcl_CreateCommand(interp, "lineto", LinetoCmd, (ClientData) w,
	    (void (*)()) NULL);
    Tcl_CreateCommand(interp, "map", MapCmd, (ClientData) w,
	    (void (*)()) NULL);
    Tcl_CreateCommand(interp, "move", MoveCmd, (ClientData) w,
	    (void (*)()) NULL);
    Tcl_CreateCommand(interp, "moveto", MovetoCmd, (ClientData) w,
	    (void (*)()) NULL);
    Tcl_CreateCommand(interp, "poly", PolyCmd, (ClientData) w,
	    (void (*)()) NULL);
    Tcl_CreateCommand(interp, "resize", ResizeCmd, (ClientData) w,
	    (void (*)()) NULL);
    if (geometry != NULL) {
	result = Tcl_VarEval(interp, "wm geometry . ", geometry,
		"; wm positionfrom . user", (char *) NULL);
	if (result != TCL_OK) {
	    char *msg;

	    msg = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
	    if (msg == NULL) {
		msg = interp->result;
	    }
	    fprintf(stderr, "%s\n", msg);
	    goto error;
	}
    }
    if (file != NULL) {
	result = Tcl_VarEval(interp, "source ", file, (char *) NULL);
	if (result != TCL_OK) {
	    char *msg;

	    msg = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
	    if (msg == NULL) {
		msg = interp->result;
	    }
	    fprintf(stderr, "%s\n", msg);
	    goto error;
	}
	tty = 0;
    } else {
	tty = isatty(0);
	Tk_CreateFileHandler(0, TK_READABLE|TK_EXCEPTION, StdinProc,
		(ClientData) 0);
	if (tty) {
	    printf("window is %s\n", Tk_Name(w));
	    printf("wish: ");
	}
    }
    fflush(stdout);
    buffer = Tcl_CreateCmdBuf();
    (void) Tcl_Eval(interp, "update", 0, (char **) NULL);

    /*
     * The window could have been deleted as part of the startup
     * script.  If so, don't try to map it.
     */

    if (w != NULL) {
	Tk_MapWindow(w);
    }
    Tk_MainLoop();
    exit(0);

error:
    Tcl_Eval(interp, "destroy .", 0, (char **) NULL);
    exit(1);
    return 0;
}
