/*
 * Browser Program.
 *
 * å© Copyright 1991, ALl Rights Reserved
 *
 *  David C. Navas
 */
#include <shadow/coreMeta.h>
#include <shadow/coreRoot.h>
#include <shadow/process.h>
#include <shadow/semaphore.h>

/*
 * Strings have to be word-aligned -- so add the space at the end,
 * just in case.
 */
#define GUITASK "Browser's Gui Task\0"
#include "/Gui/gui.h"

#include <ipc.h>
#include <exec/exec.h>
#include <shadow/shadow_proto.h>
#include <shadow/shadow_pragmas.h>
#include <shadow/method.h>
#include <dos/dostags.h>
#include <clib/alib_protos.h>

extern struct ExecBase * __far SysBase;
extern struct IntuitionBase * __far IntuitionBase;
struct Library * __far IPCBase;
struct ShadowBase * __far ShadowBase;
struct DosLibrary * __far DOSBase;
struct UtilityBase * __far UtilityBase;

/*
 * external class definitions.
 */
char GuiProcClassName[] = GUIPROCESS_CLASS,
     AslProcClassName[] = ASLPROCESS_CLASS,
     GuiTaskName[] = GUITASK,
     GuiClassName[] = GUI_CLASS,
     WindowClassName[] = WINDOW_CLASS,
     GadgTClassName[] = GADGT_CLASS,
     AslClassName[] = ASL_CLASS;

/*
 * Global Variables (non-library).
 */
OBJECT __far GlobalDirector = NULL;
struct Task * __far programTask;
OBJECT programTaskObject = NULL;

long __far GlobalNumOpen = 0;

/*
 * Function prototypes.
 */
void __regargs *addFromBinNodes(void *, ULONG, struct CWinLocalObjects *);
void LoadBrowser(void);


/*
 * ==========================================================================
 * =                                                                        =
 * =            Class definition for the BlockClass.                        =
 * =                                                                        =
 * ==========================================================================
 */

#define BLOCK_CLASS   "Browser Class"

/*
 * Attributes
 */
#define ATTR_BLOCKDIR "director"

ATTRIBUTE_TAG blockAttrs[] = {
                                ATTR_BLOCKDIR, 2 * sizeof(void *), NULL,
                                TAG_END
                             };

/*
 * Methods
 */
BOOL BlockInitMethod(METHOD_ARGS);
void BlockRemoveMethod(METHOD_ARGS);
void BlockNotifyMethod(METHOD_ARGS, long flags,
                                       W_VALUE watcher,
                                       void *first,
                                       void *second,
                                       OBJECT dispatch);
METHOD_TAG blockMethods[] =
                        {
                           {
                              METH_INIT,
                              NULL, NULL,
                              INVOKE_FORCE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)BlockInitMethod, NULL
                           },
                           {
                              METH_REMOVE,
                              NULL, NULL,
                              INVOKE_FORCE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)BlockRemoveMethod, NULL
                           },
                           {
                              METH_DIRECTOR_NOTIFY,
                              NULL, NULL,
                              INVOKE_FORCE_ASYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)BlockNotifyMethod,
                                 REF_NODENOTIFY
                           },
                           TAG_END
                        };



ARGUMENT_TAG REF_HitMethod[] = {'APTR', 4, sizeof(struct GuiIntuiMsg),
                              'JOBJ', 4, SHADOW_OBJECT,
                              TAG_END};
/*
 * ==========================================================================
 * =                                                                        =
 * =       Class definition for the Class Display Window Class.             =
 * =                                                                        =
 * ==========================================================================
 */

#define CWIN_CLASS "Window subClass that shows JOBJs"

/*
 * Attributes
 */
#define ATTR_LOCALWIN "local objects"

struct MyNode {
   struct Node node;
   void *object;
};

struct CWinLocalObjects {
   struct MyNode     *lastNode,
                     *nodes;
   struct List       list;
   OBJECT            listObject,
                     object1,
                     object2,
                     object3,
                     object4;
   char              *superClassText;
   OBJECT            director;
   struct MemoryList myMemList;
   META              meta;
};

ATTRIBUTE_TAG CWinAttrs[] =
                        {
                           {ATTR_LOCALWIN, sizeof(struct CWinLocalObjects),
                                           NULL},
                           {TAG_END}
                        };

/*
 * ArgumentTags
 */
extern ARGUMENT_TAG REF_CWinInitMethod[];

/*
 * Methods
 */
void CWinHitMethod(METHOD_ARGS, struct GuiIntuiMsg *info, OBJECT window);
void *CWinInitMethod(METHOD_ARGS, OBJECT parent,
                                  META   meta);
void CWinRemoveMethod(METHOD_ARGS);
void CWinDestroyMethod(METHOD_ARGS);

#define METH_GADGET_OPEN_MWIN  "open method display window"
#define METH_GADGET_OPEN_AWIN  "open attr display window"
#define METH_GADGET_OPEN_OWIN  "open object display"

void CWinOpenMWinMethod(METHOD_ARGS);
void CWinOpenAWinMethod(METHOD_ARGS);
void CWinOpenOWinMethod(METHOD_ARGS);

void CWinNotifyMethod(METHOD_ARGS, long flags,
                                       W_VALUE watcher,
                                       void *first,
                                       void *second);

METHOD_TAG CWinMethods[] =
                        {
                           {
                              METH_INIT,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              CWinInitMethod, REF_CWinInitMethod
                           },
                           {
                              METH_DESTROY,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)CWinDestroyMethod, NULL
                           },
                           {
                              METH_REMOVE,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)CWinRemoveMethod, NULL
                           },
                           {
                              METH_GADGET_SELECT,
                              NULL, NULL,
                              INVOKE_CALL,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)CWinHitMethod,
                                 REF_HitMethod
                           },
                           {
                              METH_GADGET_OPEN_MWIN,
                              NULL, NULL,
                              INVOKE_CALL,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)CWinOpenMWinMethod, NULL
                           },
                           {
                              METH_GADGET_OPEN_AWIN,
                              NULL, NULL,
                              INVOKE_CALL,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)CWinOpenAWinMethod, NULL
                           },
                           {
                              METH_GADGET_OPEN_OWIN,
                              NULL, NULL,
                              INVOKE_CALL,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)CWinOpenOWinMethod, NULL
                           },
                           {
                              METH_DIRECTOR_NOTIFY,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)CWinNotifyMethod,
                                 REF_NODENOTIFY
                           },
                           TAG_END
                        };

/*
 * ==========================================================================
 * =                                                                        =
 * =       Class definition for the Method Display Window Class.            =
 * =                                                                        =
 * ==========================================================================
 */

#define METWIN_CLASS "Window subClass that shows Methods"

/*
 * Attributes
 */
struct MWinLocalObjects {
   struct MyNode  *lastNode,
                  *nodes;
   struct List    list;
   OBJECT         object1,
                  object2,
                  object3,
                  object4,
                  object5,
                  director;
   CLASS          class;
};

ATTRIBUTE_TAG MetWinAttrs[] =
                        {
                           {ATTR_LOCALWIN, sizeof(struct MWinLocalObjects),
                                           NULL},
                           {TAG_END}
                        };

/*
 * ArgumentTags
 */
extern ARGUMENT_TAG REF_MetWinInitMethod[],
                  REF_MWinOpenRWinMethod[];

/*
 * Methods
 */
void MetWinUpdateInfo(METHOD_ARGS);
void MetWinHitMethod(METHOD_ARGS, struct GuiIntuiMsg *info, OBJECT window);
void *MetWinInitMethod(METHOD_ARGS, OBJECT parent,
                                    CLASS);
void MetWinDestroyMethod(METHOD_ARGS);
void MetWinRemoveMethod(METHOD_ARGS);

void MWinOpenRWinMethod(METHOD_ARGS);

#define METH_GADGET_OPEN_RWIN "open argument display window"
#define METH_METHOD_UPDATE_INFO "Update Info in Method Window"

METHOD_TAG  MetWinMethods[] =
                        {
                           {
                              METH_INIT,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              MetWinInitMethod, REF_MetWinInitMethod
                           },
                           {
                              METH_DESTROY,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)MetWinDestroyMethod, NULL
                           },
                           {
                              METH_REMOVE,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)MetWinRemoveMethod, NULL
                           },
                           {
                              METH_GADGET_SELECT,
                              NULL, NULL,
                              INVOKE_CALL,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)MetWinHitMethod,
                                 REF_HitMethod
                           },
                           {
                              METH_GADGET_OPEN_RWIN,
                              NULL, NULL,
                              INVOKE_CALL,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)MWinOpenRWinMethod, NULL
                           },
                           {
                              METH_METHOD_UPDATE_INFO,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)MetWinUpdateInfo, NULL
                           },
                           TAG_END
                        };


/*
 * ==========================================================================
 * =                                                                        =
 * =     Class definition for the Attribute Display Window Class.           =
 * =                                                                        =
 * ==========================================================================
 */

#define ATTWIN_CLASS "Window subClass that shows Attributes"

/*
 * Attributes
 */
struct AWinLocalObjects {
   struct MyNode *lastNode,
                 *nodes;
   struct List   list;
   OBJECT        object1,
                 object2,
                 object3,
                 object4;
   META          meta;
};

ATTRIBUTE_TAG AttWinAttrs[] =
                        {
                           {ATTR_LOCALWIN, sizeof(struct AWinLocalObjects),
                                           NULL},
                           {TAG_END}
                        };

/*
 * ArgumentTags
 */
extern ARGUMENT_TAG REF_AttWinInitMethod[];

/*
 * Methods
 */
void AttWinHitMethod(METHOD_ARGS, struct GuiIntuiMsg *info, OBJECT window);
void *AttWinInitMethod(METHOD_ARGS, OBJECT parent, CLASS);
void AttWinDestroyMethod(METHOD_ARGS);

METHOD_TAG AttWinMethods[] =
                        {
                           {
                              METH_INIT,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              AttWinInitMethod, REF_AttWinInitMethod
                           },
                           {
                              METH_DESTROY,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)AttWinDestroyMethod, NULL
                           },
                           {
                              METH_GADGET_SELECT,
                              NULL, NULL,
                              INVOKE_CALL,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)AttWinHitMethod,
                                 REF_HitMethod
                           },
                           TAG_END
                        };


/*
 * ==========================================================================
 * =                                                                        =
 * =     Class definition for the ArgumentTag Display Window Class.           =
 * =                                                                        =
 * ==========================================================================
 */

#define REFWIN_CLASS "Window subClass that shows ArgumentTags"

/*
 * Attributes
 */
struct RWinLocalObjects {
   struct MyNode  *lastNode,
                  *nodes;
   struct List    list;
   OBJECT         object1,
                  object2;
   char           *text;
};

ATTRIBUTE_TAG RefWinAttrs[] =
                        {
                           {ATTR_LOCALWIN, sizeof(struct RWinLocalObjects),
                                           NULL},
                           {TAG_END}
                        };

/*
 * ArgumentTags
 */
extern ARGUMENT_TAG REF_RefWinInitMethod[];

/*
 * Methods
 */
void RefWinHitMethod(METHOD_ARGS, struct GuiIntuiMsg *info, OBJECT window);
void *RefWinInitMethod(METHOD_ARGS, OBJECT parent,
                                    struct MethodHandler *,
                                    CLASS  mclass);
void RefWinDestroyMethod(METHOD_ARGS);

METHOD_TAG RefWinMethods[] =
                        {
                           {
                              METH_INIT,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              RefWinInitMethod, REF_RefWinInitMethod
                           },
                           {
                              METH_DESTROY,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)RefWinDestroyMethod, NULL
                           },
                           {
                              METH_GADGET_SELECT,
                              NULL, NULL,
                              INVOKE_CALL,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)RefWinHitMethod,
                                 REF_HitMethod
                           },
                           TAG_END
                        };


/*
 * ==========================================================================
 * =                                                                        =
 * =                    F  U  N  C  T  I  O  N  S                           =
 * =                                                                        =
 * ==========================================================================
 */

/*
 * ^C -- just say no.
 */
int CXBRK(void)
{
   return(0);
}

/*
 * no!
 */
chkabort(void)
{
   return(0);
}

/*
 * Okay, here's the main.
 */
void main(void)
{

   programTask = FindTask(NULL);

   /*
    * Open Libraries and startup the program for SHADOW.
    */
   if (DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 37))
   {
      if (IPCBase = OpenLibrary("ppipc.library", 0))
      {
         if (ShadowBase = (struct ShadowBase *)
                          OpenLibrary("shadow.library", 5))
         {
            if (InitOOProgram("Browser Program"))
            {
               programTaskObject = CurrentProcess();
               /*
                * Okay, run the Browser.
                */
               LoadBrowser();
               RemoveCurrentProgram(NULL);
            } else
               VPrintf("Can't init Browser program.\n", NULL);

            CloseLibrary(ShadowBase);
         } else
            VPrintf("requires shadow.library V5.x in libs:\n", NULL);

         CloseLibrary(IPCBase);
      } else
         VPrintf("requires ppipc.library in libs:\n", NULL);
   } else
   {
      DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 0);
      Write(Output(), "Sorry, use 2.0\n", 15);
   }
   CloseLibrary(DOSBase);
}

void LoadBrowser(void)
{
   OBJECT    guiTask;
   W_AVLTREE wbt;
   int success;

#ifndef NDEBUG
   ULONG args[10];
   long mem2;

   args[0] = mem2 = AvailMem(MEMF_ANY);
#endif

   /*
    * Have we already started a browser ???
    * if so, we can just send it a method and shut ourselves down.
    */
   PSemString("Browser Program", SSEM_LOCK);
   if (CreateInstance(NULL, BLOCK_CLASS, META_CLASS, METHOD_END))
   {
      VSemString("Browser Program");
      return;
   }

   /*
    * Initialize the GUI
    */
   success = InitGUISystem();
#ifndef NDEBUG
   VPrintf("MemStart %ld\n", args);
#endif

   if (wbt = FindAttribute(programTaskObject, ATTR_RESOURCETREE))
      guiTask = FindWatchedTreeStringNode(wbt, GUITASK);
   else
      guiTask = NULL;

   SetupMethodTags(CWinMethods, guiTask, (void *)-1);
   SetupMethodTags(MetWinMethods, guiTask, (void *)-1);
   SetupMethodTags(AttWinMethods, guiTask, (void *)-1);
   SetupMethodTags(RefWinMethods, guiTask, (void *)-1);
   SetupMethodTags(blockMethods, guiTask, (void *)-1);

   DropObject(guiTask);

   /*
    * Create BlockClass.
    */

   success &= AddAutoResource(NULL,
                              CreateSubClass(NULL,
                                             GUI_CLASS,
                                             META_CLASS,
                                             BLOCK_CLASS,
                                             NULL,
                                             blockAttrs,
                                             blockMethods,
                                             METHOD_END),
                              BLOCK_CLASS);

   VSemString("Browser Program");

   /*
    * Create the window classes.
    */
   success &= AddAutoResource(NULL,
                              CreateSubClass(NULL,
                                            WINDOW_CLASS,
                                            META_CLASS,
                                            CWIN_CLASS,
                                            NULL,
                                            CWinAttrs,
                                            CWinMethods,
                                            METHOD_END),
                              CWIN_CLASS);

   success &= AddAutoResource(NULL,
                              CreateSubClass(NULL,
                                             WINDOW_CLASS,
                                             META_CLASS,
                                             METWIN_CLASS,
                                             NULL,
                                             MetWinAttrs,
                                             MetWinMethods,
                                             METHOD_END),
                              METWIN_CLASS);

   success &= AddAutoResource(NULL,
                              CreateSubClass(NULL,
                                             WINDOW_CLASS,
                                             META_CLASS,
                                             ATTWIN_CLASS,
                                             NULL,
                                             AttWinAttrs,
                                             AttWinMethods,
                                             METHOD_END),
                              ATTWIN_CLASS);

   success &= AddAutoResource(NULL,
                              CreateSubClass(NULL,
                                             WINDOW_CLASS,
                                             META_CLASS,
                                             REFWIN_CLASS,
                                             NULL,
                                             RefWinAttrs,
                                             RefWinMethods,
                                             METHOD_END),
                              REFWIN_CLASS);

   /*
    * Create the top level window.
    */
   success &= (BOOL)CreateInstance(NULL, BLOCK_CLASS, META_CLASS, METHOD_END);


#ifndef NDEBUG
   args[0] = mem2 - AvailMem(MEMF_ANY);

   VPrintf("Memory Usage %ld\n", args);
#endif


   /*
    * basically Wait for everything to shut down.
    *
    * Nothing is actually going to use these ports, but they ARE
    *  allocated, so I might as well use them.
    */
   if (success)
   {
      HandleMessages();
   }

#ifndef NDEBUG
   args[0] = AvailMem(MEMF_ANY);
   VPrintf("MemEnd %ld\n", args);
#endif
}


/*
 * Add all of the objects into the list....
 */
void __regargs *addFromBinNodes(void *value,
                                ULONG name,
                                struct CWinLocalObjects *local)
{
   struct MyNode *node;

   if (!(node = AllocateItem(&local->myMemList)))
      return (void *)-1;

   if (name == (long)value)
   {
      char buffer[20];
      long name2;

      name2 = name;

      RawDoFmt("Object at: %lx", &name2, SprintfCallback, buffer);
      node->node.ln_Name = UseString(buffer);
   }
   else
      node->node.ln_Name = UseString((char *)name);

   /*
    * The object might reference this CWindow.
    *  THEREFORE, it hangs, unless reference removed during remove
    *   method, as opposed to DESTROY method.
    *   [Because DESTROY would never get called, it self-references.]
    */

   node->object = value;
   UseObject(value);

   AddTail(&local->list, node);
   return NULL;
}


/*
 * ==========================================================================
 * =                                                                        =
 * =            ALL OF THE CLASS METHODS ARE BELOW.                         =
 * =                                                                        =
 * ==========================================================================
 */

/*
 * Block Class methods.
 */
BOOL BlockInitMethod(METHOD_ARGS)
{
   OBJECT *director, handle;

   director = FindAttribute(object, ATTR_BLOCKDIR);

   if (CallSuper())
   {
      OBJECT window;
      CLASS  windowClass;

      /*
       * Create the example Global Director which watches all of the
       *  window classes' GUICHILDREN attribute.
       */
      if (!GlobalDirector)
      {
         /*
          * Get a director object.
          */
         GlobalDirector = CreateInstance(NULL,
                                         DIRECTOR_CLASS,
                                         META_CLASS,
                                         "WatchWindows",
                                         object,
                                         METH_DIRECTOR_NOTIFY,
                                         (W_INSERT_NODE | W_REMOVE) |
                                           (SHADOW_CLASS << 16) |
                                           W_FLAG_AUTOBREAK  |
                                           W_FLAG_AUTOREMOVE,
                                         METHOD_END);

         /*
          * Establish the actual connection.  We don't care if
          * it doesn't actually Open, so that makes things easier.
          *
          * We are watching all the ATTR_GUICHILDREN of every instance
          *  whose class is a subclass of WINDOW_CLASS
          */
         windowClass = FindShadowClass(WINDOW_CLASS);
         DropObject(DoShadow(GlobalDirector,
                                 NULL,
                                 METH_DIRECTOR_ESTABLISH,
                                 ATTR_GUICHILDREN,
                                 windowClass,
                                 METHOD_END));
         DropObject(windowClass);

         /*
          * Why is this at priority one?
          * Well, there's this race condition....  You can either shut
          *  this down FIRST, or you can make the notification in
          *  CWIN ASYNC.  I like this better.
          */
         AddAutoResource(programTaskObject, GlobalDirector, (char *)1);
      }


      /*
       * Create the director to watch the children of this object.
       *
       * When this object's children reaches zero, this object
       *  should GO AWAY!
       */

      *director = CreateInstance(NULL,
                                 DIRECTOR_CLASS,
                                 META_CLASS,
                                 "WatchBlockedChildren",
                                 object,
                                 METH_DIRECTOR_NOTIFY,
                                 (W_INSERT_NODE | W_REMOVE) |
                                   (SHADOW_OBJECT << 16) |
                                   W_FLAG_AUTOBREAK |
                                   W_FLAG_AUTOREMOVE,
                                 METHOD_END);
      /*
       * Establish the conection for the director.
       */
      if (handle = DoShadow(*director, NULL, METH_DIRECTOR_ESTABLISH,
                                        ATTR_GUICHILDREN,
                                        object,
                                        METHOD_END))
      {
         DropObject(handle);
         if (window = CreateInstance(NULL,
                                     CWIN_CLASS,
                                     META_CLASS,
                                     object,
                                     METHOD_END))
         {
            DropObject(window);
            if (AddAutoResource(programTaskObject, object, NULL))
            {
               GlobalNumOpen++;
               return TRUE;
            }
         }
      }
      RemoveObject(object);
   }
   return FALSE;
}

void BlockRemoveMethod(METHOD_ARGS)
{
   OBJECT director;

   DropObject(RemoveAutoResource(programTaskObject, object, NULL));

   director = SetObject(FindAttribute(object, ATTR_BLOCKDIR), NULL);
   RemoveObject(director);

   CallSuper();

   if (!--GlobalNumOpen)
      Signal(programTask, SIGBREAKF_CTRL_C);
}

void BlockNotifyMethod(METHOD_ARGS, long flags,
                                       W_VALUE  watcher,
                                       void *first,
                                       void *second,
                                       OBJECT dispatch)
{
   long *director;

   director = FindAttribute(object, ATTR_BLOCKDIR);
   if (!second)  second = "";

   if (dispatch == GlobalDirector)
   {
      if (flags & W_INSERT)
      {
         VPrintf("Inserted child <%s> into some Window Object.\n",
                  (ULONG *)&second);
      } else
      {
         VPrintf("Removed child <%s> from some Window Object.\n",
                  (ULONG *)&second);
      }
   } else
   {
      if (flags & W_INSERT)
         (director[1])++;
      else if (!(--(director[1])))
      {
         RemoveObject(UseObject(object));
      }
   }
}

/*
 * CWin Class methods.
 */
ARGUMENT_TAG REF_CWinInitMethod[] = {
                                     {'JOBJ', sizeof(void *), SHADOW_OBJECT},
                                     {'JOBJ', sizeof(void *), SHADOW_CLASS},
                                     {TAG_END, SHADOW_RETURN_OBJECT, 0}
                                  };
void *CWinInitMethod(METHOD_ARGS, OBJECT parent,
                                  META meta)
{
   struct CWinLocalObjects *mlo;

   mlo = FindAttribute(object, ATTR_LOCALWIN);
   NewList(&mlo->list);
   if (!(InitTable(&mlo->myMemList, NULL, NULL, sizeof(struct MyNode))))
   {
      UseObject(object);
      DropObject(object);
      return NULL;
   }

   /*
    * Create the correct window with the correct title....
    */
   {
      struct TagItem tag[8];
      char *string;

      {
         char buffer[128];

         if (!meta)
            strcpy(buffer, "Meta list for system");
         else if (meta->meta_class == meta)
         {
            strcpy(buffer, "Class list for: ");
            strncat(buffer, meta->meta_name, 64);
         } else
         {
            strcpy(buffer, "Object list for: ");
            strncat(buffer, meta->meta_name, 64);
         }
         if (!(string = UseString(buffer)))
         {
            UseObject(object);
            DropObject(object);
            return NULL;
         }
      }

      tag[0].ti_Tag = WA_Width;
      tag[0].ti_Data = 500;
      tag[1].ti_Tag = WA_Height;
      tag[1].ti_Data = 200;
      tag[2].ti_Tag = WA_MinWidth;
      tag[2].ti_Data = 60;
      tag[3].ti_Tag = WA_MinHeight;
      tag[3].ti_Data = 40;
      tag[4].ti_Tag = WA_MaxWidth;
      tag[4].ti_Data = -1;
      tag[5].ti_Tag = WA_MaxHeight;
      tag[5].ti_Data = -1;
      tag[6].ti_Tag = WA_SimpleRefresh;
      tag[6].ti_Data = TRUE;
      tag[7].ti_Tag = TAG_END;

      object = DoSuperShadow(object, class, METH_INIT,
                                            parent,
                                            string,
                                            NULL,
                                            NULL,
                                            tag,
                                            METHOD_END);
      DropString(string);
      if (!object)
         return NULL;
   }

   mlo->meta = UseObject(meta);

   /*
    * So watch the tree....
    */
   /*
    * Create the watching director object.
    */
   mlo->director = CreateInstance(NULL,
                                  DIRECTOR_CLASS,
                                  META_CLASS,
                                  "Watch Meta",
                                  object,
                                  METH_DIRECTOR_NOTIFY,
                                  (W_INSERT_NODE | W_REMOVE) |
                                    (SHADOW_OBJECT << 16) |
                                    W_FLAG_AUTOBREAK |
                                    W_FLAG_AUTOREMOVE,
                                  METHOD_END);

   /*
    * Establish the connection.
    */
   DropObject( DoShadow(mlo->director,
                            NULL,
                            METH_DIRECTOR_ESTABLISH,
                            (meta)?(void *)ATTR_INSTANCETREE:
                                   (void *)&ShadowBase->sb_metaTree,
                            meta,
                            METHOD_END));


   /*
    * Copy all the instance objects into the list.
    */
   {
      W_AVLTREE tree;

      tree = (meta)?(W_AVLTREE)FindAttribute(meta, ATTR_INSTANCETREE):
                    &ShadowBase->sb_metaTree;
      DoInOrderTree(&tree->wv_value, addFromBinNodes, mlo);
      mlo->lastNode = NULL;
   }

   /*
    * Okay, we have a window.  Now we need gadgets.
    */
   {
      struct TagItem tag[3];
      struct NewGadget ng;

      ng.ng_LeftEdge = 50;
      ng.ng_TopEdge = 45;
      ng.ng_Width = 300;
      ng.ng_Height = 90;
      ng.ng_Flags = PLACETEXT_ABOVE;
      tag[0].ti_Tag = GTLV_Labels;
      tag[0].ti_Data = (ULONG)&mlo->list;

      if (!meta || meta->meta_class == meta)
         tag[1].ti_Tag = GTLV_ShowSelected;
      else
         tag[1].ti_Tag = 0;

      tag[1].ti_Data = NULL;
      tag[2].ti_Tag = TAG_END;
      mlo->listObject = CreateInstance(NULL,
                                       GADGT_CLASS,
                                       META_CLASS,
                                       object,
                                       (meta)?((meta->meta_class == meta)?
                                                             "Class List:":
                                                             "Instances:")
                                             :"Meta List:",
                                       (!meta || meta->meta_class == meta)?
                                          object:NULL,
                                       METH_GADGET_SELECT,
                                       &ng,
                                       LISTVIEW_KIND,
                                       tag,
                                       METHOD_END);

      if (meta && (meta->meta_class != meta))
         return object;

      ng.ng_TopEdge += ng.ng_Height;
      ng.ng_Height = 15;
      ng.ng_Width = 80;
      ng.ng_Flags = PLACETEXT_RIGHT;
      tag[0].ti_Tag = TAG_END;
      mlo->object1 = CreateInstance(NULL,
                                    GADGT_CLASS,
                                    META_CLASS,
                                    object,
                                    ":Instance size",
                                    object,
                                    METH_GADGET_SELECT,
                                    &ng,
                                    NUMBER_KIND,
                                    tag,
                                    METHOD_END);

      ng.ng_TopEdge += ng.ng_Height;
      ng.ng_Height = 15;
      ng.ng_Width = 80;
      ng.ng_Flags = PLACETEXT_RIGHT;
      tag[0].ti_Tag = TAG_END;
      mlo->object2 = CreateInstance(NULL,
                                    GADGT_CLASS,
                                    META_CLASS,
                                    object,
                                    ":methodTable size",
                                    object,
                                    METH_GADGET_SELECT,
                                    &ng,
                                    NUMBER_KIND,
                                    tag,
                                    METHOD_END);

      ng.ng_TopEdge += ng.ng_Height;
      ng.ng_Height = 15;
      ng.ng_Width = 80;
      ng.ng_Flags = PLACETEXT_RIGHT;
      tag[0].ti_Tag = TAG_END;
      mlo->object3 = CreateInstance(NULL,
                                    GADGT_CLASS,
                                    META_CLASS,
                                    object,
                                    ":attributeTable size",
                                    object,
                                    METH_GADGET_SELECT,
                                    &ng,
                                    NUMBER_KIND,
                                    tag,
                                    METHOD_END);

      ng.ng_TopEdge += ng.ng_Height;
      ng.ng_Height = 15;
      ng.ng_Width = 80;
      ng.ng_Flags = PLACETEXT_RIGHT;
      tag[0].ti_Tag = TAG_END;
      mlo->object4 = CreateInstance(NULL,
                                    GADGT_CLASS,
                                    META_CLASS,
                                    object,
                                    NULL,
                                    object,
                                    METH_GADGET_SELECT,
                                    &ng,
                                    TEXT_KIND,
                                    tag,
                                    METHOD_END);

      ng.ng_TopEdge = 45;
      ng.ng_LeftEdge = 370;
      ng.ng_Height = 20;
      ng.ng_Width = 100;
      ng.ng_Flags = 0;
      tag[0].ti_Tag = TAG_END;
      DropObject(CreateInstance(NULL,
                                GADGT_CLASS,
                                META_CLASS,
                                object,
                                "Methods",
                                object,
                                METH_GADGET_OPEN_MWIN,
                                &ng,
                                BUTTON_KIND,
                                tag,
                                METHOD_END));

      ng.ng_TopEdge += ng.ng_Height;
      ng.ng_Height = 20;
      ng.ng_Width = 100;
      ng.ng_Flags = 0;
      tag[0].ti_Tag = TAG_END;
      DropObject(CreateInstance(NULL,
                                GADGT_CLASS,
                                META_CLASS,
                                object,
                                "Attributes",
                                object,
                                METH_GADGET_OPEN_AWIN,
                                &ng,
                                BUTTON_KIND,
                                tag,
                                METHOD_END));

      ng.ng_TopEdge += ng.ng_Height;
      ng.ng_Height = 20;
      ng.ng_Width = 100;
      ng.ng_Flags = 0;
      tag[0].ti_Tag = TAG_END;
      DropObject(CreateInstance(NULL,
                                GADGT_CLASS,
                                META_CLASS,
                                object,
                                "Instances",
                                object,
                                METH_GADGET_OPEN_OWIN,
                                &ng,
                                BUTTON_KIND,
                                tag,
                                METHOD_END));
   }
   return object;
}

void CWinNotifyMethod(METHOD_ARGS, long flags,
                                       W_VALUE watcher,
                                       void *first,
                                       void *second)
{
   struct CWinLocalObjects *mlo;
   struct TagItem tags[2];
   struct MyNode *node;

   mlo = FindAttribute(object, ATTR_LOCALWIN);
   if (!mlo->director)
      return;

   tags[0].ti_Tag = GTLV_Labels;
   tags[0].ti_Data = ~0;
   tags[1].ti_Tag = TAG_END;
   DoShadow(mlo->listObject, NULL, METH_GADGET_CHANGE,
                                          tags,
                                          METHOD_END);
   if (flags & W_INSERT)
   {

      if (!(node = AllocateItem(&mlo->myMemList)))
         return;
      if (second != first)
      {
         node->node.ln_Name = UseString((char *)second);
      } else
      {
         char buffer[20];

         RawDoFmt("Object at: %lx", &first, SprintfCallback, buffer);

         node->node.ln_Name = UseString(buffer);
      }

      node->object = first;
      UseObject(first);
      AddTail(&mlo->list, node);
   } else if (flags & W_REMOVE)
   {
      char *name;

      if (second != first)
      {
         name = FindString((char *)second);
      } else
      {
         char buffer[20];

         RawDoFmt("Object at: %lx", &first, SprintfCallback, buffer);
         name = FindString(buffer);
      }
      for(node = (struct MyNode *)mlo->list.lh_Head;
          node->node.ln_Succ;
          node = (struct MyNode *)node->node.ln_Succ)
      {
         if (node->node.ln_Name == name && node->object == first)
         {
            QuickDropString(name);
            DropObject(first);
            Remove(node);
            FreeItem(&mlo->myMemList, node);
            if (mlo->lastNode == node)
               mlo->lastNode = NULL;
            break;
         }
      }
   }
   tags[0].ti_Tag = GTLV_Labels;
   tags[0].ti_Data = (ULONG)&mlo->list;
   DoShadow(mlo->listObject, NULL, METH_GADGET_CHANGE,
                                          tags,
                                          METHOD_END);
}

void CWinRemoveMethod(METHOD_ARGS)
{
   struct CWinLocalObjects *mlo;
   struct Node *node;


   mlo = FindAttribute(object, ATTR_LOCALWIN);
   RemoveObject(SetObject(&mlo->director, NULL));

   node = mlo->list.lh_Head;

   UseObject(object);         /* Make sure object stays around! */
   CallSuper();               /* Let GadTools know to get rid of gadgets. */

   NewList(&mlo->list);
   for(; node->ln_Succ; node = node->ln_Succ)
   {
      DropObject(((struct MyNode *)node)->object);
      QuickDropString(node->ln_Name);
   }
   DropObject(object);        /* OKAY, now we're done! */
}

void CWinDestroyMethod(METHOD_ARGS)
{
   struct CWinLocalObjects *mlo;

   mlo = FindAttribute(object, ATTR_LOCALWIN);
   DropObject(mlo->object1);
   DropObject(mlo->object2);
   DropObject(mlo->object3);
   DropObject(mlo->object4);
   DropObject(mlo->listObject);
   DropObject(mlo->meta);
   QuickDropString(mlo->superClassText);

   FreeTable(&mlo->myMemList);
   CallSuper();
}


/*
 * Selected a new item in the list.
 * So update all of our information.
 * Only called if this is a class information window -- not for an
 *  instances window.
 */

void CWinHitMethod(METHOD_ARGS, struct GuiIntuiMsg *info, OBJECT window)
{
   struct CWinLocalObjects *mlo;
   META   meta;
   struct TagItem tags[2];
   long code = (info)?info->gii_Code:0;

   mlo = FindAttribute(object, ATTR_LOCALWIN);

   {
      struct Node *node;

      for(node = mlo->list.lh_Head; code; --code)
         node = node->ln_Succ;
      mlo->lastNode = (struct MyNode *)node;
   }

   /*
    * Instance size gadget.
    */
   tags[0].ti_Tag = GTNM_Number;
   tags[0].ti_Data = ((META)(mlo->lastNode->object))->meta_size;
   tags[1].ti_Tag = TAG_END;
   DoShadow(mlo->object1, NULL, METH_GADGET_CHANGE, tags, METHOD_END);

   /*
    * Method table size in bytes.
    */
   tags[0].ti_Data = ((META)
                      (mlo->lastNode->object))->meta_verbs.mt_num *
                     sizeof(struct MethodHandler);
   DoShadow(mlo->object2, NULL, METH_GADGET_CHANGE, tags, METHOD_END);

   /*
    * Attribute table size in bytes.
    */
   tags[0].ti_Data = ((META)
                      (mlo->lastNode->object))->meta_attributes.att_num *
                     sizeof(struct Attribute);
   DoShadow(mlo->object3, NULL, METH_GADGET_CHANGE, tags, METHOD_END);

   /*
    * superClass name.
    */
   tags[0].ti_Tag = GTTX_Text;
   meta = ((META)(mlo->lastNode->object))->meta_superClass;
   if (meta)
   {
      QuickDropString(mlo->superClassText);

      tags[0].ti_Data = (ULONG)(mlo->superClassText =
                        UseString(meta->meta_name));
   }
   else
      tags[0].ti_Data = 0L;
   DoShadow(mlo->object4, NULL, METH_GADGET_CHANGE, tags, METHOD_END);
}

void CWinOpenMWinMethod(METHOD_ARGS)
{
   struct CWinLocalObjects *mlo;
   struct GUIStruct *gui;

   mlo = FindAttribute(object, ATTR_LOCALWIN);
   gui = FindAttribute(object, ATTR_GUISTRUCT);

   if (!mlo->lastNode)
      return;

   DropObject(CreateInstance(NULL,
                             METWIN_CLASS,
                             META_CLASS,
                             gui->gui_parent,
                             mlo->lastNode->object,
                             METHOD_END));
}

void CWinOpenAWinMethod(METHOD_ARGS)
{
   struct CWinLocalObjects *mlo;
   struct GUIStruct *gui;

   mlo = FindAttribute(object, ATTR_LOCALWIN);
   gui = FindAttribute(object, ATTR_GUISTRUCT);

   if (!mlo->lastNode)
      return;

   DropObject(CreateInstance(NULL,
                             ATTWIN_CLASS,
                             META_CLASS,
                             gui->gui_parent,
                             mlo->lastNode->object,
                             METHOD_END));
}

void CWinOpenOWinMethod(METHOD_ARGS)
{
   struct CWinLocalObjects *mlo;
   struct GUIStruct *gui;

   mlo = FindAttribute(object, ATTR_LOCALWIN);
   gui = FindAttribute(object, ATTR_GUISTRUCT);

   if (!mlo->lastNode)
      return;

   DropObject(CreateInstance(NULL,
                             CWIN_CLASS,
                             META_CLASS,
                             gui->gui_parent,
                             mlo->lastNode->object,
                             METHOD_END));
}

/*
 * MetWin Class methods.
 */
ARGUMENT_TAG REF_MetWinInitMethod[] = {
                                       {'JOBJ', sizeof(void *),
                                                SHADOW_OBJECT},
                                       {'JOBJ', sizeof(void *),
                                                SHADOW_CLASS},
                                       {TAG_END, SHADOW_RETURN_OBJECT, 0}
                                    };
void *MetWinInitMethod(METHOD_ARGS, OBJECT parent,
                                    CLASS theClass)
{
   struct NewGadget ng;
   struct TagItem tag[8];
   struct MWinLocalObjects *mlo;
   char buffer[128];

   tag[0].ti_Tag = WA_Width;
   tag[0].ti_Data = 500;
   tag[1].ti_Tag = WA_Height;
   tag[1].ti_Data = 200;
   tag[2].ti_Tag = WA_MinWidth;
   tag[2].ti_Data = 60;
   tag[3].ti_Tag = WA_MinHeight;
   tag[3].ti_Data = 40;
   tag[4].ti_Tag = WA_MaxWidth;
   tag[4].ti_Data = -1;
   tag[5].ti_Tag = WA_MaxHeight;
   tag[5].ti_Data = -1;
   tag[6].ti_Tag = WA_SimpleRefresh;
   tag[6].ti_Data = TRUE;
   tag[7].ti_Tag = TAG_END;

   object = DoSuperShadow(object, class, MethodID,
                                         parent,
                                         "Method Window",
                                         NULL,
                                         NULL,
                                         tag,
                                         METHOD_END);
   if (!object)
      return NULL;

   mlo = FindAttribute(object, ATTR_LOCALWIN);
   mlo->class = UseObject(theClass);
   NewList(&mlo->list);

   if (theClass->ccl_verbs.mt_num)
   {
      struct MethodHandler *methods;
      struct MyNode *nodes;
      int i;

      mlo->nodes = AllocVec(sizeof(struct MyNode) * theClass->ccl_verbs.mt_num,
                            MEMF_PUBLIC);

      nodes = mlo->nodes;
      for (methods = theClass->ccl_verbs.mt_methods, i = 0;
           i < theClass->ccl_verbs.mt_num;
           i++, methods++)
      {
         nodes->node.ln_Name = UseString(methods->mh_methodID);
         nodes->object = methods;
         AddTail(&mlo->list, nodes);
         nodes++;
      }

   }

   ng.ng_LeftEdge = ng.ng_TopEdge = 50;
   ng.ng_Width = 300;
   ng.ng_Height = 90;
   ng.ng_Flags = PLACETEXT_ABOVE;
   tag[0].ti_Tag = GTLV_Labels;
   tag[0].ti_Data = (ULONG)&mlo->list;
   tag[1].ti_Tag = GTLV_ShowSelected;
   tag[1].ti_Data = NULL;
   tag[2].ti_Tag = TAG_END;
   strcpy(buffer, "Method list for class: ");
   strncat(buffer, theClass->ccl_name, 14);
   strcat(buffer, "...");
   DropObject(CreateInstance(NULL,
                             GADGT_CLASS,
                             META_CLASS,
                             object,
                             buffer,
                             object,
                             METH_GADGET_SELECT,
                             &ng,
                             LISTVIEW_KIND,
                             tag,
                             METHOD_END));

   ng.ng_TopEdge += ng.ng_Height;
   ng.ng_Height = 15;
   ng.ng_Width = 170;
   ng.ng_Flags = PLACETEXT_RIGHT;
   tag[0].ti_Tag = TAG_END;
   mlo->object1 = CreateInstance(NULL,
                                 GADGT_CLASS,
                                 META_CLASS,
                                 object,
                                 ":Controlled",
                                 object,
                                 METH_GADGET_SELECT,
                                 &ng,
                                 TEXT_KIND,
                                 tag,
                                 METHOD_END);

   ng.ng_TopEdge += ng.ng_Height;
   ng.ng_Height = 15;
   ng.ng_Width = 170;
   ng.ng_Flags = PLACETEXT_RIGHT;
   tag[0].ti_Tag = TAG_END;
   mlo->object2 = CreateInstance(NULL,
                                 GADGT_CLASS,
                                 META_CLASS,
                                 object,
                                 ":Defined",
                                 object,
                                 METH_GADGET_SELECT,
                                 &ng,
                                 TEXT_KIND,
                                 tag,
                                 METHOD_END);

   ng.ng_TopEdge += ng.ng_Height;
   ng.ng_Height = 15;
   ng.ng_Width = 170;
   ng.ng_Flags = PLACETEXT_RIGHT;
   tag[0].ti_Tag = TAG_END;
   mlo->object3 = CreateInstance(NULL,
                                 GADGT_CLASS,
                                 META_CLASS,
                                 object,
                                 ":Function address",
                                 object,
                                 METH_GADGET_SELECT,
                                 &ng,
                                 NUMBER_KIND,
                                 tag,
                                 METHOD_END);

   ng.ng_TopEdge += ng.ng_Height;
   ng.ng_Height = 15;
   ng.ng_Width = 170;
   ng.ng_Flags = PLACETEXT_RIGHT;
   tag[0].ti_Tag = TAG_END;
   mlo->object4 = CreateInstance(NULL,
                                 GADGT_CLASS,
                                 META_CLASS,
                                 object,
                                 ":threadStat",
                                 object,
                                 METH_GADGET_SELECT,
                                 &ng,
                                 TEXT_KIND,
                                 tag,
                                 METHOD_END);

   ng.ng_TopEdge = 50;
   ng.ng_LeftEdge = 370;
   ng.ng_Height = 20;
   ng.ng_Width = 100;
   ng.ng_Flags = 0;
   tag[0].ti_Tag = TAG_END;
   DropObject(CreateInstance(NULL,
                             GADGT_CLASS,
                             META_CLASS,
                             object,
                             "Arguments",
                             object,
                             METH_GADGET_OPEN_RWIN,
                             &ng,
                             BUTTON_KIND,
                             tag,
                             METHOD_END));

   ng.ng_TopEdge += ng.ng_Height;
   ng.ng_Height = 15;
   ng.ng_Width = 25;
   ng.ng_Flags = PLACETEXT_RIGHT;
   tag[0].ti_Tag = TAG_END;
   mlo->object5 = CreateInstance(NULL,
                                 GADGT_CLASS,
                                 META_CLASS,
                                 object,
                                 ":Patches",
                                 object,
                                 METH_GADGET_SELECT,
                                 &ng,
                                 NUMBER_KIND,
                                 tag,
                                 METHOD_END);

   /*
    * So watch the Patch list....
    */
   {
      mlo->director = CreateInstance(NULL,
                                     DIRECTOR_CLASS,
                                     META_CLASS,
                                     "Watch Patches",
                                     object,
                                     METH_METHOD_UPDATE_INFO,
                                       (W_INSERT_NODE | W_REMOVE) |
                                       (SHADOW_OBJECT << 16) |
                                       W_FLAG_AUTOBREAK |
                                       W_FLAG_AUTOREMOVE,
                                     METHOD_END);
      DropObject( DoShadow(mlo->director,
                               NULL,
                               METH_DIRECTOR_ESTABLISH,
                               ATTR_PATCHEDVERBS,
                               theClass,
                               METHOD_END));
   }
   return object;
}

void MetWinDestroyMethod(METHOD_ARGS)
{
   struct MWinLocalObjects *mlo;
   struct Node *node;

   mlo = FindAttribute(object, ATTR_LOCALWIN);
   DropObject(mlo->object1);
   DropObject(mlo->object2);
   DropObject(mlo->object3);
   DropObject(mlo->object4);
   DropObject(mlo->object5);
   DropObject(mlo->class);

   if (mlo->nodes)
   {
      for(node = mlo->list.lh_Head; node->ln_Succ; node = node->ln_Succ)
         QuickDropString(node->ln_Name);

      FreeVec(mlo->nodes);
   }

   CallSuper();
}

void MetWinRemoveMethod(METHOD_ARGS)
{
   struct MWinLocalObjects *mlo;

   mlo = FindAttribute(object, ATTR_LOCALWIN);
   RemoveObject(SetObject(&mlo->director, NULL));
   mlo->director = NULL;

   CallSuper();
}

void MetWinUpdateInfo(METHOD_ARGS)
{
   struct MWinLocalObjects *mlo;
   struct TagItem tags[2];

   mlo = FindAttribute(object, ATTR_LOCALWIN);

   tags[0].ti_Tag = GTNM_Number;
   tags[1].ti_Tag = TAG_END;

   /*
    * Number of Patches
    */
   tags[0].ti_Data = (ULONG)((struct MethodHandler *)
                      (mlo->lastNode->object))->mh_numPatches;
   DoShadow(mlo->object5, NULL, METH_GADGET_CHANGE, tags, METHOD_END);

}

/*
 * A new METHOD has been hit, show the selected argument's information.
 */
void MetWinHitMethod(METHOD_ARGS,  struct GuiIntuiMsg *info, OBJECT window)
{
   struct MWinLocalObjects *mlo;
   struct TagItem tags[2];
   long code = (info)?info->gii_Code:0;

   mlo = FindAttribute(object, ATTR_LOCALWIN);

   mlo->lastNode = &mlo->nodes[code];

   tags[0].ti_Tag = GTTX_Text;
   tags[0].ti_Data = (ULONG)"";
   tags[1].ti_Tag = TAG_END;

   /*
    * Controlled Process Object.
    */
   {
      OBJECT obj;
      struct ShadowProcess *sp;

      obj = ((struct MethodHandler *)
                (mlo->lastNode->object))->mh_procObject;
      PSem(obj, SSEM_LOCK);
      switch(((struct MethodHandler *)mlo->lastNode->object)->mh_flags &
             (METH_FLAG_PORT |METH_FLAG_OBJECT | METH_FLAG_SPEC))
      {
         case METH_FLAG_OBJECT:
            if ((sp = FindAttribute(obj, ATTR_SHADOWPROCESS)) &&
                sp->sp_procName)
               tags[0].ti_Data = (ULONG)sp->sp_procName;
            else
               tags[0].ti_Data = (ULONG)((sp)?"NoNameProcess":
                                              ((obj)?"ILLEGAL! Object":
                                                     "No Object"));
            break;

         case METH_FLAG_PORT:
            if (obj && ((struct MsgPort *)obj)->mp_Node.ln_Name)
               tags[0].ti_Data = (ULONG)
                  ((struct MsgPort *)obj)->mp_Node.ln_Name;
            else
               tags[0].ti_Data = (ULONG)((obj)?"Unnamed Port":"No Port");
            break;

         case METH_FLAG_CLASS:
            if (obj && ((META)obj)->meta_name)
               tags[0].ti_Data = (ULONG)((META)obj)->meta_name;
            else
               tags[0].ti_Data = (ULONG)((obj)?"Unnamed Class":"No Class");
            break;

         case (METH_FLAG_OBJECT | METH_FLAG_SPEC):
            if (((struct MethodInvokeSpec *)obj)->mis_instanceName)
               tags[0].ti_Data = (ULONG)
                  ((struct MethodInvokeSpec *)obj)->mis_instanceName;
            else
               tags[0].ti_Data = (ULONG)"Spec has no instance name?";
            break;
         case (METH_FLAG_PORT | METH_FLAG_SPEC):
            if (((struct MethodInvokeSpec *)obj)->mis_instanceName)
               tags[0].ti_Data = (ULONG)
                  ((struct MethodInvokeSpec *)obj)->mis_instanceName;
            else
               tags[0].ti_Data = (ULONG)"Spec has no port name?";
            break;
         case (METH_FLAG_CLASS | METH_FLAG_SPEC):
            if (((struct MethodInvokeSpec *)obj)->mis_className)
               tags[0].ti_Data = (ULONG)
                  ((struct MethodInvokeSpec *)obj)->mis_className;
            else
               tags[0].ti_Data = (ULONG)"Spec has no class name?";
            break;
      }
      VSem(obj);

   }
   DoShadow(mlo->object1, NULL, METH_GADGET_CHANGE, tags, METHOD_END);
   /*
    * Defined Process Object.
    */
   {
      OBJECT object;
      struct ShadowProcess *sp;

      object = ((struct MethodHandler *)
                (mlo->lastNode->object))->mh_defnObject;
      if (sp = FindAttribute(object, ATTR_SHADOWPROCESS))
         tags[0].ti_Data = (ULONG)((sp->sp_procName)?sp->sp_procName:
                                   "NoName Process");
      else
      {
         tags[0].ti_Data = (ULONG)((object)?"non-Process Object":"No Object");
      }
   }
   DoShadow(mlo->object2, NULL, METH_GADGET_CHANGE, tags, METHOD_END);

   /*
    * Function Address
    */
   tags[0].ti_Tag = GTNM_Number;
   tags[0].ti_Data = (ULONG)((struct MethodHandler *)
                      (mlo->lastNode->object))->mh_method;
   DoShadow(mlo->object3, NULL, METH_GADGET_CHANGE, tags, METHOD_END);

   /*
    * Number of Patches
    */
   tags[0].ti_Tag = GTNM_Number;
   tags[0].ti_Data = (ULONG)((struct MethodHandler *)
                      (mlo->lastNode->object))->mh_numPatches;
   DoShadow(mlo->object5, NULL, METH_GADGET_CHANGE, tags, METHOD_END);

   /*
    * ThreadStat
    */
   tags[0].ti_Tag = GTTX_Text;
   switch(((struct MethodHandler *)
          (mlo->lastNode->object))->mh_threadStat &
          (INVOKE_FORCE | INVOKE_SYNC | INVOKE_ASYNC))
   {
       case INVOKE_CALL:
          tags[0].ti_Data = (ULONG)"Function call";
          break;
       case INVOKE_SYNC:
          tags[0].ti_Data = (ULONG)"Synchronous call";
          break;
       case INVOKE_ASYNC:
          tags[0].ti_Data = (ULONG)"Asynchronous call";
          break;
       case INVOKE_FORCE_SYNC:
          tags[0].ti_Data = (ULONG)"forced synch. call";
          break;
       default:
          tags[0].ti_Data = (ULONG)"forced async. call";
          break;
   }
   DoShadow(mlo->object4, NULL, METH_GADGET_CHANGE, tags, METHOD_END);
}

/*
 * Open the Reference (parameter) Window.
 */
void MWinOpenRWinMethod(METHOD_ARGS)
{
   struct MWinLocalObjects *mlo;

   mlo = FindAttribute(object, ATTR_LOCALWIN);

   if (!mlo->lastNode)
      return;

   DropObject(CreateInstance(NULL,
                             REFWIN_CLASS,
                             META_CLASS,
                             object,
                             mlo->lastNode->object,
                             mlo->class,
                             METHOD_END));
}


/*
 * AttWin Class methods.
 */
ARGUMENT_TAG REF_AttWinInitMethod[] = {
                                       {'JOBJ', sizeof(void *),
                                                SHADOW_OBJECT},
                                       {'JOBJ', sizeof(void *),
                                                SHADOW_CLASS},
                                       { TAG_END, SHADOW_RETURN_OBJECT, 0}
                                    };
void *AttWinInitMethod(METHOD_ARGS, OBJECT parent,
                                    CLASS  theClass)
{
   struct NewGadget ng;
   struct TagItem tag[8];
   struct AWinLocalObjects *mlo;
   char buffer[128];

   tag[0].ti_Tag = WA_Width;
   tag[0].ti_Data = 500;
   tag[1].ti_Tag = WA_Height;
   tag[1].ti_Data = 200;
   tag[2].ti_Tag = WA_MinWidth;
   tag[2].ti_Data = 60;
   tag[3].ti_Tag = WA_MinHeight;
   tag[3].ti_Data = 40;
   tag[4].ti_Tag = WA_MaxWidth;
   tag[4].ti_Data = -1;
   tag[5].ti_Tag = WA_MaxHeight;
   tag[5].ti_Data = -1;
   tag[6].ti_Tag = WA_SimpleRefresh;
   tag[6].ti_Data = TRUE;
   tag[7].ti_Tag = TAG_END;

   object = DoSuperShadow(object, class, MethodID,
                                         parent,
                                         "Attribute Window",
                                         NULL,
                                         NULL,
                                         tag,
                                         METHOD_END);

   if (!object)
      return NULL;

   mlo = FindAttribute(object, ATTR_LOCALWIN);
   mlo->meta = UseObject(theClass);
   NewList(&mlo->list);

   /*
    * Copy all of the attributes into the allocated list.
    */
   if (theClass->ccl_attributes.att_num)
   {
      struct Attribute *attrs;
      struct MyNode *nodes;
      int i;

      mlo->nodes = AllocVec(sizeof(struct MyNode) *
                                 theClass->ccl_attributes.att_num,
                            MEMF_PUBLIC);

      nodes = mlo->nodes;
      for (attrs = theClass->ccl_attributes.att_attrs, i = 0;
           i < theClass->ccl_attributes.att_num;
           i++, attrs++)
      {
         nodes->node.ln_Name = UseString(attrs->attr_name);
         nodes->object = attrs;
         AddTail(&mlo->list, nodes);
         nodes++;
      }
   }

   ng.ng_LeftEdge = ng.ng_TopEdge = 50;
   ng.ng_Width = 300;
   ng.ng_Height = 90;
   ng.ng_Flags = PLACETEXT_ABOVE;
   tag[0].ti_Tag = GTLV_Labels;
   tag[0].ti_Data = (ULONG)&mlo->list;
   tag[1].ti_Tag = GTLV_ShowSelected;
   tag[1].ti_Data = NULL;
   tag[2].ti_Tag = TAG_END;
   strcpy(buffer, "Attributes for class: ");
   strncat(buffer, theClass->ccl_name, 14);
   strcat(buffer, "...");
   DropObject(CreateInstance(NULL,
                             GADGT_CLASS,
                             META_CLASS,
                             object,
                             buffer,
                             object,
                             METH_GADGET_SELECT,
                             &ng,
                             LISTVIEW_KIND,
                             tag,
                             METHOD_END));

   ng.ng_TopEdge += ng.ng_Height;
   ng.ng_Height = 15;
   ng.ng_Width = 80;
   ng.ng_Flags = PLACETEXT_RIGHT;
   tag[0].ti_Tag = TAG_END;
   mlo->object1 = CreateInstance(NULL,
                                 GADGT_CLASS,
                                 META_CLASS,
                                 object,
                                 ":Attribute offset",
                                 object,
                                 METH_GADGET_SELECT,
                                 &ng,
                                 NUMBER_KIND,
                                 tag,
                                 METHOD_END);

   ng.ng_TopEdge += ng.ng_Height;
   ng.ng_Height = 15;
   ng.ng_Width = 80;
   ng.ng_Flags = PLACETEXT_RIGHT;
   tag[0].ti_Tag = TAG_END;
   mlo->object2 = CreateInstance(NULL,
                                 GADGT_CLASS,
                                 META_CLASS,
                                 object,
                                 ":size",
                                 object,
                                 METH_GADGET_SELECT,
                                 &ng,
                                 NUMBER_KIND,
                                 tag,
                                 METHOD_END);

   ng.ng_TopEdge += ng.ng_Height;
   ng.ng_Height = 15;
   ng.ng_Width = 80;
   ng.ng_Flags = PLACETEXT_RIGHT;
   tag[0].ti_Tag = TAG_END;
   mlo->object3 = CreateInstance(NULL,
                                 GADGT_CLASS,
                                 META_CLASS,
                                 object,
                                 ":watcher list",
                                 object,
                                 METH_GADGET_SELECT,
                                 &ng,
                                 NUMBER_KIND,
                                 tag,
                                 METHOD_END);

   ng.ng_TopEdge += ng.ng_Height;
   ng.ng_Height = 15;
   ng.ng_Width = 80;
   ng.ng_Flags = PLACETEXT_RIGHT;
   tag[0].ti_Tag = TAG_END;
   mlo->object4 = CreateInstance(NULL,
                                 GADGT_CLASS,
                                 META_CLASS,
                                 object,
                                 ":default object",
                                 object,
                                 METH_GADGET_SELECT,
                                 &ng,
                                 NUMBER_KIND,
                                 tag,
                                 METHOD_END);
   return object;
}

void AttWinDestroyMethod(METHOD_ARGS)
{
   struct AWinLocalObjects *mlo;
   struct Node *node;

   mlo = FindAttribute(object, ATTR_LOCALWIN);
   DropObject(mlo->object1);
   DropObject(mlo->object2);
   DropObject(mlo->object3);
   DropObject(mlo->object4);
   DropObject(mlo->meta);

   if (mlo->nodes)
   {
      for(node = mlo->list.lh_Head; node->ln_Succ; node = node->ln_Succ)
         QuickDropString(node->ln_Name);

      FreeVec(mlo->nodes);
   }

   CallSuper();
}

/*
 * A new Attribute has been hit, show the selected argument's information.
 */
void AttWinHitMethod(METHOD_ARGS, struct GuiIntuiMsg *info, OBJECT window)
{
   struct AWinLocalObjects *mlo;
   struct TagItem tags[2];
   long code = (info)?info->gii_Code:0;

   mlo = FindAttribute(object, ATTR_LOCALWIN);

   mlo->lastNode = &mlo->nodes[code];

   tags[0].ti_Tag = GTNM_Number;
   tags[0].ti_Data = ((struct Attribute *)
                      (mlo->lastNode->object))->attr_offset;
   tags[1].ti_Tag = TAG_END;

   /*
    * Offset.
    */
   DoShadow(mlo->object1, NULL, METH_GADGET_CHANGE, tags, METHOD_END);

   /*
    * Size
    */
   tags[0].ti_Data = ((struct Attribute *)
                      (mlo->lastNode->object))->attr_size;
   if (tags[0].ti_Data & FLAG_ATTR_WATCHED)
      tags[0].ti_Data = sizeof(struct WatchedTree);
   DoShadow(mlo->object2, NULL, METH_GADGET_CHANGE, tags, METHOD_END);

   /*
    * if watched (attr->size & FLAG_ATTR_WATCHED), then display it.
    *  else -1.
    */
   if (FLAG_ATTR_WATCHED & ((struct Attribute *)
                            (mlo->lastNode->object))->attr_size)
      tags[0].ti_Data = (ULONG)((struct Attribute *)
                      (mlo->lastNode->object))->attr_first;
   else
      tags[0].ti_Data = -1;
   DoShadow(mlo->object3, NULL, METH_GADGET_CHANGE, tags, METHOD_END);

   /*
    * default Object.
    */
   if (FLAG_ATTR_WATCHED & ((struct Attribute *)
                            (mlo->lastNode->object))->attr_size)
      tags[0].ti_Data = (~FLAG_ATTR_WATCHED & ((struct Attribute *)
                          (mlo->lastNode->object))->attr_size);
   else
      tags[0].ti_Data = (ULONG)((struct Attribute *)
                         (mlo->lastNode->object))->attr_value;
   DoShadow(mlo->object4, NULL, METH_GADGET_CHANGE, tags, METHOD_END);
}


/*
 * RefWin Class methods.
 */
ARGUMENT_TAG REF_RefWinInitMethod[] = {
                                       {'JOBJ', sizeof(void *),
                                                SHADOW_OBJECT},
                                       {'MREF', sizeof(void *),
                                                sizeof(struct MethodHandler)},
                                       {'JOBJ', sizeof(void *),
                                                SHADOW_CLASS},
                                       {TAG_END, SHADOW_RETURN_OBJECT, 0}
                                    };
void *RefWinInitMethod(METHOD_ARGS, OBJECT parent,
                                    struct MethodHandler *method,
                                    CLASS mclass)
{
   char *name;
   char buffer[256];
   struct TagItem tag[8];
   struct NewGadget ng;
   struct RWinLocalObjects *mlo;

   strcpy(buffer, "Arguments to: ");
   strncat(buffer, method->mh_methodID, 200);
   name = UseString(buffer);

   {
      OBJECT object2;

      if (object2 =
           FindWatchedTreeStringNode(
              (W_AVLTREE)FindAttribute(parent, ATTR_GUICHILDREN),
              name))
      {
         struct WindowObject *wo;

         /*
          * The window is already up top, so pop it on top of all the
          *  windows.
          */
         if (wo = FindAttribute(object2, ATTR_WINDOW))
            WindowToFront(wo->wo_window);

         DropObject(object2);
         QuickDropString(name);

         /*
          * Destroy this object.
          */
         UseObject(object);
         DropObject(object);
         return NULL;
      }
   }

   tag[0].ti_Tag = WA_Width;
   tag[0].ti_Data = 500;
   tag[1].ti_Tag = WA_Height;
   tag[1].ti_Data = 200;
   tag[2].ti_Tag = WA_MinWidth;
   tag[2].ti_Data = 60;
   tag[3].ti_Tag = WA_MinHeight;
   tag[3].ti_Data = 40;
   tag[4].ti_Tag = WA_MaxWidth;
   tag[4].ti_Data = -1;
   tag[5].ti_Tag = WA_MaxHeight;
   tag[5].ti_Data = -1;
   tag[6].ti_Tag = WA_SimpleRefresh;
   tag[6].ti_Data = TRUE;
   tag[7].ti_Tag = TAG_END;

   object = DoSuperShadow(object, class, MethodID,
                                         parent,
                                         name,
                                         NULL,
                                         NULL,
                                         tag,
                                         METHOD_END);
   QuickDropString(name);

   if (!object)
      return NULL;

   mlo = FindAttribute(object, ATTR_LOCALWIN);
   NewList(&mlo->list);

   /*
    * Copy the method-ref (argument or parameter) designations into
    *  an allocated list.
    */
   if (method->mh_num)
   {
      ARGUMENT_TAG *ref;
      struct MyNode *nodes;

      mlo->nodes = AllocVec(sizeof(struct MyNode) * method->mh_num,
                            MEMF_PUBLIC);

      nodes = mlo->nodes;
      buffer[4] = 0;
      for (ref = method->mh_args; ref->at_tag; ref++)
      {
         *((long *)buffer) = ref->at_tag;
         nodes->node.ln_Name = UseString(buffer);
         nodes->object = ref;
         AddTail(&mlo->list, nodes);
         nodes++;
      }

   }

   ng.ng_LeftEdge = ng.ng_TopEdge = 50;
   ng.ng_Width = 300;
   ng.ng_Height = 90;
   ng.ng_Flags = PLACETEXT_ABOVE;
   tag[0].ti_Tag = GTLV_Labels;
   tag[0].ti_Data = (ULONG)&mlo->list;
   tag[1].ti_Tag = TAG_END;

   strcpy(buffer, "method in class: ");
   if (mclass)
      strncat(buffer, mclass->ccl_name, 18);
   strcat(buffer, "...");
   name = UseString(buffer);
   DropObject(CreateInstance(NULL,
                             GADGT_CLASS,
                             META_CLASS,
                             object,
                             name,
                             object,
                             METH_GADGET_SELECT,
                             &ng,
                             LISTVIEW_KIND,
                             tag,
                             METHOD_END));
   QuickDropString(name);

   ng.ng_TopEdge += ng.ng_Height;
   ng.ng_Height = 15;
   ng.ng_Width = 80;
   ng.ng_Flags = PLACETEXT_RIGHT;
   tag[0].ti_Tag = TAG_END;
   mlo->object1 = CreateInstance(NULL,
                                 GADGT_CLASS,
                                 META_CLASS,
                                 object,
                                 ":size of argument",
                                 object,
                                 METH_GADGET_SELECT,
                                 &ng,
                                 NUMBER_KIND,
                                 tag,
                                 METHOD_END);

   ng.ng_TopEdge += ng.ng_Height;
   ng.ng_Height = 15;
   ng.ng_Width = 80;
   ng.ng_Flags = PLACETEXT_RIGHT;
   tag[0].ti_Tag = TAG_END;
   mlo->object2 = CreateInstance(NULL,
                                 GADGT_CLASS,
                                 META_CLASS,
                                 object,
                                 NULL,
                                 object,
                                 METH_GADGET_SELECT,
                                 &ng,
                                 TEXT_KIND,
                                 tag,
                                 METHOD_END);
   return object;
}

void RefWinDestroyMethod(METHOD_ARGS)
{
   struct RWinLocalObjects *mlo;
   struct Node *node;

   mlo = FindAttribute(object, ATTR_LOCALWIN);
   DropObject(mlo->object1);
   DropObject(mlo->object2);
   DropString(mlo->text);
   if (mlo->nodes)
   {
      for(node = mlo->list.lh_Head; node->ln_Succ; node = node->ln_Succ)
         QuickDropString(node->ln_Name);

      FreeVec(mlo->nodes);
   }
   CallSuper();
}

/*
 * A new ARGUMENT_TAG has been hit, show the selected argument's information.
 */
void RefWinHitMethod(METHOD_ARGS, struct GuiIntuiMsg *info, OBJECT window)
{
   struct RWinLocalObjects *mlo;
   struct TagItem tags[2];
   long code = (info)?info->gii_Code:0;

   mlo = FindAttribute(object, ATTR_LOCALWIN);
   mlo->lastNode = &mlo->nodes[code];

   tags[0].ti_Tag = GTNM_Number;
   tags[0].ti_Data = ((ARGUMENT_TAG *)(mlo->lastNode->object))->at_size;
   tags[1].ti_Tag = TAG_END;

   DoShadow(mlo->object1, NULL, METH_GADGET_CHANGE, tags, METHOD_END);

   {
      char buffer[256];

      switch(((ARGUMENT_TAG *)(mlo->lastNode->object))->at_tag)
      {
         case 'TAGL':
            RawDoFmt("size of tag item: %d",
                     &((ARGUMENT_TAG *)(mlo->lastNode->object))->at_flags,
                     SprintfCallback, buffer);
            break;
         case 'JOBJ':
            switch(((ARGUMENT_TAG *)(mlo->lastNode->object))->at_flags)
            {
               case SHADOW_OBJECT:
                  strcpy(buffer, "Shadow Object");
                  break;
               case SHADOW_CLASSLESSOBJECT:
                  strcpy(buffer, "Shadow Classless");
                  break;
               case SHADOW_META:
                  strcpy(buffer, "Shadow Meta");
                  break;
               case SHADOW_CLASS:
                  strcpy(buffer, "Shadow Class");
                  break;
               case SHADOW_CLUSTER:
                  strcpy(buffer, "Shadow Cluster");
                  break;
               case SHADOW_COMPOSITE:
                  strcpy(buffer, "Shadow Composite");
                  break;
               default:
                  strcpy(buffer, "unknown/unspecified");
                  break;
            }
            break;
         case 'JSTR':
            strcpy(buffer, "String");
            break;
         default:
            RawDoFmt("size of pointer? : %d",
                     &((ARGUMENT_TAG *)(mlo->lastNode->object))->at_flags,
                     SprintfCallback, buffer);
      }

      DropString(mlo->text);
      mlo->text = UseString(buffer);
   }

   tags[0].ti_Tag = GTTX_Text;
   tags[0].ti_Data = (ULONG)mlo->text;
   DoShadow(mlo->object2, NULL, METH_GADGET_CHANGE, tags, METHOD_END);

}
