/* 
 * tkMegaWidget.c --
 *
 *	This module implements "magawidget" widgets for the Tk
 *	toolkit.  MegaWidgets are windows with a background color
 *	and possibly a 3-D effect, and the ability to handle
 *      major/minor commands and user definable options.
 *
 * Copyright (c) 1993 by Sven Delmas
 * All rights reserved.
 * See the file COPYRIGHT for the copyright notes.
 *
 *
 * This source is based upon the file tkFrame.c from:
 *
 * John Ousterhout
 *
 * Copyright (c) 1990-1993 The Regents of the University of California.
 * All rights reserved.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

#if defined(USE_MEGAWIDGET)

#ifndef lint
static char *AtFSid = "$Header: tkMegaWidget.c[2.0] Thu May  5 00:03:58 1994 garfield@mydomain.de frozen $";
#endif /* not lint */

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

/*
 * Support for a separate widget tree for each private
 * interpreter. This code is currently not working!!!
 */
#define TK_SUPPORT 1

/*
 * Add some debugging code.
 */
/*#define DEBUGGING 1*/

/*
 * I do not know why, but several window managers require multiple
 * reparent events. Right now a value of 25 should be enough.
 */
#define REPARENT_LOOPS 25

#if defined(USE_DES)
#include "des.h"
#endif

/*
 * A data structure of the following type is kept for each
 * magawidget that currently exists for this process:
 */

static int initialized = 0;

static Tcl_HashTable megaWidgetInterpsTable;

typedef struct {
  int refCount;
  Tcl_Interp *interp;
  int crypting;
#if defined(TK_SUPPORT)
  Tk_Window mainWin;
  Tk_Window embedWin;
#endif
} MegaWidgetInterps;

typedef struct {
  char *minorCmd;
} MegaWidgetMinor;

typedef struct {
  char *name;
  char *class;
  char *defaultValue;
  char *value;
  char *optionCmd;
  int type;
} MegaWidgetOption;

typedef struct {
    Tk_Window tkwin;		/* Window that embodies the magawidget.  NULL
				 * means that the window has been destroyed
				 * but the data structures haven't yet been
				 * cleaned up.*/
    Display *display;		/* Display containing widget.  Used, among
				 * other things, so that resources can be
				 * freed even after tkwin has gone away. */
    Tcl_Interp *interp;		/* Interpreter associated with
				 * widget.  Used to delete widget
				 * command.  */
    Tk_3DBorder border;		/* Structure used to draw 3-D border and
				 * background. */
    int borderWidth;		/* Width of 3-D border (if any). */
    int relief;			/* 3-d effect: TK_RELIEF_RAISED etc. */
    int width;			/* Width to request for window.  <= 0 means
				 * don't request any size. */
    int height;			/* Height to request for window.  <= 0 means
				 * don't request any size. */
    char *geometry;		/* Geometry that user requested.  NULL
				 * means use width and height instead. 
				 * Malloc'ed. */
    char *class;		/* The class of the widget. */
    Cursor cursor;		/* Current cursor for window, or None. */
    int flags;			/* Various flags;  see below for
				 * definitions. */

    char *createCommand;	/* This command is evaluated at startup. */
    char *userFile;		/* This is an user file that is */
				/* loaded at startup. */
    char *libFile;		/* This is the system library. */
    int crypting;               /* This flag is set to true, when the */
				/* userFile and libFile files are */
				/* encrypted. */
    int tkSupport;              /* This flag is set to true, when the */
				/* local interpreter should use a */
				/* local widget tree too. */
				/* encrypted. */
    char *interpreter;		/* The interpreter to use. */
    Tcl_Interp *internalInterp; /* The interpreter attatched to the
			         * widget. */
    char *pathName;		/* The pathName of this widget. Used
				 * when the widget is destroyed. */
#if defined(TK_SUPPORT)
    Tk_Window mainWin;          /* The main Tk window. */
    Tk_Window embedWin;         /* The embedded Tk window. */
#endif
    Tcl_HashTable minors;       /* All minor commands attatched to the
				 * widget. */
    Tcl_HashTable options;      /* All options attatched to the 
				 * widget. */
} MegaWidget;

/*
 * Flag bits for magawidgets:
 *
 * REDRAW_PENDING:		Non-zero means a DoWhenIdle handler
 *				has already been queued to redraw
 *				this window.
 * CLEAR_NEEDED;		Need to clear the window when redrawing.
 */

#define REDRAW_PENDING		1
#define CLEAR_NEEDED		2
#define CALLED_CONFIG		4
#define TK_MEGA_CONFIG_HIDDEN   16
#define TK_MEGA_CONFIG_INTERNAL 32
#define TK_MEGA_CONFIG_INITIAL  64

static Tk_ConfigSpec configSpecs[] = {
    {TK_CONFIG_BORDER, "-background", "background", "Background",
        DEF_FRAME_BG_COLOR, Tk_Offset(MegaWidget, border),
        TK_CONFIG_COLOR_ONLY},
    {TK_CONFIG_BORDER, "-background", "background", "Background",
        DEF_FRAME_BG_MONO, Tk_Offset(MegaWidget, border),
        TK_CONFIG_MONO_ONLY},
    {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
	(char *) NULL, 0, 0},
    {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
	(char *) NULL, 0, 0},
    {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
	DEF_FRAME_BORDER_WIDTH, Tk_Offset(MegaWidget, borderWidth), 0},
    {TK_CONFIG_STRING, "-class", "class", "Class",
        "", Tk_Offset(MegaWidget, class), TK_CONFIG_NULL_OK},
    {TK_CONFIG_STRING, "-createcommand", "createCommand", "CreateCommand",
	"", Tk_Offset(MegaWidget, createCommand), 0},
    {TK_CONFIG_INT, "-crypting", "crypting", "Crypting",
	"0", Tk_Offset(MegaWidget, crypting), 0},
    {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
        DEF_FRAME_CURSOR, Tk_Offset(MegaWidget, cursor),
        TK_CONFIG_NULL_OK},
    {TK_CONFIG_STRING, "-geometry", "geometry", "Geometry",
        DEF_FRAME_GEOMETRY, Tk_Offset(MegaWidget, geometry),
        TK_CONFIG_NULL_OK},
    {TK_CONFIG_PIXELS, "-height", "height", "Height",
	DEF_FRAME_HEIGHT, Tk_Offset(MegaWidget, height), 0},
    {TK_CONFIG_STRING, "-interpreter", "interpreter", "Interpreter",
	"", Tk_Offset(MegaWidget, interpreter), 0},
    {TK_CONFIG_STRING, "-libfile", "libFile", "LibFile",
	"", Tk_Offset(MegaWidget, libFile), 0},
    {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
	DEF_FRAME_RELIEF, Tk_Offset(MegaWidget, relief), 0},
    {TK_CONFIG_INT, "-tksupport", "tkSupport", "TkSupport",
	"0", Tk_Offset(MegaWidget, tkSupport), 0},
    {TK_CONFIG_STRING, "-userfile", "userFile", "UserFile",
	"", Tk_Offset(MegaWidget, userFile), 0},
    {TK_CONFIG_PIXELS, "-width", "width", "Width",
	DEF_FRAME_WIDTH, Tk_Offset(MegaWidget, width), 0},
    {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
	(char *) NULL, 0, 0}
};

/*
 * Forward declarations for procedures defined later in this file:
 */

static int      TkInitMegaWidget _ANSI_ARGS_((Tcl_Interp *interp,
		    Tk_Window tkwin, int toplevel, int argc,
		    char **argv));
static int	ConfigureMegaWidget _ANSI_ARGS_((Tcl_Interp *interp,
		    MegaWidget *megaWidgetPtr, int argc,
                    char **argv, int flags));
static void	DestroyMegaWidget _ANSI_ARGS_((ClientData clientData));
static void	DisplayMegaWidget _ANSI_ARGS_((ClientData clientData));
static void	MegaWidgetEventProc _ANSI_ARGS_((ClientData clientData,
		    XEvent *eventPtr));
static void	MegaWidgetPrivateEventProc _ANSI_ARGS_((ClientData clientData,
		    XEvent *eventPtr));
static int	MegaWidgetWidgetCmd _ANSI_ARGS_((ClientData clientData,
		    Tcl_Interp *interp, int argc, char **argv));
static void	MapMegaWidget _ANSI_ARGS_((ClientData clientData));
static void	RecursiveConfigMegaWidget _ANSI_ARGS_((Tcl_Interp *interp,
		    TkWindow *rootWinPtr, int argc, char **argv));

/*
 *--------------------------------------------------------------
 *
 * Tk_MegaWidgetCmd --
 *
 *	This procedure is invoked to process the "magawidget" and
 *	"toplevel" Tcl commands.  See the user documentation for
 *	details on what it does.
 *
 * Results:
 *	A standard Tcl result.
 *
 * Side effects:
 *	See the user documentation.
 *
 *--------------------------------------------------------------
 */

int
Tk_MegaWidgetCmd(clientData, interp, argc, argv)
    ClientData clientData;	/* Main window associated with
				 * interpreter. */
    Tcl_Interp *interp;		/* Current interpreter. */
    int argc;			/* Number of arguments. */
    char **argv;		/* Argument strings. */
{
  Tk_Window tkwin = (Tk_Window) clientData;
  Tk_Window new;
  Tk_Uid screenUid;
  char *className, *screen;
  int src, dst;

  if (argc < 2) {
    Tcl_AppendResult(interp, "wrong # args: should be \"",
		     argv[0], " pathName ?options?\"", (char *) NULL);
    return TCL_ERROR;
  }
  
  /*
   * The code below is a special hack that extracts a few key
   * options from the argument list now, rather than letting
   * ConfigureMegaWidget do it.  This is necessary because we have
   * to know the window's screen (if it's top-level) and its
   * class before creating the window.
   */
  
  screen = NULL;
  className = (argv[0][0] == 't') ? "Toplevel" : "MegaWidget";
  for (src = 2, dst = 2; src < argc;  src += 2) {
    char c;
    
    c = argv[src][1];
    if ((argv[0][0] == 't') && (c == 's')
	&& (strncmp(argv[src], "-screen", strlen(argv[src])) == 0)) {
      screen = argv[src+1];
    } else {
      argv[dst] = argv[src];
      argv[dst+1] = argv[src+1];
      dst += 2;
    }
  }
  argc -= src-dst;
  
  /*
   * Provide a default screen for top-level windows (same as screen
   * of parent window).
   */
  
  if ((argv[0][0] == 't') && (screen == NULL)) {
    screen = "";
  }
  if (screen != NULL) {
    screenUid = Tk_GetUid(screen);
  } else {
    screenUid = NULL;
  }
  
  /*
   * Create the window and initialize our structures and event handlers.
   */
  
  new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], screenUid);
  if (new == NULL) {
    return TCL_ERROR;
  }
  Tk_SetClass(new, className);
  return TkInitMegaWidget(interp, new, (screenUid != NULL), argc-2, argv+2);
}

/*
 *----------------------------------------------------------------------
 *
 * TkInitMegaWidget --
 *
 *	This procedure initializes a magawidget or toplevel widget.  It's
 *	separate from Tk_MegaWidgetCmd so that it can be used for the
 *	main window, which has already been created elsewhere.
 *
 * Results:
 *	A standard Tcl completion code.
 *
 * Side effects:
 *	A widget record gets allocated, handlers get set up, etc..
 *
 *----------------------------------------------------------------------
 */

static int
TkInitMegaWidget(interp, tkwin, toplevel, argc, argv)
    Tcl_Interp *interp;			/* Interpreter associated with the
					 * application. */
    Tk_Window tkwin;			/* Window to use for magawidget or
					 * top-level.   Caller must already
					 * have set window's class. */
    int toplevel;			/* Non-zero means that this is a
					 * top-level window, 0 means it's a
					 * magawidget. */
    int argc;				/* Number of configuration arguments
					 * (not including class command and
					 * window name). */
    char *argv[];			/* Configuration arguments. */
{
  register MegaWidget *megaWidgetPtr;
  int fileId = -1, new, readLen;
  unsigned int counter;
  char *cmdBuffer = NULL, *readBuffer = NULL, *value, msg[200], iv[8];
  struct stat statBuf;
  MegaWidgetInterps *megaWidgetInterps;
  Tcl_HashEntry *megaWidgetInterpsHashPtr;
  Tcl_DString command;
#if defined(USE_DES)
  des_cblock kk;
  des_key_schedule ks;
#endif
  
  if (!initialized) {
    initialized = 1;
    Tcl_InitHashTable(&megaWidgetInterpsTable, TCL_STRING_KEYS);
  }
  
  megaWidgetPtr = (MegaWidget *) ckalloc(sizeof(MegaWidget));
  megaWidgetPtr->tkwin = tkwin;
  megaWidgetPtr->display = Tk_Display(tkwin);
  megaWidgetPtr->interp = interp;
  megaWidgetPtr->border = NULL;
  megaWidgetPtr->borderWidth = 0;
  megaWidgetPtr->relief = TK_RELIEF_FLAT;
  megaWidgetPtr->width = 0;
  megaWidgetPtr->height = 0;
  megaWidgetPtr->geometry = NULL;
  megaWidgetPtr->cursor = None;
  megaWidgetPtr->flags = 0;
  
  megaWidgetPtr->class = NULL;
  megaWidgetPtr->createCommand = NULL;
  megaWidgetPtr->crypting = 0;
  megaWidgetPtr->libFile = NULL;
  megaWidgetPtr->userFile = NULL;
  megaWidgetPtr->interpreter = NULL;
  megaWidgetPtr->internalInterp = interp;
  megaWidgetPtr->tkSupport = 0;
  megaWidgetPtr->pathName =
    ckalloc(strlen(Tk_PathName(megaWidgetPtr->tkwin)) + 2);
  strcpy(megaWidgetPtr->pathName, Tk_PathName(megaWidgetPtr->tkwin));
#if defined(TK_SUPPORT)
  megaWidgetPtr->mainWin = NULL;
  megaWidgetPtr->embedWin = NULL;
#endif

  Tcl_InitHashTable(&megaWidgetPtr->minors, TCL_STRING_KEYS);
  Tcl_InitHashTable(&megaWidgetPtr->options, TCL_STRING_KEYS);
  Tk_CreateEventHandler(megaWidgetPtr->tkwin,
			ExposureMask|StructureNotifyMask,
			MegaWidgetEventProc, (ClientData) megaWidgetPtr);
  Tcl_CreateCommand(interp, Tk_PathName(megaWidgetPtr->tkwin),
		    MegaWidgetWidgetCmd, (ClientData) megaWidgetPtr,
		    (void (*)()) NULL);
  
  if (ConfigureMegaWidget(interp, megaWidgetPtr, argc, argv,
			  TK_MEGA_CONFIG_INITIAL) != TCL_OK) {
    Tk_DestroyWindow(megaWidgetPtr->tkwin);
    return TCL_ERROR;
  }
  
  /* Create new interpreter. */
  if (megaWidgetPtr->interpreter != NULL &&
      strlen(megaWidgetPtr->interpreter) > (size_t) 0) {
    megaWidgetInterpsHashPtr =
      Tcl_CreateHashEntry(&megaWidgetInterpsTable,
			  megaWidgetPtr->interpreter, &new);
    if (new) {
      megaWidgetInterps = (MegaWidgetInterps *)
	ckalloc(sizeof(MegaWidgetInterps));
      megaWidgetInterps->refCount = 1;
      megaWidgetInterps->crypting = megaWidgetPtr->crypting;
      megaWidgetInterps->mainWin = NULL;
      megaWidgetInterps->embedWin = NULL;
      megaWidgetPtr->internalInterp = interp;
      Tcl_SetHashValue(megaWidgetInterpsHashPtr, megaWidgetInterps);
    } else {
      megaWidgetInterps = (MegaWidgetInterps *)
	Tcl_GetHashValue(megaWidgetInterpsHashPtr);
      megaWidgetInterps->refCount++;
      megaWidgetPtr->internalInterp = megaWidgetInterps->interp;
      megaWidgetPtr->mainWin = megaWidgetInterps->mainWin;
    }
    
    /* A new interpreter has to be created... */
    if (megaWidgetPtr->internalInterp == interp) {
      megaWidgetInterps->interp = Tcl_CreateInterp();
#if defined(TK_SUPPORT)
      if (megaWidgetInterps->mainWin == NULL && megaWidgetPtr->tkSupport) {
	megaWidgetInterps->mainWin = 
	  Tk_CreateMainWindow(megaWidgetInterps->interp, "", 
			      megaWidgetPtr->interpreter, "Tk");
	if (megaWidgetInterps->mainWin == NULL) {
	  fprintf(stderr, "%s\n", megaWidgetInterps->interp->result);
	  exit(1);
	}
	megaWidgetPtr->mainWin = megaWidgetInterps->mainWin;
	if (Tcl_AppInit(megaWidgetInterps->interp) != TCL_OK) {
	  fprintf(stderr, "Tcl_AppInit failed: %s\n", 
		  megaWidgetInterps->interp->result);
	}
      }
#endif
      megaWidgetPtr->internalInterp = megaWidgetInterps->interp;
      if ((value = Tcl_GetVar(interp, "argc",
			      TCL_GLOBAL_ONLY)) != NULL) {
	Tcl_SetVar(megaWidgetPtr->internalInterp, "argc",
		   value, TCL_GLOBAL_ONLY);
      }
      if ((value = Tcl_GetVar(interp, "argv",
			      TCL_GLOBAL_ONLY)) != NULL) {
	Tcl_SetVar(megaWidgetPtr->internalInterp, "argv",
		   value, TCL_GLOBAL_ONLY);
      }
      if ((value = Tcl_GetVar(interp, "argv0",
			      TCL_GLOBAL_ONLY)) != NULL) {
	Tcl_SetVar(megaWidgetPtr->internalInterp, "argv0",
		   value, TCL_GLOBAL_ONLY);
      }
      Tcl_SetVar(megaWidgetPtr->internalInterp, "tcl_interactive",
		 "0", TCL_GLOBAL_ONLY);
      Tcl_SetVar(megaWidgetPtr->internalInterp, "mega_interpreter",
		 megaWidgetPtr->interpreter, TCL_GLOBAL_ONLY);
      sprintf(msg, "%d", megaWidgetPtr->crypting);
      Tcl_SetVar(megaWidgetPtr->internalInterp, "mega_crypting",
		 msg, TCL_GLOBAL_ONLY);
    }
    
#if defined(TK_SUPPORT)
    if (megaWidgetPtr->mainWin != NULL) {
      Tcl_DStringInit(&command);
      Tcl_DStringAppend(&command, "toplevel .", -1);
      Tcl_DStringAppend(&command, Tk_Name(megaWidgetPtr->tkwin), -1);
      Tcl_DStringAppend(&command, " ; wm minsize .", -1);
      Tcl_DStringAppend(&command, Tk_Name(megaWidgetPtr->tkwin), -1);
      Tcl_DStringAppend(&command, " 0 0 ; wm maxsize . ", -1);
      Tcl_DStringAppend(&command, Tk_Name(megaWidgetPtr->tkwin), -1);
      Tcl_DStringAppend(&command, " 10000 10000", -1);
      Tcl_Eval(megaWidgetPtr->internalInterp, command.string);
      Tcl_DStringFree(&command);
      Tcl_DStringInit(&command);
      Tcl_DStringAppend(&command, ".", -1);
      Tcl_DStringAppend(&command, Tk_Name(megaWidgetPtr->tkwin), -1);
      megaWidgetInterps->embedWin =
	Tk_NameToWindow(megaWidgetPtr->internalInterp, 
			command.string, megaWidgetPtr->mainWin);
      Tcl_DStringFree(&command);
      if (megaWidgetInterps->embedWin == NULL) {
	Tk_DestroyWindow(megaWidgetPtr->mainWin);
	Tk_DestroyWindow(megaWidgetPtr->tkwin);
	return TCL_ERROR;
      }
      Tk_CreateEventHandler(megaWidgetInterps->embedWin,
			    ExposureMask|StructureNotifyMask,
			    MegaWidgetPrivateEventProc,
			    (ClientData) megaWidgetPtr);
      megaWidgetPtr->embedWin = megaWidgetInterps->embedWin;

      Tk_MakeWindowExist(tkwin);
      Tk_MakeWindowExist(megaWidgetPtr->mainWin);
      Tk_MakeWindowExist(megaWidgetPtr->embedWin);
      if (megaWidgetPtr->mainWin != NULL) {
	Tcl_DStringInit(&command);
	Tcl_DStringAppend(&command, "wm withdraw .", -1);
	Tcl_Eval(megaWidgetPtr->internalInterp, command.string);
      }
      if (megaWidgetPtr->embedWin != NULL) {
	for (counter = 0; counter < REPARENT_LOOPS; counter++) {
	  XReparentWindow(Tk_Display(megaWidgetPtr->embedWin), 
			  Tk_WindowId(megaWidgetPtr->embedWin),
			  Tk_WindowId(tkwin), 0, 0);
	  XSync(Tk_Display(megaWidgetPtr->embedWin), False);
	}
      }
    }
#endif

    /* Create the new widget command in the additional interpreter. */
    /* The command gets the prefix "mega" to allow the access to */
    /* the original widget command. */
    value = ckalloc(strlen(Tk_PathName(megaWidgetPtr->tkwin)) + 20);
    strcpy(value, "mega");
    strcat(value, Tk_PathName(megaWidgetPtr->tkwin));
    Tcl_CreateCommand(megaWidgetPtr->internalInterp,
		      value, MegaWidgetWidgetCmd,
		      (ClientData) megaWidgetPtr,
		      (void (*)()) NULL);
    ckfree((char *) value);
  } else {
    megaWidgetInterpsHashPtr =
      Tcl_CreateHashEntry(&megaWidgetInterpsTable,
			  "TKMEGAWIDGET-MAIN", &new);
    if (new) {
      megaWidgetInterps = (MegaWidgetInterps *)
	ckalloc(sizeof(MegaWidgetInterps));
      megaWidgetInterps->refCount = 1;
      megaWidgetInterps->crypting = 0;
      Tcl_SetHashValue(megaWidgetInterpsHashPtr, megaWidgetInterps);
    } else {
      megaWidgetInterps = (MegaWidgetInterps *)
	Tcl_GetHashValue(megaWidgetInterpsHashPtr);
      megaWidgetInterps->refCount++;
    }
    megaWidgetInterps->interp = interp;
  }

  /* Once we decided wheather to use crypting we have to contionue */
  /* with that. We also want to guarantee the crypting is only done in */
  /* a secure interpreter. */
  if (megaWidgetPtr->crypting == 1 &&
      interp == megaWidgetPtr->internalInterp) {
    Tcl_AppendResult(interp, "crypting only in a secure interpreter", 
		     (char *) NULL);
    goto error;
  }
  if (megaWidgetPtr->crypting != megaWidgetInterps->crypting) {
    Tcl_AppendResult(interp, "previous crypting selection does not match",
		     (char *) NULL);
    goto error;
  }

  /* initialize decryption */
#if defined(USE_DES)
  if (megaWidgetPtr->libFile != NULL || megaWidgetPtr->userFile != NULL) {
    des_string_to_key("abcdabcd", (des_cblock *) kk);
    des_set_key((des_cblock *) kk, ks);
  }
#endif
  
  /* Initialize the interpreter from Tcl libs. */
  if (megaWidgetPtr->libFile != NULL &&
      strlen(megaWidgetPtr->libFile) > (size_t) 0) {
    if (megaWidgetPtr->crypting) {
      fileId = open(megaWidgetPtr->libFile, O_RDONLY, 0);
      if (fileId < 0) {
	Tcl_AppendResult(interp, "couldn't open file \"",
			 megaWidgetPtr->libFile, "\": ",
			 Tcl_PosixError(megaWidgetPtr->internalInterp),
			 (char *) NULL);
	goto error;
      }
      if (fstat(fileId, &statBuf) == -1) {
	Tcl_AppendResult(interp, "couldn't stat file \"",
			 megaWidgetPtr->libFile, "\": ",
			 Tcl_PosixError(megaWidgetPtr->internalInterp),
			 (char *) NULL);
	goto error;
      }
      readLen = statBuf.st_size;
      readBuffer = (char *) ckalloc((unsigned) readLen + 9);
      cmdBuffer = (char *) ckalloc((unsigned) readLen + 9);
      if (read(fileId, readBuffer, readLen) != readLen) {
	Tcl_AppendResult(interp, "couldn't read file \"",
			 megaWidgetPtr->libFile, "\": ",
			 Tcl_PosixError(megaWidgetPtr->internalInterp),
			 (char *) NULL);
	goto error;
      }
      memset(iv, 0, sizeof(iv));
#if defined(USE_DES)
      des_cbc_encrypt((des_cblock *) readBuffer,
		      (des_cblock *) cmdBuffer,
		      (long) readLen, ks,
		      (des_cblock *) iv, DES_DECRYPT);
      cmdBuffer[readLen - 8 + cmdBuffer[readLen-1]] = '\0';
      if (close(fileId) != 0) {
	Tcl_AppendResult(interp, "couldn't close file \"",
			 megaWidgetPtr->libFile, "\": ",
			 Tcl_PosixError(megaWidgetPtr->internalInterp),
			 (char *) NULL);
	goto error;
      }
      if (Tcl_Eval(megaWidgetPtr->internalInterp, cmdBuffer) == TCL_ERROR) {
	if (megaWidgetPtr->internalInterp != interp) {
	  Tcl_AppendResult(interp,
			   megaWidgetPtr->internalInterp->result,
			   (char *) NULL);
	}
	sprintf(msg, "\n    (file \"%.150s\" line %d)",
		megaWidgetPtr->libFile,
		megaWidgetPtr->internalInterp->errorLine);
	Tcl_AddErrorInfo(interp, msg);
	goto error;
      }
      ckfree((char *) cmdBuffer);
      ckfree((char *) readBuffer);
#else
      ckfree((char *) cmdBuffer);
      ckfree((char *) readBuffer);
      Tcl_AppendResult(interp, "no encryption available \"",
		       megaWidgetPtr->libFile, (char *) NULL);
      goto error;
#endif
    } else {
      if (Tcl_EvalFile(megaWidgetPtr->internalInterp,
		       megaWidgetPtr->libFile) != TCL_OK) {
	if (megaWidgetPtr->internalInterp != interp) {
	  Tcl_AppendResult(interp,
			   megaWidgetPtr->internalInterp->result,
			   (char *) NULL);
	}
	goto error;
      }
    }
  }
    
  /* Load the user library file. */
  if (megaWidgetPtr->userFile != NULL &&
      strlen(megaWidgetPtr->userFile) > (size_t) 0) {
    if (megaWidgetPtr->crypting) {
      fileId = open(megaWidgetPtr->userFile, O_RDONLY, 0);
      if (fileId < 0) {
	Tcl_AppendResult(interp, "couldn't open file \"",
			 megaWidgetPtr->userFile, "\": ",
			 Tcl_PosixError(megaWidgetPtr->internalInterp),
			 (char *) NULL);
	goto error;
      }
      if (fstat(fileId, &statBuf) == -1) {
	Tcl_AppendResult(interp, "couldn't stat file \"",
			 megaWidgetPtr->userFile, "\": ",
			 Tcl_PosixError(megaWidgetPtr->internalInterp),
			 (char *) NULL);
	goto error;
      }
      readLen = statBuf.st_size;
      readBuffer = (char *) ckalloc((unsigned) readLen + 9);
      cmdBuffer = (char *) ckalloc((unsigned) readLen + 9);
      if (read(fileId, readBuffer, readLen) != readLen) {
	Tcl_AppendResult(interp, "couldn't read file \"",
			 megaWidgetPtr->userFile, "\": ",
			 Tcl_PosixError(megaWidgetPtr->internalInterp),
			 (char *) NULL);
	goto error;
      }
      memset(iv, 0, sizeof(iv));
#if defined(USE_DES)
      des_cbc_encrypt((des_cblock *) readBuffer,
		      (des_cblock *) cmdBuffer,
		      (long) readLen, ks,
		      (des_cblock *) iv, DES_DECRYPT);
      cmdBuffer[readLen - 8 + cmdBuffer[readLen-1]] = '\0';
      if (close(fileId) != 0) {
	Tcl_AppendResult(interp, "couldn't close file \"",
			 megaWidgetPtr->userFile, "\": ",
			 Tcl_PosixError(megaWidgetPtr->internalInterp),
			 (char *) NULL);
	goto error;
      }
      if (Tcl_Eval(megaWidgetPtr->internalInterp, cmdBuffer) == TCL_ERROR) {
	if (megaWidgetPtr->internalInterp != interp) {
	  Tcl_AppendResult(interp,
			   megaWidgetPtr->internalInterp->result,
			   (char *) NULL);
	}
	sprintf(msg, "\n    (file \"%.150s\" line %d)",
		megaWidgetPtr->userFile,
		megaWidgetPtr->internalInterp->errorLine);
	Tcl_AddErrorInfo(interp, msg);
	goto error;
      }
      ckfree((char *) cmdBuffer);
      ckfree((char *) readBuffer);
#else
      ckfree((char *) cmdBuffer);
      ckfree((char *) readBuffer);
      Tcl_AppendResult(interp, "no encryption available \"",
		       megaWidgetPtr->libFile, (char *) NULL);
      goto error;
#endif
    } else {
      if (Tcl_EvalFile(megaWidgetPtr->internalInterp,
		       megaWidgetPtr->userFile) != TCL_OK) {
	if (megaWidgetPtr->internalInterp != interp) {
	  Tcl_AppendResult(interp,
			   megaWidgetPtr->internalInterp->result,
			   (char *) NULL);
	}
	goto error;
      }
    }
  }
  
  /* Run initialization command. */
  if (megaWidgetPtr->createCommand != NULL &&
      strlen(megaWidgetPtr->createCommand) > (size_t) 0) {
    Tcl_DStringInit(&command);
    Tcl_DStringAppend(&command, megaWidgetPtr->createCommand, -1);
    Tcl_DStringAppend(&command, " ", -1);
    Tcl_DStringAppend(&command, Tk_PathName(megaWidgetPtr->tkwin), -1);
    for (counter = 0; counter < argc; counter++) {
      Tcl_DStringAppend(&command, " ", -1);
      Tcl_DStringAppend(&command, argv[counter], -1);
    }
    if (Tcl_Eval(megaWidgetPtr->internalInterp,
		 command.string) != TCL_OK) {
      if (megaWidgetPtr->internalInterp != interp) {
	Tcl_AppendResult(interp,
			 megaWidgetPtr->internalInterp->result,
			 (char *) NULL);
      }
      goto error;
    }
    Tcl_DStringFree(&command);
  }
  
  if (toplevel) {
    Tk_DoWhenIdle(MapMegaWidget, (ClientData) megaWidgetPtr);
  }
  interp->result = Tk_PathName(megaWidgetPtr->tkwin);
  return TCL_OK;

 error:
  if (fileId >= 0) {
    close(fileId);
  }
  if (cmdBuffer != NULL) {
    ckfree((char *) cmdBuffer);
  }
  if (readBuffer != NULL) {
    ckfree((char *) readBuffer);
  }
  Tk_DestroyWindow(megaWidgetPtr->tkwin);
  return TCL_ERROR;
}

/*
 *--------------------------------------------------------------
 *
 * MegaWidgetWidgetCmd --
 *
 *	This procedure is invoked to process the Tcl command
 *	that corresponds to a magawidget widget.  See the user
 *	documentation for details on what it does.
 *
 * Results:
 *	A standard Tcl result.
 *
 * Side effects:
 *	See the user documentation.
 *
 *--------------------------------------------------------------
 */

static int
MegaWidgetWidgetCmd(clientData, interp, argc, argv)
    ClientData clientData;	/* Information about magawidget widget. */
    Tcl_Interp *interp;		/* Current interpreter. */
    int argc;			/* Number of arguments. */
    char **argv;		/* Argument strings. */
{
  register MegaWidget *megaWidgetPtr = (MegaWidget *) clientData;
  int result = TCL_OK;
  int length;
  int new;
  int counter, argc2;
  char c, *value, **argv2;
  Tcl_HashEntry *hashEntry;
  Tcl_HashSearch search;
  MegaWidgetMinor *minorPtr;
  MegaWidgetOption *optionPtr;
  Tcl_DString command;
  
  if (argc < 2) {
    Tcl_AppendResult(interp, "wrong # args: should be \"",
		     argv[0], " option ?arg arg ...?\"", (char *) NULL);
    return TCL_ERROR;
  }
  
  Tk_Preserve((ClientData) megaWidgetPtr);
  c = argv[1][0];
  length = strlen(argv[1]);
  if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
    if (argc == 2) {
      result = Tk_ConfigureInfo(interp, megaWidgetPtr->tkwin,
				configSpecs, (char *) megaWidgetPtr,
				(char *) NULL, 0);
      for (hashEntry = Tcl_FirstHashEntry(&megaWidgetPtr->options, &search);
	   hashEntry != NULL; hashEntry = Tcl_NextHashEntry(&search)) {
	optionPtr = (MegaWidgetOption *) Tcl_GetHashValue(hashEntry);
	if ((optionPtr->type == 0 || optionPtr->type == 1) &&
	    strcmp(Tcl_GetHashKey(&megaWidgetPtr->options,
				  hashEntry), "-background") != 0 &&
	    strcmp(Tcl_GetHashKey(&megaWidgetPtr->options,
				  hashEntry), "-bd") != 0 &&
	    strcmp(Tcl_GetHashKey(&megaWidgetPtr->options,
				  hashEntry), "-bg") != 0 &&
	    strcmp(Tcl_GetHashKey(&megaWidgetPtr->options,
				  hashEntry), "-borderwidth") != 0 &&
	    strcmp(Tcl_GetHashKey(&megaWidgetPtr->options,
				  hashEntry), "-cursor") != 0 &&
	    strcmp(Tcl_GetHashKey(&megaWidgetPtr->options,
				  hashEntry), "-geometry") != 0 &&
	    strcmp(Tcl_GetHashKey(&megaWidgetPtr->options,
				  hashEntry), "-height") != 0 &&
	    strcmp(Tcl_GetHashKey(&megaWidgetPtr->options,
				  hashEntry), "-relief") != 0 &&
	    strcmp(Tcl_GetHashKey(&megaWidgetPtr->options,
				  hashEntry), "-width") != 0) {
	  Tcl_AppendResult(interp, " {",
			   Tcl_GetHashKey(&megaWidgetPtr->options,
					  hashEntry), " ",
			   (char *) NULL);
	  Tcl_AppendResult(interp, "{", optionPtr->name, "} {",
			   optionPtr->class, "} {",
			   optionPtr->defaultValue, "} {",
			   optionPtr->value, "}", "}",
			   (char *) NULL);
	}
      }
    } else if (argc == 3) {
      result = Tk_ConfigureInfo(interp, megaWidgetPtr->tkwin,
				configSpecs, (char *) megaWidgetPtr,
				argv[2], 0);
      if (result == TCL_ERROR) {
	result = TCL_OK;
	Tcl_ResetResult(interp);
	hashEntry = Tcl_FindHashEntry(&megaWidgetPtr->options, argv[2]);
	if (hashEntry != NULL) {
	  optionPtr = (MegaWidgetOption *) Tcl_GetHashValue(hashEntry);
	  if (optionPtr->type == 0 || optionPtr->type == 1) {
	    Tcl_AppendResult(interp,
			     Tcl_GetHashKey(&megaWidgetPtr->options,
					    hashEntry), " ",
			     (char *) NULL);
	    Tcl_AppendResult(interp, "{", optionPtr->name, "} {",
			     optionPtr->class, "} {",
			     optionPtr->defaultValue, "} {",
			     optionPtr->value, "}",
			     (char *) NULL);
	  } else {
	    Tcl_AppendResult(interp, "no access to private option \"",
			     argv[2], "\"", (char *) NULL);
	    result = TCL_ERROR;
	  }
	} else {
	  Tcl_AppendResult(interp, "unknown option \"", argv[2],
			   "\"", (char *) NULL);
	  result = TCL_ERROR;
	}
      }
    } else {
      result = ConfigureMegaWidget(interp, megaWidgetPtr, argc-2,
				   argv+2, TK_CONFIG_ARGV_ONLY);
    }
  } else if ((c == 'c') && (strncmp(argv[1], "confhidden", length) == 0)) {
    if (interp != megaWidgetPtr->internalInterp) {
      Tcl_AppendResult(interp, "minor command \"", argv[1],
                       "\" only available in secure interpreter",
		       (char *) NULL);
      result = TCL_ERROR;
      goto finish;
    }
    if (argc == 2) {
      result = Tk_ConfigureInfo(interp, megaWidgetPtr->tkwin,
				configSpecs, (char *) megaWidgetPtr,
				(char *) NULL, 0);
      for (hashEntry = Tcl_FirstHashEntry(&megaWidgetPtr->options, &search);
	   hashEntry != NULL; hashEntry = Tcl_NextHashEntry(&search)) {
	optionPtr = (MegaWidgetOption *) Tcl_GetHashValue(hashEntry);
	if (optionPtr->type == 2) {
	  Tcl_AppendResult(interp, " {",
			   Tcl_GetHashKey(&megaWidgetPtr->options,
					  hashEntry), " ",
			   (char *) NULL);
	  Tcl_AppendResult(interp, "{", optionPtr->name, "} {",
			   optionPtr->class, "} {",
			   optionPtr->defaultValue, "} {",
			   optionPtr->value, "}", "}",
			   (char *) NULL);
	}
      }
    } else if (argc == 3) {
      result = Tk_ConfigureInfo(interp, megaWidgetPtr->tkwin,
				configSpecs, (char *) megaWidgetPtr,
				argv[2], 0);
      if (result == TCL_ERROR) {
	result = TCL_OK;
	Tcl_ResetResult(interp);
	hashEntry = Tcl_FindHashEntry(&megaWidgetPtr->options, argv[2]);
	if (hashEntry != NULL) {
	  optionPtr = (MegaWidgetOption *) Tcl_GetHashValue(hashEntry);
	  if (optionPtr->type == 2 ||
	      megaWidgetPtr->internalInterp == interp) {
	    Tcl_AppendResult(interp, optionPtr->value, (char *) NULL);
	  } else {
	    Tcl_AppendResult(interp, "no access to hidden option \"",
			     argv[2], "\"", (char *) NULL);
	    result = TCL_ERROR;
	  }
	} else {
	  Tcl_AppendResult(interp, "unknown hidden option \"", argv[2],
			   "\"", (char *) NULL);
	  result = TCL_ERROR;
	}
      }
    } else {
      result = ConfigureMegaWidget(interp, megaWidgetPtr, argc-2,
				   argv+2,
				   TK_CONFIG_ARGV_ONLY |
				   TK_MEGA_CONFIG_HIDDEN);
    }
  } else if ((c == 'c') && (strncmp(argv[1], "confinternal", length) == 0)) {
    if (interp != megaWidgetPtr->internalInterp) {
      Tcl_AppendResult(interp, "minor command \"", argv[1],
                       "\" only available in secure interpreter",
		       (char *) NULL);
      result = TCL_ERROR;
      goto finish;
    }
    if (argc > 3) {
      result = ConfigureMegaWidget(interp, megaWidgetPtr, argc-2,
				   argv+2, TK_CONFIG_ARGV_ONLY |
				   TK_MEGA_CONFIG_INTERNAL);
    }
  } else if ((c == 'c') && (strncmp(argv[1], "confvalue", length) == 0)) {
    if (argc == 3) {
      result = Tk_ConfigureInfo(interp, megaWidgetPtr->tkwin,
				configSpecs, (char *) megaWidgetPtr,
				argv[2], 0);
      if (result == TCL_OK) {
	if (Tcl_SplitList(interp, interp->result,
			  &argc2, &argv2) != TCL_OK) {
	  Tcl_AppendResult(interp, "error during config",
			   (char *) NULL);
	  return TCL_ERROR;
	}
	Tcl_ResetResult(interp);
	Tcl_AppendResult(interp, argv2[4], (char *) NULL);
	ckfree((char *) argv2);
      } else {
	result = TCL_OK;
	Tcl_ResetResult(interp);
	hashEntry = Tcl_FindHashEntry(&megaWidgetPtr->options, argv[2]);
	if (hashEntry != NULL) {
	  optionPtr = (MegaWidgetOption *) Tcl_GetHashValue(hashEntry);
	  if (optionPtr->type == 0 || optionPtr->type == 1) {
	    Tcl_AppendResult(interp, optionPtr->value,
			     (char *) NULL);
	  } else {
	    Tcl_AppendResult(interp, "no access to private option \"",
			     argv[2], "\"", (char *) NULL);
	    result = TCL_ERROR;
	  }
	} else {
	  Tcl_AppendResult(interp, "unknown option \"", argv[2],
			   "\"", (char *) NULL);
	  result = TCL_ERROR;
	}
      }
    } else {
      Tcl_AppendResult(interp, "wrong # of option names", (char *) NULL);
      result = TCL_ERROR;
      goto finish;
    }
  } else if ((c == 'i') && (strncmp(argv[1], "interpeval", length) == 0)
	     && (length >= 6)) {
    if (interp != megaWidgetPtr->internalInterp) {
      Tcl_AppendResult(interp, "minor command \"", argv[1],
                       "\" only available in secure interpreter",
		       (char *) NULL);
      result = TCL_ERROR;
      goto finish;
    }
    if (argc == 3) {
      result = Tcl_GlobalEval(megaWidgetPtr->interp, argv[2]);
      if (result == TCL_ERROR) {
	Tcl_AddErrorInfo(interp, megaWidgetPtr->interp->result);
      }
      if (megaWidgetPtr->internalInterp != megaWidgetPtr->interp) {
	Tcl_ResetResult(interp);
	Tcl_AppendResult(interp, megaWidgetPtr->interp->result,
			 (char *) NULL);
      }
    } else {
      if (argc > 3) {
	Tcl_DStringInit(&command);
	for (counter = 2; counter < argc; counter++) {
	  Tcl_DStringAppend(&command, "{", -1);
	  Tcl_DStringAppend(&command, argv[counter], -1);
	  Tcl_DStringAppend(&command, "} ", -1);
	}
	result = Tcl_GlobalEval(megaWidgetPtr->interp, command.string);
	if (result == TCL_ERROR) {
	  Tcl_AddErrorInfo(interp, megaWidgetPtr->interp->result);
	}
	if (megaWidgetPtr->internalInterp != megaWidgetPtr->interp) {
	  Tcl_ResetResult(interp);
	  Tcl_AppendResult(interp, megaWidgetPtr->interp->result,
			   (char *) NULL);
	}
	Tcl_DStringFree(&command);
      } else {
	Tcl_AppendResult(interp, "wrong # args",
			 ": should be \"", argv[0], " ", argv[1],
			 " arg ?arg ...?\"",
			 (char *) NULL);
	result = TCL_ERROR;
      }
    }
  } else if ((c == 'i') && (strncmp(argv[1], "interpset", length) == 0)
	     && (length >= 6)) {
    if (interp != megaWidgetPtr->internalInterp) {
      Tcl_AppendResult(interp, "minor command \"", argv[1],
                       "\" only available in secure interpreter",
		       (char *) NULL);
      result = TCL_ERROR;
      goto finish;
    }
    if (argc == 3) {
      if ((value = Tcl_GetVar(megaWidgetPtr->interp, argv[2],
			      TCL_GLOBAL_ONLY)) == NULL) {
	Tcl_AddErrorInfo(interp, megaWidgetPtr->interp->result);
	result = TCL_ERROR;
      }
      Tcl_ResetResult(interp);
      Tcl_AppendResult(interp, value, (char *) NULL);
    } else {
      if (argc == 4) {
	if ((value = Tcl_SetVar(megaWidgetPtr->interp, argv[2], argv[3],
				TCL_GLOBAL_ONLY)) == NULL) {
	  Tcl_AddErrorInfo(interp, megaWidgetPtr->interp->result);
	  result = TCL_ERROR;
	}
	Tcl_ResetResult(interp);
	Tcl_AppendResult(interp, value, (char *) NULL);
      } else {
	Tcl_AppendResult(interp, "wrong # args",
			 ": should be \"", argv[0], " ", argv[1],
			 " varName ?newValue?\"",
			 (char *) NULL);
	result = TCL_ERROR;
      }
    }
  } else if ((c == 'm') && (strncmp(argv[1], "minoradd", length) == 0)
	     && (length >= 6)) {
    if (interp != megaWidgetPtr->internalInterp) {
      Tcl_AppendResult(interp, "minor command \"", argv[1],
                       "\" only available in secure interpreter",
		       (char *) NULL);
      result = TCL_ERROR;
      goto finish;
    }
    if (argc == 4) {
      hashEntry = Tcl_CreateHashEntry(&megaWidgetPtr->minors,
				      argv[2], &new);
      if (new) {
	minorPtr = (MegaWidgetMinor *) ckalloc(sizeof(MegaWidgetMinor));
	Tcl_SetHashValue(hashEntry, minorPtr);
      } else {
	minorPtr = (MegaWidgetMinor *) Tcl_GetHashValue(hashEntry);
	ckfree((char *) minorPtr->minorCmd);
      }
      minorPtr->minorCmd = (char *) ckalloc(strlen(argv[3])+1);
      strcpy(minorPtr->minorCmd, argv[3]);
    } else {
      Tcl_AppendResult(interp, "wrong number of arguments",
		       ": must be \"", argv[1],
		       " minorName minorProc\"",
		       (char *) NULL);
      result = TCL_ERROR;
    }
  } else if ((c == 'm') && (strncmp(argv[1], "minordelete", length) == 0)
	     && (length >= 6)) {
    if (interp != megaWidgetPtr->internalInterp) {
      Tcl_AppendResult(interp, "minor command \"", argv[1],
                       "\" only available in secure interpreter",
		       (char *) NULL);
      result = TCL_ERROR;
      goto finish;
    }
    if (argc == 2) {
      Tcl_ResetResult(interp);
      for (hashEntry = Tcl_FirstHashEntry(&megaWidgetPtr->minors, &search);
	   hashEntry != NULL; hashEntry = Tcl_NextHashEntry(&search)) {
	minorPtr = (MegaWidgetMinor *) Tcl_GetHashValue(hashEntry);
	Tcl_DeleteHashEntry(hashEntry);
	ckfree((char *) minorPtr->minorCmd);
	ckfree((char *) minorPtr);
      }
    } else {
      if (argc == 3) {
	Tcl_ResetResult(interp);
	hashEntry = Tcl_FindHashEntry(&megaWidgetPtr->minors, argv[2]);
	if (hashEntry != NULL) {
	  minorPtr = (MegaWidgetMinor *) Tcl_GetHashValue(hashEntry);
	  Tcl_DeleteHashEntry(hashEntry);
	  ckfree((char *) minorPtr->minorCmd);
	  ckfree((char *) minorPtr);
	} else {
	  Tcl_AppendResult(interp, "unknown minor command: \"",
			   argv[2], "\"", (char *) NULL);
	  result = TCL_ERROR;
	}
      } else {
	Tcl_AppendResult(interp, "wrong number of arguments",
			 ": must be \"", argv[1],
			 " ?minorName?\"", (char *) NULL);
	result = TCL_ERROR;
      }
    }
  } else if ((c == 'm') && (strncmp(argv[1], "minorlist", length) == 0)
	     && (length >= 6)) {
    if (interp != megaWidgetPtr->internalInterp) {
      Tcl_AppendResult(interp, "minor command \"", argv[1],
                       "\" only available in secure interpreter",
		       (char *) NULL);
      result = TCL_ERROR;
      goto finish;
    }
    if (argc == 2) {
      Tcl_ResetResult(interp);
      for (hashEntry = Tcl_FirstHashEntry(&megaWidgetPtr->minors, &search);
	   hashEntry != NULL; hashEntry = Tcl_NextHashEntry(&search)) {
	Tcl_AppendResult(interp, Tcl_GetHashKey(&megaWidgetPtr->minors,
						hashEntry),
			 " ", (char *) NULL);
      }
    } else {
      if (argc == 3) {
	Tcl_ResetResult(interp);
	hashEntry = Tcl_FindHashEntry(&megaWidgetPtr->minors,
				      argv[2]);
	if (hashEntry != NULL) {
	  minorPtr = (MegaWidgetMinor *) Tcl_GetHashValue(hashEntry);
	  Tcl_AppendResult(interp, minorPtr->minorCmd,
			   " ", (char *) NULL);
	} else {
	  Tcl_AppendResult(interp, "unknown minor command: \"",
			   argv[2], "\"", (char *) NULL);
	  result = TCL_ERROR;
	}
      } else {
	Tcl_AppendResult(interp, "wrong number of arguments",
			 ": must be \"", argv[1],
			 " ?minorName?\"", (char *) NULL);
	result = TCL_ERROR;
      }
    }
  } else if ((c == 'o') && (strncmp(argv[1], "optionadd", length) == 0)
	     && (length >= 7)) {
    if (interp != megaWidgetPtr->internalInterp) {
      Tcl_AppendResult(interp, "minor command \"", argv[1],
                       "\" only available in secure interpreter",
		       (char *) NULL);
      result = TCL_ERROR;
      goto finish;
    }
    if (argc == 9) {
      hashEntry = Tcl_CreateHashEntry(&megaWidgetPtr->options,
				      argv[2], &new);
      if (new) {
	optionPtr = (MegaWidgetOption *) ckalloc(sizeof(MegaWidgetOption));
	Tcl_SetHashValue(hashEntry, optionPtr);
      } else {
	optionPtr = (MegaWidgetOption *) Tcl_GetHashValue(hashEntry);
	ckfree((char *) optionPtr->name);
	ckfree((char *) optionPtr->class);
	ckfree((char *) optionPtr->defaultValue);
	ckfree((char *) optionPtr->value);
	ckfree((char *) optionPtr->optionCmd);
      }
      optionPtr->name = (char *) ckalloc(strlen(argv[3])+1);
      strcpy(optionPtr->name, argv[3]);
      optionPtr->class = (char *) ckalloc(strlen(argv[4])+1);
      strcpy(optionPtr->class, argv[4]);
      optionPtr->defaultValue = (char *) ckalloc(strlen(argv[6])+1);
      strcpy(optionPtr->defaultValue, argv[6]);
      optionPtr->value = (char *) ckalloc(strlen(argv[5])+1);
      strcpy(optionPtr->value, argv[5]);
      if (strcmp(argv[7], "readonly") == 0) {
	optionPtr->type = 1;
      } else {
	if (strcmp(argv[7], "hidden") == 0) {
	  optionPtr->type = 2;
	} else {
	  if (strcmp(argv[7], "once") == 0) {
	    optionPtr->type = 3;
	  } else {
	    optionPtr->type = 0;
	  }
	}
      }
      optionPtr->optionCmd = (char *) ckalloc(strlen(argv[8])+1);
      strcpy(optionPtr->optionCmd, argv[8]);
    } else {
      Tcl_AppendResult(interp, "wrong number of arguments",
		       ": must be \"", argv[1],
		       " commandlineSwitch optionName ",
		       "className defaultValue value ",
		       "type optionProc\"", (char *) NULL);
      result = TCL_ERROR;
    }
  } else if ((c == 'o') && (strncmp(argv[1], "optiondelete", length) == 0)
	     && (length >= 7)) {
    if (interp != megaWidgetPtr->internalInterp) {
      Tcl_AppendResult(interp, "minor command \"", argv[1],
                       "\" only available in secure interpreter",
		       (char *) NULL);
      result = TCL_ERROR;
      goto finish;
    }
    if (argc == 2) {
      Tcl_ResetResult(interp);
      for (hashEntry = Tcl_FirstHashEntry(&megaWidgetPtr->options, &search);
	   hashEntry != NULL; hashEntry = Tcl_NextHashEntry(&search)) {
	optionPtr = (MegaWidgetOption *) Tcl_GetHashValue(hashEntry);
	Tcl_DeleteHashEntry(hashEntry);
	ckfree((char *) optionPtr->name);
	ckfree((char *) optionPtr->class);
	ckfree((char *) optionPtr->defaultValue);
	ckfree((char *) optionPtr->value);
	ckfree((char *) optionPtr->optionCmd);
	ckfree((char *) optionPtr);
      }
    } else {
      if (argc == 3) {
	Tcl_ResetResult(interp);
	hashEntry = Tcl_FindHashEntry(&megaWidgetPtr->options, argv[2]);
	if (hashEntry != NULL) {
	  optionPtr = (MegaWidgetOption *) Tcl_GetHashValue(hashEntry);
	  Tcl_DeleteHashEntry(hashEntry);
	  ckfree((char *) optionPtr->name);
	  ckfree((char *) optionPtr->class);
	  ckfree((char *) optionPtr->defaultValue);
	  ckfree((char *) optionPtr->value);
	  ckfree((char *) optionPtr->optionCmd);
	  ckfree((char *) optionPtr);
	} else {
	  Tcl_AppendResult(interp, "unknown option \"",
			   argv[2], "\"", (char *) NULL);
	  result = TCL_ERROR;
	}
      } else {
	Tcl_AppendResult(interp, "wrong number of arguments",
			 ": must be \"", argv[1],
			 " ?optionName?\"", (char *) NULL);
	result = TCL_ERROR;
      }
    }
  } else if ((c == 'o') && (strncmp(argv[1], "optionlist", length) == 0)
	     && (length >= 7)) {
    if (interp != megaWidgetPtr->internalInterp) {
      Tcl_AppendResult(interp, "minor command \"", argv[1],
                       "\" only available in secure interpreter",
		       (char *) NULL);
      result = TCL_ERROR;
      goto finish;
    }
    if (argc == 2) {
      Tcl_ResetResult(interp);
      for (hashEntry = Tcl_FirstHashEntry(&megaWidgetPtr->options, &search);
	   hashEntry != NULL; hashEntry = Tcl_NextHashEntry(&search)) {
	Tcl_AppendResult(interp, Tcl_GetHashKey(&megaWidgetPtr->options,
						hashEntry),
			 " ", (char *) NULL);
      }
    } else {
      if (argc == 3) {
	Tcl_ResetResult(interp);
	hashEntry = Tcl_FindHashEntry(&megaWidgetPtr->options,
				      argv[2]);
	if (hashEntry != NULL) {
	  optionPtr = (MegaWidgetOption *) Tcl_GetHashValue(hashEntry);
	  Tcl_AppendResult(interp,
			   Tcl_GetHashKey(&megaWidgetPtr->options,
					  hashEntry), " ",
			   (char *) NULL);
	  Tcl_AppendResult(interp, "{", optionPtr->name, "} {",
			   optionPtr->class, "} {",
			   optionPtr->defaultValue, "} {",
			   optionPtr->value, "} {",
			   optionPtr->optionCmd, "} ",
			   (char *) NULL);
	  if (optionPtr->type == 0) {
	    Tcl_AppendResult(interp, "normal", (char *) NULL);
	  } else {
	    if (optionPtr->type == 1) {
	      Tcl_AppendResult(interp, "readonly", (char *) NULL);
	    } else {
	      if (optionPtr->type == 2) {
		Tcl_AppendResult(interp, "hidden", (char *) NULL);
	      }
	    }
	  }
	} else {
	  Tcl_AppendResult(interp, "unknown option \"", argv[2],
			   "\"", (char *) NULL);
	  result = TCL_ERROR;
	}
      } else {
	Tcl_AppendResult(interp, "wrong number of arguments",
			 ": must be \"", argv[1], 
			 " ?optionName?\"", (char *) NULL);
	result = TCL_ERROR;
      }
    }
  } else if ((c == 'r') && (strncmp(argv[1], "recursiveconfigure", length) == 0)
	     && (length >= 11)) {
    if (argc == 4) {
      Tk_FakeWin *rootWinPtr = (Tk_FakeWin *) megaWidgetPtr->tkwin;
      
      Tcl_VarEval(interp, rootWinPtr->pathName,
		  " confinternal ", argv[2], " {", argv[3],
		  "}", (char *) NULL);
      RecursiveConfigMegaWidget(interp, (TkWindow *) rootWinPtr,
				argc, argv);
      Tcl_ResetResult(interp);
    } else {
      Tcl_AppendResult(interp, "wrong number of arguments",
		       ": must be \"", argv[1], 
		       " optionName optionValue\"", (char *) NULL);
      result = TCL_ERROR;
    }
  } else {
    for (hashEntry = Tcl_FirstHashEntry(&megaWidgetPtr->minors, &search);
	 hashEntry != NULL; hashEntry = Tcl_NextHashEntry(&search)) {
      if (strcmp(Tcl_GetHashKey(&megaWidgetPtr->minors,
				hashEntry), argv[1]) == 0) {
	minorPtr = (MegaWidgetMinor *) Tcl_GetHashValue(hashEntry);
	Tcl_DStringInit(&command);
	Tcl_DStringAppend(&command, minorPtr->minorCmd, -1);
	Tcl_DStringAppend(&command, " ", -1);
	Tcl_DStringAppend(&command, argv[0], -1);
	for (counter = 2; counter < argc; counter++) {
	  Tcl_DStringAppend(&command, " {", -1);
	  Tcl_DStringAppend(&command, argv[counter], -1);
	  Tcl_DStringAppend(&command, "}", -1);
	}
	result = Tcl_GlobalEval(megaWidgetPtr->internalInterp,
				command.string);
	if (result == TCL_ERROR) {
	  Tcl_AddErrorInfo(interp,
			   megaWidgetPtr->internalInterp->result);
	}
	if (megaWidgetPtr->internalInterp != interp) {
	  Tcl_ResetResult(interp);
	  Tcl_AppendResult(interp, megaWidgetPtr->internalInterp->result,
			   (char *) NULL);
	}
	Tcl_DStringFree(&command);
	goto finish;
      }
    }
    Tcl_AppendResult(interp, "unknown minor command: \"",
		     argv[1], "\"", (char *) NULL);
    result = TCL_ERROR;
  }

 finish:
  Tk_Release((ClientData) megaWidgetPtr);
  return result;
}

/*
 *----------------------------------------------------------------------
 *
 * DestroyMegaWidget --
 *
 *	This procedure is invoked by Tk_EventuallyFree or Tk_Release
 *	to clean up the internal structure of a magawidget at a safe time
 *	(when no-one is using it anymore).
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Everything associated with the magawidget is freed up.
 *
 *----------------------------------------------------------------------
 */

static void
DestroyMegaWidget(clientData)
    ClientData clientData;	/* Info about magawidget widget. */
{
  Tcl_HashEntry *interpHashPtr;
  MegaWidgetInterps *interpPtr;
  register MegaWidget *megaWidgetPtr = (MegaWidget *) clientData;
  char *value;

  /* Remove the mega procedure. */
  value = ckalloc(strlen(megaWidgetPtr->pathName) + 20);
  strcpy(value, "mega");
  strcat(value, megaWidgetPtr->pathName);
  Tcl_DeleteCommand(megaWidgetPtr->internalInterp, value);
  ckfree((char *) value);

  /* Destroy interpreter. */
  if (megaWidgetPtr->interpreter != NULL &&
      strlen(megaWidgetPtr->interpreter) > (size_t) 0) {
    interpHashPtr = Tcl_FindHashEntry(&megaWidgetInterpsTable,
				      (char *) megaWidgetPtr->interpreter);
    if (interpHashPtr != NULL) {
      interpPtr = (MegaWidgetInterps *) Tcl_GetHashValue(interpHashPtr);
      interpPtr->refCount--;
      if (interpPtr->refCount <= 0) {
	value = ckalloc(30);
	strcpy(value, "update idletask");
	Tcl_Eval(interpPtr->interp, value);
	strcpy(value, "destroy .");
	Tcl_Eval(interpPtr->interp, value);
	ckfree((char *) value);
	Tcl_DeleteInterp(interpPtr->interp);
	Tcl_DeleteHashEntry(interpHashPtr);
      }
    }
  }
  
  Tk_FreeOptions(configSpecs, (char *) megaWidgetPtr,
		 megaWidgetPtr->display, 0);
  if (megaWidgetPtr->class != NULL) {
    ckfree((char *) megaWidgetPtr->class);
  }
  if (megaWidgetPtr->createCommand != NULL) {
    ckfree((char *) megaWidgetPtr->createCommand);
  }
  if (megaWidgetPtr->interpreter != NULL) {
    ckfree((char *) megaWidgetPtr->interpreter);
  }
  if (megaWidgetPtr->libFile != NULL) {
    ckfree((char *) megaWidgetPtr->libFile);
  }
  if (megaWidgetPtr->userFile != NULL) {
    ckfree((char *) megaWidgetPtr->userFile);
  }
  if (megaWidgetPtr->pathName != NULL) {
    ckfree((char *) megaWidgetPtr->pathName);
  }
  Tcl_DeleteHashTable(&megaWidgetPtr->minors);
  Tcl_DeleteHashTable(&megaWidgetPtr->options);
  ckfree((char *) megaWidgetPtr);
}

/*
 *----------------------------------------------------------------------
 *
 * ConfigureMegaWidget --
 *
 *	This procedure is called to process an argv/argc list, plus
 *	the Tk option database, in order to configure (or
 *	reconfigure) a magawidget widget.
 *
 * Results:
 *	The return value is a standard Tcl result.  If TCL_ERROR is
 *	returned, then interp->result contains an error message.
 *
 * Side effects:
 *	Configuration information, such as text string, colors, font,
 *	etc. get set for megaWidgetPtr;  old resources get freed, if there
 *	were any.
 *
 *----------------------------------------------------------------------
 */

static int
ConfigureMegaWidget(interp, megaWidgetPtr, argc, argv, flags)
    Tcl_Interp *interp;		/* Used for error reporting. */
    register MegaWidget *megaWidgetPtr;	/* Information about
					 * widget; may or may
                                         * not already have values
                                         * for some fields. */
    int argc;			/* Number of valid entries in argv. */
    char **argv;		/* Arguments. */
    int flags;			/* Flags to pass to Tk_ConfigureWidget. */
{
  int counter;
  char *oldValue;
  Tcl_HashEntry *hashEntry;
  MegaWidgetOption *optionPtr;
  
  if (argc % 2 == 1) {
    Tcl_AppendResult(interp, "value for \"",
		     argv[argc-1], "\" missing", (char *) NULL);
    return TCL_ERROR;
  }
  
  Tcl_ResetResult(interp);
  for (counter = 0; counter < argc; counter++) {
    hashEntry = Tcl_FindHashEntry(&megaWidgetPtr->options,
				  argv[counter]);
    if (hashEntry != NULL) {
      optionPtr = (MegaWidgetOption *) Tcl_GetHashValue(hashEntry);
      if ((optionPtr->type == 3 && (flags & TK_MEGA_CONFIG_INITIAL)) ||
	  (optionPtr->type == 0 && !(flags & TK_MEGA_CONFIG_HIDDEN)) ||
	  (optionPtr->type == 1 && (flags & TK_MEGA_CONFIG_INTERNAL)) ||
	  (optionPtr->type == 2 && (flags & TK_MEGA_CONFIG_HIDDEN))) {
	oldValue = optionPtr->value;
	optionPtr->value = (char *) ckalloc(strlen(argv[counter+1])+1);
	strcpy(optionPtr->value, argv[counter+1]);
	if (strlen(optionPtr->optionCmd) > (size_t) 0 &&
	    !(flags & TK_MEGA_CONFIG_INTERNAL)) {
	  if (Tcl_VarEval(megaWidgetPtr->internalInterp,
			  optionPtr->optionCmd, " ",
			  Tk_PathName(megaWidgetPtr->tkwin), " ",
			  argv[counter], " {", oldValue, "} {",
			  argv[counter+1], "}",
			  (char *) NULL) != TCL_OK) {
	    ckfree((char *) oldValue);
	    if (megaWidgetPtr->internalInterp != interp) {
	      Tcl_AppendResult(interp,
			       megaWidgetPtr->internalInterp->result,
			       (char *) NULL);
	    }
	    return TCL_ERROR;
	  }
	}
	ckfree((char *) oldValue);
      } else {
	Tcl_AppendResult(interp, "not a valid option \"",
			 argv[counter], "\"", (char *) NULL);
	return TCL_ERROR;
      }
    } else {
      if (strcmp(argv[counter], "-background") != 0 &&
	  strcmp(argv[counter], "-bd") != 0 &&
	  strcmp(argv[counter], "-bg") != 0 &&
	  strcmp(argv[counter], "-borderwidth") != 0 &&
	  strcmp(argv[counter], "-class") != 0 &&
	  strcmp(argv[counter], "-createcommand") != 0 &&
	  strcmp(argv[counter], "-crypting") != 0 &&
	  strcmp(argv[counter], "-cursor") != 0 &&
	  strcmp(argv[counter], "-geometry") != 0 &&
	  strcmp(argv[counter], "-height") != 0 &&
	  strcmp(argv[counter], "-interpreter") != 0 &&
	  strcmp(argv[counter], "-libfile") != 0 &&
	  strcmp(argv[counter], "-relief") != 0 &&
	  strcmp(argv[counter], "-tksupport") != 0 &&
	  strcmp(argv[counter], "-userfile") != 0 &&
	  strcmp(argv[counter], "-width") != 0) {
	Tcl_AppendResult(interp, "unknown option \"",
			 argv[counter], "\"", (char *) NULL);
	return TCL_ERROR;
      }
    }
    counter++;
  }
  
  Tk_ConfigureWidget(interp, megaWidgetPtr->tkwin, configSpecs,
		     argc, argv, (char *) megaWidgetPtr, flags);
  Tcl_ResetResult(interp);
  
  Tk_SetBackgroundFromBorder(megaWidgetPtr->tkwin, megaWidgetPtr->border);
  /* I don't want borders != 0... reparenting will overwrite anyway. */
  megaWidgetPtr->borderWidth = 0;
  Tk_SetInternalBorder(megaWidgetPtr->tkwin, megaWidgetPtr->borderWidth);
  if (megaWidgetPtr->geometry != NULL) {
    int height, width;
    
    if (sscanf(megaWidgetPtr->geometry, "%dx%d", &width, &height) != 2) {
      Tcl_AppendResult(interp, "bad geometry \"",
		       megaWidgetPtr->geometry,
		       "\": expected widthxheight", (char *) NULL);
      return TCL_ERROR;
    }
    Tk_GeometryRequest(megaWidgetPtr->tkwin, width, height);
  } else if ((megaWidgetPtr->width > 0) || (megaWidgetPtr->height > 0)) {
    Tk_GeometryRequest(megaWidgetPtr->tkwin, megaWidgetPtr->width,
		       megaWidgetPtr->height);
  }
  
  if (Tk_IsMapped(megaWidgetPtr->tkwin)
      && !(megaWidgetPtr->flags & REDRAW_PENDING)) {
    Tk_DoWhenIdle(DisplayMegaWidget, (ClientData) megaWidgetPtr);
    megaWidgetPtr->flags |= REDRAW_PENDING|CLEAR_NEEDED;
  }
  return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * DisplayMegaWidget --
 *
 *	This procedure is invoked to display a megawidget widget.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Commands are output to X to display the megawidget in its
 *	current mode.
 *
 *----------------------------------------------------------------------
 */

static void
DisplayMegaWidget(clientData)
    ClientData clientData;	/* Information about widget. */
{
  register MegaWidget *megaWidgetPtr = (MegaWidget *) clientData;
  register Tk_Window tkwin = megaWidgetPtr->tkwin;
  
  megaWidgetPtr->flags &= ~REDRAW_PENDING;
  if ((megaWidgetPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
    return;
  }
  
  if (megaWidgetPtr->flags & CLEAR_NEEDED) {
    XClearWindow(megaWidgetPtr->display, Tk_WindowId(tkwin));
    megaWidgetPtr->flags &= ~CLEAR_NEEDED;
  }
  if ((megaWidgetPtr->border != NULL)
      && (megaWidgetPtr->relief != TK_RELIEF_FLAT)) {
    Tk_Draw3DRectangle(megaWidgetPtr->display, Tk_WindowId(tkwin),
		       megaWidgetPtr->border, 0, 0, Tk_Width(tkwin),
		       Tk_Height(tkwin), megaWidgetPtr->borderWidth,
		       megaWidgetPtr->relief);
  }
}

/*
 *--------------------------------------------------------------
 *
 * MegaWidgetEventProc --
 *
 *	This procedure is invoked by the Tk dispatcher on
 *	structure changes to a megawidget.  For megawidgets with 3D
 *	borders, this procedure is also invoked for exposures.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	When the window gets deleted, internal structures get
 *	cleaned up.  When it gets exposed, it is redisplayed.
 *
 *--------------------------------------------------------------
 */

static void
MegaWidgetEventProc(clientData, eventPtr)
    ClientData clientData;	/* Information about window. */
    register XEvent *eventPtr;	/* Information about event. */
{
  register MegaWidget *megaWidgetPtr = (MegaWidget *) clientData;

  if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
#if defined(DEBUGGING)
    fprintf(stderr, "public expose %s\n", 
	    Tk_PathName(megaWidgetPtr->tkwin));
#endif
    if ((megaWidgetPtr->relief != TK_RELIEF_FLAT) &&
	(megaWidgetPtr->tkwin != NULL) &&
	!(megaWidgetPtr->flags & REDRAW_PENDING)) {
      Tk_DoWhenIdle(DisplayMegaWidget, (ClientData) megaWidgetPtr);
      megaWidgetPtr->flags |= REDRAW_PENDING;
    }
  } else if (eventPtr->type == DestroyNotify) {
#if defined(DEBUGGING)
    fprintf(stderr, "public destroy %s\n", 
	    Tk_PathName(megaWidgetPtr->tkwin));
#endif
    Tcl_DeleteCommand(megaWidgetPtr->interp,
		      Tk_PathName(megaWidgetPtr->tkwin));
    megaWidgetPtr->tkwin = NULL;
    if (megaWidgetPtr->flags & REDRAW_PENDING) {
      Tk_CancelIdleCall(DisplayMegaWidget, (ClientData) megaWidgetPtr);
    }
    Tk_CancelIdleCall(MapMegaWidget, (ClientData) megaWidgetPtr);
    Tk_EventuallyFree((ClientData) megaWidgetPtr, DestroyMegaWidget);
  }
#if defined(TK_SUPPORT)
  if (eventPtr->type == ConfigureNotify &&
      megaWidgetPtr->embedWin != NULL &&
      Tk_IsMapped(megaWidgetPtr->embedWin)) {
    char buffer[30];
    Tcl_DString command;

    megaWidgetPtr->flags |= CALLED_CONFIG;
    Tcl_DStringInit(&command);
    Tcl_DStringAppend(&command, "wm geometry .", -1);
    Tcl_DStringAppend(&command, Tk_Name(megaWidgetPtr->tkwin), -1);
    sprintf(buffer, " %d", Tk_Width(megaWidgetPtr->tkwin));
    Tcl_DStringAppend(&command, buffer, -1);
    sprintf(buffer, "x%d", Tk_Height(megaWidgetPtr->tkwin));
    Tcl_DStringAppend(&command, buffer, -1);
#if defined(DEBUGGING)
    fprintf(stderr, "public configure %s: %s\n", 
	    Tk_PathName(megaWidgetPtr->tkwin), command.string);
#endif
    Tcl_Eval(megaWidgetPtr->internalInterp, command.string);
    Tcl_DStringFree(&command);
  }
#endif
}
/*
 *--------------------------------------------------------------
 *
 * MegaWidgetPrivateEventProc --
 *
 *	This procedure is invoked by the Tk dispatcher on
 *	structure changes to a window embedded in a megawidget.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	When the window gets deleted, internal structures get
 *	cleaned up.  When it gets exposed, it is redisplayed.
 *
 *--------------------------------------------------------------
 */

static void
MegaWidgetPrivateEventProc(clientData, eventPtr)
    ClientData clientData;	/* Information about window. */
    register XEvent *eventPtr;	/* Information about event. */
{
#if defined(TK_SUPPORT)
  register MegaWidget *megaWidgetPtr = (MegaWidget *) clientData;

  if (megaWidgetPtr->flags & CALLED_CONFIG) {
    megaWidgetPtr->flags &= ~CALLED_CONFIG;
    return;
  }
  if ((megaWidgetPtr->embedWin == NULL) ||
      !Tk_IsMapped(megaWidgetPtr->embedWin)) {
    return;
  }
  if (((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) ||
      eventPtr->type == ConfigureNotify || eventPtr->type == MapNotify) {
#if defined(DEBUGGING)
    fprintf(stderr, "private expose %s: %d %d\n", 
	    Tk_PathName(megaWidgetPtr->tkwin),
	    Tk_Width(megaWidgetPtr->embedWin), 
	    Tk_Height(megaWidgetPtr->embedWin));
#endif
    Tk_GeometryRequest(megaWidgetPtr->tkwin,
		       Tk_Width(megaWidgetPtr->embedWin), 
		       Tk_Height(megaWidgetPtr->embedWin));
  } else if (eventPtr->type == DestroyNotify) {
#if defined(DEBUGGING)
    fprintf(stderr, "private destroy %s\n", 
	    Tk_PathName(megaWidgetPtr->tkwin));
#endif
  }

#endif
}

/*
 *----------------------------------------------------------------------
 *
 * MapMegaWidget --
 *
 *	This procedure is invoked as a when-idle handler to map a
 *	newly-created top-level megawidget.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The megawidget given by the clientData argument is mapped.
 *
 *----------------------------------------------------------------------
 */

static void
MapMegaWidget(clientData)
    ClientData clientData;		/* Pointer to megawidget structure. */
{
  MegaWidget *megaWidgetPtr = (MegaWidget *) clientData;
  
  /*
   * Wait for all other background events to be processed before
   * mapping window.  This ensures that the window's correct geometry
   * will have been determined before it is first mapped, so that the
   * window manager doesn't get a false idea of its desired geometry.
   */

  Tk_Preserve((ClientData) megaWidgetPtr);
  while (1) {
    if (Tk_DoOneEvent(TK_IDLE_EVENTS) == 0) {
      break;
    }

    /*
     * After each event, make sure that the window still exists
     * and quit if the window has been destroyed.
     */
    
    if (megaWidgetPtr->tkwin == NULL) {
      Tk_Release((ClientData) megaWidgetPtr);
      return;
    }
  }
  Tk_MapWindow(megaWidgetPtr->tkwin);
  Tk_Release((ClientData) megaWidgetPtr);
}

/*
 *----------------------------------------------------------------------
 *
 * RecursiveConfigMegaWidget --
 *
 *	This procedure is invoked as a when-idle handler to map a
 *	newly-created top-level megawidget.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The megawidget given by the clientData argument is mapped.
 *
 *----------------------------------------------------------------------
 */

static void
RecursiveConfigMegaWidget(interp, rootWinPtr, argc, argv)
    Tcl_Interp *interp;
    TkWindow *rootWinPtr;
    int argc;
    char **argv;
{
  register TkWindow *winPtr;
  
  for (winPtr = ((TkWindow *) rootWinPtr)->childList;
       winPtr != NULL; winPtr = winPtr->nextPtr) {
    Tcl_VarEval(interp, winPtr->pathName, " configure ",
		argv[2], " {", argv[3], "}", (char *) NULL);
    RecursiveConfigMegaWidget(interp, winPtr, argc, argv);
  }
}

/*
 *----------------------------------------------------------------------
 *
 * TkMegaWidget_Init --
 *
 *      This procedure performs application-specific initialization.
 *      Most applications, especially those that incorporate additional
 *      packages, will have their own version of this procedure.
 *
 * Results:
 *      Returns a standard Tcl completion code, and leaves an error
 *      message in interp->result if an error occurs.
 *
 * Side effects:
 *      Depends on the startup script.
 *
 *----------------------------------------------------------------------
 */
int
TkMegaWidget_Init(interp)
    Tcl_Interp *interp;         /* Interpreter for application. */
{
  /*
   * Call Tcl_CreateCommand for application-specific commands.
   */
  Tcl_CreateCommand(interp, "megawidget", Tk_MegaWidgetCmd,
		    (ClientData) Tk_MainWindow(interp),
		    (Tcl_CmdDeleteProc *) NULL);
  Tcl_CreateCommand(interp, "topmegawidget", Tk_MegaWidgetCmd,
		    (ClientData) Tk_MainWindow(interp),
		    (Tcl_CmdDeleteProc *) NULL);
  
  return TCL_OK;
}

#endif

/* eof */
