/*
 * First run attempt at a functional GUI library.
 * I agree, it sucks, but it's good enough, as Americans USED to
 *  say.
 *
 * COPYRIGHT: 1991, 1992 David C. Navas
 *            License granted to SwRI to modify and use as per site
 *             license.  Further distribution license rights granted
 *             upon receipt of agreed upon compensation.
 *            All Other Rights Reserved by Author
 */
#include "gui.h"

/*
 * Of course!  max() is in string.h....
 */
#define USE_BUILTIN_MATH
#include <string.h>

#include <libraries/diskfont.h>
#include <libraries/asl.h>
#include <clib/diskfont_protos.h>
#include <clib/graphics_protos.h>
#include <clib/asl_protos.h>
#include <clib/utility_protos.h>

#include <pragmas/diskfont_pragmas.h>
#include <pragmas/graphics_pragmas.h>
#include <pragmas/asl_pragmas.h>
#include <pragmas/utility_pragmas.h>

#include <shadow/coreRoot.h>
#include <shadow/coreMeta.h>
#include <shadow/misc.h>
#include <shadow/process.h>
#include <shadow/semaphore.h>
#include <shadow/shadowBase.h>
#include <shadow/shadow_proto.h>
#include <shadow/shadow_pragmas.h>

#include <dos/dostags.h>
#include <ipc.h>
#include <ipc_proto.h>

extern struct Library * __far SysBase;
extern struct Library * __far DOSBase;
struct Library * __far GadToolsBase;
struct Library * __far IntuitionBase;
extern struct Library * __far DiskfontBase;
extern struct Library * __far GfxBase;
extern struct Library * __far ShadowBase;
extern struct Library * __far UtilityBase;
struct Library * __far AslBase;

/*
 * external class definitions.
 */
extern char GuiProcClassName[],
            AslProcClassName[],
            GuiTaskName[],
            GuiClassName[],
            WindowClassName[],
            GadgTClassName[],
            AslClassName[];

void RemoveWinSafely(struct Window *win);
void StripIntuiMessages(struct MsgPort *port, struct Window *win);

struct TextAttr __far ta = {"topaz.font", 11, FS_NORMAL,
                            FPF_ROMFONT | FPF_DISKFONT};
struct TextFont * __far tf;

OBJECT __GlobalFocus = NULL;  /* one valid focus only */


/*
 * ==========================================================================
 * =                                                                        =
 * =           Class definition for the GUI process.                        =
 * =                                                                        =
 * ==========================================================================
 */
ATTRIBUTE_TAG guiProcAttrs[] =
                        {
                           ATTR_GUIPROCESS, sizeof(struct GuiProcess), NULL,
                           TAG_END
                        };

ARGUMENT_TAG REF_AssociateGuiProcObject[] =
                        {
                           {
                              'JSTR', 4, 0
                           },
                           {
                              TAG_END, SHADOW_RETURN_OBJECT, 0
                           }
                        };

void __saveds *AssociateGuiProcObject(METHOD_ARGS, char *name);
void __saveds HandleGuiProcObject(METHOD_ARGS);
void __saveds DisGuiProcObject(METHOD_ARGS);

METHOD_TAG guiProcMethods[] =
                        {
                           {
                              METH_PROC_ASSOCIATE,
                              NULL, NULL,
                              INVOKE_FORCE_SYNC,
                              METH_FLAG_OBJECT_AS_DEST, 0,
                              (METHODFUNCTYPE)AssociateGuiProcObject,
                                 REF_AssociateGuiProcObject
                           },
                           {
                              METH_PROC_HANDLER,
                              NULL, NULL,
                              INVOKE_FORCE_SYNC,
                              METH_FLAG_OBJECT_AS_DEST, 0,
                              (METHODFUNCTYPE)HandleGuiProcObject, NULL
                           },
                           {
                              METH_PROC_DISASSOCIATE,
                              NULL, NULL,
                              INVOKE_FORCE_SYNC,
                              METH_FLAG_OBJECT_AS_DEST, 0,
                              (METHODFUNCTYPE)DisGuiProcObject, NULL
                           },
                           TAG_END
                        };


void __saveds *InitAslProcObject(METHOD_ARGS, char *name,
                                 OBJECT junk,
                                 struct SignalSemaphore *semJunk,
                                 struct TagItem *tags);
extern ARGUMENT_TAG REF_InitAslProcObject[];

METHOD_TAG aslProcMethods[] =
                        {
                           {
                              METH_INIT,
                              NULL, NULL,
                              INVOKE_CALL,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)InitAslProcObject,
                                 REF_InitAslProcObject
                           },
                           TAG_END
                        };

/*
 * ==========================================================================
 * =                                                                        =
 * =           Class definition for GUI type of objects.                    =
 * =                                                                        =
 * ==========================================================================
 */

ATTRIBUTE_TAG guiAttrs[] =
                        {
                           ATTR_GUICHILDREN, FLAG_ATTR_WATCHED | SHADOW_TREE,
                                             NULL,
                           ATTR_GUISTRUCT, sizeof(struct GUIStruct), NULL,
                           ATTR_GUIOUTPUT, sizeof(struct OutputStruct), NULL,
                           TAG_END
                        };
METHOD_TAG guiMethods[] =
                        {
                           {
                              METH_REMOVE,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)GuiRemoveMethod, NULL
                           },
                           {
                              METH_DESTROY,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)GuiDestroyMethod, NULL
                           },
                           {
                              METH_INIT,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              GuiInitMethod, REF_GuiInitMethod
                           },
                           {
                              METH_GUI_STATE,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)GuiStateNotify,
                                 REF_GuiStateNotify
                           },
                           {
                              METH_GUI_FOCUS,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)GuiGrabFocus, REF_GuiGrabFocus
                           },
                           TAG_END
                        };

/*
 * ==========================================================================
 * =                                                                        =
 * =           Class definition for window objects.                         =
 * =                                                                        =
 * ==========================================================================
 */

ATTRIBUTE_TAG winAttrs[] =
                        {
                           ATTR_WINDOW, sizeof(struct WindowObject), NULL,
                           TAG_END
                        };

ARGUMENT_TAG REF_MoveWin[],
             REF_PreTitleWindow[];

void MoveWin(METHOD_ARGS, long *);
void WinUpdateMethod(METHOD_ARGS);
BOOL PreTitleWindow(METHOD_ARGS, char *string);

METHOD_TAG winMethods[] =
                        {
                           {
                              METH_INIT,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              WinOpenMethod, REF_WinOpenMethod
                           },
                           {
                              METH_DESTROY,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)WinDestroyMethod, NULL
                           },
                           {
                              METH_WINDOW_CLOSE,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)WinCloseMethod, NULL
                           },
                           {
                              METH_WINDOW_PRETITLE,
                              NULL, NULL,
                              INVOKE_ASYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)PreTitleWindow,
                                 REF_PreTitleWindow
                           },
                           {
                              METH_WINDOW_UPDATE,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)WinUpdateMethod, NULL
                           },
                           {
                              METH_WINDOW_MOVE,
                              NULL, NULL,
                              INVOKE_CALL,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)MoveWin,
                                 REF_MoveWin
                           },
                           TAG_END
                        };

/*
 * ==========================================================================
 * =                                                                        =
 * =           Class definition for gadget objects.                         =
 * =                                                                        =
 * ==========================================================================
 */

ATTRIBUTE_TAG gadAttrs[] =
                        {
                            ATTR_GADGET, sizeof(struct GadgetObject), NULL,
                            TAG_END
                        };

METHOD_TAG gadMethods[] =
                        {
                           {
                              METH_INIT,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              GadgTOpenMethod, REF_GadgTOpenMethod
                           },
                           {
                              METH_GADGET_CHANGE,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)GadgTChangeMethod,
                                 REF_GadgTChangeMethod
                           },
                           TAG_END
                        };


/*
 * ==========================================================================
 * =                                                                        =
 * =           Class definition for asl objects.                            =
 * =                                                                        =
 * ==========================================================================
 */

ATTRIBUTE_TAG aslAttrs[] =
                        {
                            ATTR_ASLREQUEST, sizeof(struct AslRequest), NULL,
                            TAG_END
                        };

extern ARGUMENT_TAG REF_AslOpenMethod[],
                  REF_AslBeginMethod[],
                  REF_AslDoneMethod[];

void *AslOpenMethod(METHOD_ARGS, OBJECT window,
                                 char *name,
                                 OBJECT out_object,
                                 char *out_method,
                                 long aslType,
                                 struct TagItem *tags);

extern void AslBeginMethod(METHOD_ARGS, struct TagItem *);
extern void AslLaunchMethod(METHOD_ARGS, struct TagItem *);
extern void AslDoneMethod(METHOD_ARGS, long);
extern void AslRemoveMethod(METHOD_ARGS);
extern void AslDestroyMethod(METHOD_ARGS);

METHOD_TAG aslMethods[] =
                        {
                           {
                              METH_INIT,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              AslOpenMethod, REF_AslOpenMethod
                           },
                           {
                              METH_REMOVE,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)AslRemoveMethod, NULL
                           },
                           {
                              METH_DESTROY,
                              NULL, NULL,
                              INVOKE_CALL,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)AslDestroyMethod, NULL
                           },
#define SET_ASL_LAUNCH 3
                           {
                              METH_ASL_LAUNCH,
                              NULL, NULL,
                              INVOKE_FORCE_ASYNC,
                              METH_FLAG_CLASS, 0,
                              (METHODFUNCTYPE)AslLaunchMethod,
                                 REF_AslBeginMethod
                           },
                           {
                              METH_ASL_BEGIN,
                              NULL, NULL,
                              INVOKE_CALL,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)AslBeginMethod,
                                 REF_AslBeginMethod
                           },
                           {
                              METH_ASL_DONE,
                              NULL, NULL,
                              INVOKE_SYNC,
                              METH_FLAG_OBJECT, 0,
                              (METHODFUNCTYPE)AslDoneMethod,
                                 REF_AslDoneMethod
                           },
                           TAG_END
                        };


/*
 * ==========================================================================
 * =                                                                        =
 * =                 Initialize these classes                               =
 * =                                                                        =
 * ==========================================================================
 */

void geta4(void);

BOOL InitGUISystem(void)
{
   OBJECT guiTask;
   CLASS  aslProcClass;
   BOOL   success;

   SetupMethodTags(guiProcMethods, (void *)-1, (void *)-1);
   SetupMethodTags(aslProcMethods, (void *)-1, (void *)-1);

   /*
    * Create the guiProcess CLass.
    */
   success = AddAutoResource(NULL,CreateSubClass(NULL,
                                                 PROCESS_CLASS,
                                                 META_CLASS,
                                                 GuiProcClassName,
                                                 NULL,
                                                 guiProcAttrs,
                                                 guiProcMethods,
                                                 METHOD_END),
                             GuiProcClassName);

   /*
    * Create the aslProcess CLass.
    */
   success &= AddAutoResource(NULL,
                              aslProcClass = (CLASS)
                                       UseObject(
                                          CreateSubClass(NULL,
                                                   GuiProcClassName,
                                                   META_CLASS,
                                                   AslProcClassName,
                                                   NULL,
                                                   NULL,
                                                   aslProcMethods,
                                                   METHOD_END)),
                              AslProcClassName);

   /*
    * Create the guiTask
    */
   {
      struct TagItem tag[4];

      tag[0].ti_Tag = NP_Priority;
      tag[0].ti_Data = 1;
      tag[1].ti_Tag = NP_StackSize;
      tag[1].ti_Data = 6000;
      tag[2].ti_Tag = NP_Output;
      tag[2].ti_Data = (ULONG)Open("CONSOLE:", MODE_OLDFILE);
      tag[3].ti_Tag = TAG_END;

      guiTask = CreateInstance(NULL,
                               GuiProcClassName,
                               META_CLASS,
                               GuiTaskName,
                               FindTask(NULL)->tc_UserData,
                               NULL,
                               tag,
                               METHOD_END);

      if (tag[2].ti_Tag != TAG_IGNORE)
         Close(tag[2].ti_Data);
   }

   SetupMethodTags(guiMethods, guiTask, (void *)-1);
   SetupMethodTags(winMethods, guiTask, (void *)-1);
   SetupMethodTags(gadMethods, guiTask, (void *)-1);
   SetupMethodTags(aslMethods, guiTask, (void *)-1);

   aslMethods[SET_ASL_LAUNCH].mtag_procObject = aslProcClass;

   success &= AddAutoResource(NULL,
                              CreateSubClass(NULL,
                                             ROOT_CLASS,
                                             META_CLASS,
                                             GuiClassName,
                                             NULL,
                                             guiAttrs,
                                             guiMethods,
                                             METHOD_END),
                              GuiClassName);

   success &= AddAutoResource(NULL,
                              CreateSubClass(NULL,
                                             GuiClassName,
                                             META_CLASS,
                                             WindowClassName,
                                             NULL,
                                             winAttrs,
                                             winMethods,
                                             METHOD_END),
                              WindowClassName);

   success &= AddAutoResource(NULL,
                              CreateSubClass(NULL,
                                             GuiClassName,
                                             META_CLASS,
                                             GadgTClassName,
                                             NULL,
                                             gadAttrs,
                                             gadMethods,
                                             METHOD_END),
                              GadgTClassName);

   success &= AddAutoResource(NULL,
                              CreateSubClass(NULL,
                                             GuiClassName,
                                             META_CLASS,
                                             AslClassName,
                                             NULL,
                                             aslAttrs,
                                             aslMethods,
                                             METHOD_END),
                              AslClassName);

   success &= AddAutoResource(NULL, guiTask, GuiTaskName);

   DropObject(aslProcClass);
   return success;
}

/*
 ==========================================================================
                           gui task
 ==========================================================================
 */

/*
 * First, define the GUI Process Class
 */
void __saveds *AssociateGuiProcObject(METHOD_ARGS, char *name)
{
   struct GuiProcess *gui = FindAttribute(object, ATTR_GUIPROCESS);

   if (IntuitionBase = OpenLibrary("intuition.library", 36))
   {
      if (GadToolsBase = OpenLibrary("gadtools.library", 36))
      {
         if (UtilityBase = OpenLibrary("utility.library", 36))
         {
            if (AslBase = OpenLibrary("asl.library", 36))
            {
               if (gui->guip_port = CreateMsgPort())
               {
                  if (DiskfontBase = OpenLibrary("diskfont.library", 0))
                  {
                     if (GfxBase = OpenLibrary("graphics.library", 0))
                     {
                        if (tf = OpenDiskFont(&ta))
                        {
                           if (CallSuper())
                              return object;

                           CloseFont(tf);
                        }
                        CloseLibrary(GfxBase);
                     }
                     CloseLibrary(DiskfontBase);
                  }
                  DeleteMsgPort(gui->guip_port);
               }
               CloseLibrary(AslBase);
            }
            CloseLibrary(UtilityBase);
         }
         CloseLibrary(GadToolsBase);
      }
      CloseLibrary(IntuitionBase);
   }
   return NULL;
}

void __saveds HandleGuiProcObject(METHOD_ARGS)
{
   struct ShadowProcess *sp = FindAttribute(object, ATTR_SHADOWPROCESS);
   struct GuiProcess *gui = FindAttribute(object, ATTR_GUIPROCESS);
   struct IPCMessage *msg2;
   struct IntuiMessage *intui;
   ULONG signals;


   while(TRUE)
   {
      signals = Wait( SigBitIPCPort(sp->sp_port) |
                      SigBitIPCPort(sp->sp_replyPort) |
                      (1L << gui->guip_port->mp_SigBit) |
                      SIGBREAKF_CTRL_C);

      while(msg2 = GetIPCMessage(sp->sp_port))
         ParseShadowMessage(msg2, SHADOW_RETURN_MSG_NEVER);

      while(msg2 = GetIPCMessage(sp->sp_replyPort))
         JunkIPCMessage(msg2);

      while(intui = GT_GetIMsg(gui->guip_port))
         HandleIntuiMessage(intui);

      if (signals & SIGBREAKF_CTRL_C)
         if (sp->sp_flags & SHADOW_PROC_FLAGS_DESTROYED)
            break;
   }
}

void __saveds DisGuiProcObject(METHOD_ARGS)
{
   struct GuiProcess *gui = FindAttribute(object, ATTR_GUIPROCESS);

   CloseFont(tf);
   CloseLibrary(DiskfontBase);
   CloseLibrary(GfxBase);
   DeleteMsgPort(gui->guip_port);

   CloseLibrary(AslBase);
   CloseLibrary(UtilityBase);
   CloseLibrary(GadToolsBase);
   CloseLibrary(IntuitionBase);
   CallSuper();
}


ARGUMENT_TAG REF_InitAslProcObject[] = {
                                       'JSTR', 4, 0,
                                       'JOBJ', 4, 0,
                                       'SEMF', 4, 0,
                                       'TAGL', 4, sizeof(struct TagItem),
                                       TAG_END, SHADOW_RETURN_OBJECT
                                     };

void __saveds *InitAslProcObject(METHOD_ARGS, char *name,
                                             OBJECT junk,
                                             struct SignalSemaphore *semJunk,
                                             struct TagItem *tags)
{
   struct TagItem lTags[4];

   lTags[0].ti_Tag = NP_Priority;
   lTags[0].ti_Data = 0;
   lTags[1].ti_Tag = NP_StackSize;
   lTags[1].ti_Data = 6000;
   lTags[2].ti_Tag = NP_Output;
   lTags[2].ti_Data = (ULONG)Open("CONSOLE:", MODE_OLDFILE);
   lTags[3].ti_Tag = TAG_MORE;
   lTags[3].ti_Data = (ULONG)tags;

   ResetPtr(tags, lTags);

   if (!CallSuper())
   {
      Close(lTags[2].ti_Data);
      return NULL;
   }
   return object;
}



/*
 *
 * GUI CLASS METHODS
 *
 */
ARGUMENT_TAG REF_GuiInitMethod[] = {
                                    {'JOBJ', sizeof(void *), SHADOW_OBJECT},
                                    {'JSTR', sizeof(char *), 0},
                                    {'JOBJ', sizeof(void *), SHADOW_OBJECT},
                                    {'JSTR', sizeof(char *), 0},
                                    {TAG_END, SHADOW_RETURN_OBJECT, 0}
                                 };

void *GuiInitMethod(METHOD_ARGS, OBJECT parent,
                                 char *name,
                                 OBJECT out_object,
                                 char *out_method)
{
   W_AVLTREE Wtree;
   struct GUIStruct *gui;
   struct OutputStruct *io;

   gui = FindAttribute(object, ATTR_GUISTRUCT);
   gui->gui_parent = parent;

   if (parent)
      Wtree = FindAttribute(parent, ATTR_GUICHILDREN);

   io = FindAttribute(object, ATTR_GUIOUTPUT);
   io->out_object = out_object;

   UseObject(object);
   UseObject(parent);
   UseObject(out_object);

   if (!name || (name = UseString(name)))
   {
      gui->gui_moniker = name;
      if (!out_method || (out_method = UseString(out_method)))
      {
         io->out_method = out_method;
         if (!parent || AddWatchedTreeStringNode(Wtree, object, name))
         {
            if(DoSuperShadow(object, class, MethodID, METHOD_END))
            {

               DropObject(object);
               return object;
            }
            if (parent) RemoveWatchedTreeStringNode(Wtree, object, name);
         }
         DropString(out_method);
      }
      DropString(name);
   }
   DropObject(object);
   return NULL;
}

/*
 * Watch the semaphores!
 */

void GuiRemoveMethod(METHOD_ARGS)
{
   struct GUIStruct *gui;
   struct OutputStruct *io;
   W_AVLTREE children;
   OBJECT    parent;

   DropObject(ReplaceObject(&__GlobalFocus, NULL, object));

   gui = FindAttribute(object, ATTR_GUISTRUCT);
   io = FindAttribute(object, ATTR_GUIOUTPUT);

   PSem(object, SSEM_LOCK);

   DropObject(io->out_object);
   QuickDropString(io->out_method);

   parent = gui->gui_parent;
   gui->gui_parent = io->out_object = NULL;
   io->out_method = NULL;

   VSem(object);

   children = FindAttribute(object, ATTR_GUICHILDREN);
   PSem(&children->wv_value, SSEM_READ);
   while(children->wv_value)
   {
      OBJECT gadgetObject;

      gadgetObject = UseObject((void *)children->wv_value->bn_value);
      VSem(&children->wv_value);
      DoShadow(gadgetObject, NULL, METH_REMOVE, METHOD_END);
      DropObject(gadgetObject);
      PSem(&children->wv_value, SSEM_READ);
   }

   VSem(&children->wv_value);

   /*
    * remove object from parent list.
    */
   if (parent)
   {
      /*
       * Ignore misnomer, please.
       * Actually, fellow sblings.
       */
      children = FindAttribute(parent, ATTR_GUICHILDREN);
      RemoveWatchedTreeStringNode(children, object, gui->gui_moniker);
   }

   CallSuper();
   DropObject(parent);
}

void GuiDestroyMethod(METHOD_ARGS)
{
   struct GUIStruct *gui;

   gui = FindAttribute(object, ATTR_GUISTRUCT);
   QuickDropString(gui->gui_moniker);
   CallSuper();
}

ARGUMENT_TAG REF_GuiGrabFocus[] = {'flag', 4, 0, TAG_END};

void GuiGrabFocus(METHOD_ARGS, long flag)
{
   DropObject(SetObject(&__GlobalFocus, (flag)?UseObject(object):NULL));
}

/*
 * ARGUMENT_TAG for external use!
 */

ARGUMENT_TAG REF_GuiStateNotify[] = {'INTU', 4, sizeof(struct GuiIntuiMsg),
                                   'JOBJ', 4, SHADOW_OBJECT,
                                   TAG_END};
void GuiStateNotify(METHOD_ARGS, struct GuiIntuiMsg *info, OBJECT window)
{
   struct OutputStruct  *out;
   OBJECT obj2;

   /*
    * Change the focus as required.
    */
   if (info)
      switch(info->gii_Class)
      {
         case MOUSEBUTTONS:
	         if (info->gii_Code & IECODE_UP_PREFIX)
               DropObject(ReplaceObject(&__GlobalFocus, NULL, object));
            else
               DoShadow(object, NULL, METH_GUI_FOCUS,
                                          (void *)TRUE,
                                          METHOD_END);
            break;
         case INACTIVEWINDOW:
            DropObject(ReplaceObject(&__GlobalFocus, NULL, object));
            break;
      }
   out = FindAttribute(object, ATTR_GUIOUTPUT);
   if (!(obj2 = GetObject(&out->out_object)))
      return;

   DoShadow(obj2, NULL, out->out_method, info, window, object, METHOD_END);

   DropObject(obj2);
}

/*
 *
 * WINDOW CLASS METHODS
 *
 */

BOOL CalculateWindowPosition(struct WindowLocation *wloc,
                             struct TagItem *tag,
                             char *name)
{
   struct WindowLocation wl;
   struct Screen *screen;
   struct Window *win;
   ULONG ibaseLock, recurse, origRecurse;
   USHORT left, top, height, width;

   if (!wloc)
   {
      return TRUE;
   }

   if (!(screen = LockPubScreen((char *)GetTagData(WA_PubScreenName,
                                                   NULL,
                                                   tag))))
   {
      return FALSE;
   }

   wl = *wloc;

   /*
    * Setup the tag's ti_Tag values.
    */

   tag[0].ti_Tag = WA_Left;
   tag[1].ti_Tag = WA_Top;
   tag[2].ti_Tag = (wl.wl_width & WLO_Border)?WA_InnerWidth:WA_Width;
   tag[3].ti_Tag = (wl.wl_height & WLO_Border)?WA_InnerHeight:WA_Height;

   /*
    * Take care of screen-percent stuff.  Neat huh?
    */

   if (wl.wl_left & WLO_Percent)
   {
      wl.wl_left &= 0xffff0000;
      wl.wl_left |= (screen->Width * (wl.wl_left & 0xffff))/0xffff;
   }
   if (wl.wl_width & WLO_Percent)
      wl.wl_width = (screen->Width * (wl.wl_width & 0xffff))/0xffff;

   if (wl.wl_left & WLO_UnderMouse)
      wl.wl_left = screen->MouseX;

   /*
    * Left-Width border check.
    */
   if ((wl.wl_left & 0xffff) + (wl.wl_width & 0xffff) > screen->Width)
   {
      wl.wl_left = max(0, screen->Width - (wl.wl_width & 0xffff));
   }

   /*
    * Top edge screen-percents.
    */
   if (wl.wl_top & WLO_Percent)
   {
      wl.wl_top &= 0xffff0000;
      wl.wl_top |= (screen->Height * (wl.wl_top & 0xffff))/0xffff;
   }
   if (wl.wl_height & WLO_Percent)
      wl.wl_height = (screen->Height * (wl.wl_height & 0xffff))/0xffff;

   if (wl.wl_top & WLO_UnderMouse)
      wl.wl_top = screen->MouseY;

   /*
    * Top-Height border check.
    */
   if ((wl.wl_top & 0xffff) + (wl.wl_height & 0xffff) > screen->Height)
   {
      wl.wl_top = max(0, screen->Height - (wl.wl_height & 0xffff));
   }

   /*
    * So, now we have the starting positions.
    * We need to search the screen for a better, optimal location.
    */

   ibaseLock = LockIBase(0L);

   height = width = 0;
   left = (wl.wl_left &= 0xffff);
   top = (wl.wl_top &= 0xffff);
   wl.wl_width &= 0xffff;
   wl.wl_height &= 0xffff;

   name = UseString(name);

   /*
    * Any other windows of the same name around here?
    * We will use their height to pre-calculate the width/height.
    */
   for(win = screen->FirstWindow; win; win= win->NextWindow)
   {
      if (win->Title == name || win->ScreenTitle == name)
      {
         height = win->Height;
         width = win->Width;
         if (!wl.wl_width)
         {
            wl.wl_width = width;
            tag[2].ti_Tag = WA_Width;
         }
         if (!wl.wl_height)
         {
            wl.wl_height = height;
            tag[3].ti_Tag = WA_Height;
         }
         break;
      }
   }


   if (!(wloc->wl_flags & WLO_NoAuto))
   {

      recurse = origRecurse = 0;
      for(win = screen->FirstWindow; win; win = (win)?win->NextWindow:
                                                screen->FirstWindow)
      {
         ULONG xInc, yInc, xInc2, yInc2;

         /*
          * First, is the increment as a percentage of the window
          *  size, or as straight pixels.  The window size is then
          *  either the win->[Width|Height] -OR- without the borders,
          *  depending on whether the BORDER bit is set.  This way you
          *  can skip the border PLUS a remaining portion of the window.
          */
         if (wl.wl_xInc & WLO_Percent)
         {
            if (wl.wl_xInc & WLO_Border)
               xInc = (((win->Width - win->BorderLeft) *
                        (wl.wl_xInc & 0xffff))/0xffff);
            else
               xInc = ((win->Width * (wl.wl_xInc & 0xffff))/0xffff);
         } else
            xInc = (wl.wl_xInc & 0xffff);

         if (wl.wl_yInc & WLO_Percent)
         {
            if (wl.wl_yInc & WLO_Border)
               yInc = (((win->Height - win->BorderTop) *
                        (wl.wl_yInc & 0xffff))/0xffff);
            else
               yInc = ((win->Height * (wl.wl_yInc & 0xffff))/0xffff);
         } else
            yInc = (wl.wl_yInc & 0xffff);

         /*
          * This is the increment for RE_TILE, as well as a check
          *  to verify that the window doesn't encroach on another window
          *  from the left.  The above checks if the window itself is
          *  encroached from the left.
          *
          * The border size is the same for all windows, so....
          */
         if (wl.wl_xInc & WLO_Percent)
         {
            if (wl.wl_xInc & WLO_Border)
               xInc2 = (((width - win->BorderLeft) *
                         (wl.wl_xInc & 0xffff))/0xffff);
            else
               xInc2 = ((width * (wl.wl_xInc & 0xffff))/0xffff);
         } else
            xInc2 = (wl.wl_xInc & 0xffff);

         if (wl.wl_yInc & WLO_Percent)
         {
            if (wl.wl_yInc & WLO_Border)
               yInc2 = (((height - win->BorderTop) *
                         (wl.wl_yInc & 0xffff))/0xffff);
            else
               yInc2 = ((height * (wl.wl_yInc & 0xffff))/0xffff);
         } else
            yInc2 = (wl.wl_yInc & 0xffff);

         /*
          * Add in the border offsets.
          */
         if (wl.wl_xInc & WLO_Border)
            xInc += win->BorderLeft;
         if (wl.wl_yInc & WLO_Border)
            yInc += win->BorderTop;

         if (wl.wl_xInc & WLO_Border)
            xInc2 += win->BorderLeft;
         if (wl.wl_yInc & WLO_Border)
            yInc2 += win->BorderTop;

         /*
          * Is window either:
          *    a) encroached on by another window or
          *    b) encraching ON another window.
          *
          * b) calculation won't work for the first parameter window
          *    of a module....
          */
         if ((left - win->LeftEdge < ((xInc)?xInc:1) &&
              left - win->LeftEdge >= 0 &&
              top - win->TopEdge < ((yInc)?yInc:1) &&
              top - win->TopEdge >= 0)          ||
             (win->LeftEdge - left < ((xInc2)?xInc2:1) &&
              win->LeftEdge - left >= 0 &&
              win->TopEdge - top < ((yInc2)?yInc2:1) &&
              win->TopEdge - top >= 0))
         {
            BOOL changed = FALSE;

            if (recurse)
            {
               --recurse;
               continue;
            }

            if (!( ( (wl.wl_flags & WLO_TileHoriz) &&
                     (wl.wl_flags & WLO_ReTile)     ) ||
                   ( (wl.wl_flags & WLO_TileVert) &&
                    !(wl.wl_flags & WLO_TileHoriz) &&
                    !(wl.wl_flags & WLO_ReTile)     )) &&
                !(wloc->wl_left & WLO_UnderMouse))
            {
               if (wl.wl_flags & WLO_ReTile)
                  left += ((xInc2)?xInc2:xInc);
               else
                  left = win->LeftEdge + xInc;
               changed = TRUE;
            }
            if (!( ( (wl.wl_flags & WLO_TileVert ) &&
                     (wl.wl_flags & WLO_ReTile)     ) ||
                   ( (wl.wl_flags & WLO_TileHoriz) &&
                    !(wl.wl_flags & WLO_TileVert ) &&
                    !(wl.wl_flags & WLO_ReTile)     )) &&
                !(wloc->wl_top & WLO_UnderMouse))
            {
               if (wl.wl_flags & WLO_ReTile)
                  top += ((yInc2)?yInc2:yInc);
               else
                  top = win->TopEdge + yInc;
               changed = TRUE;
            }

            if (!changed && !(wl.wl_flags & WLO_ReTile))
               /*
                * Caught in non-update loop!
                */
               break;

            wl.wl_flags &= ~WLO_ReTile;

            /*
             * Double border problem?
             */
            if ((top + ((height)?height:win->Height) > screen->Height) &&
                (left + ((width)?width:win->Width) > screen->Width))
            {
               top = wl.wl_top;
               left = wl.wl_left & 0xffff;
               if (top == wl.wl_top |
                   left == wl.wl_left)
                  break;
               origRecurse++;
               wl.wl_flags &= ~(WLO_ResetHoriz | WLO_ResetVert);
            }

            /*
             * Border collision check.
             */
            if (top + ((height)?height:win->Height) > screen->Height)
            {
               if (top == wl.wl_top)
                  break;

               top = wl.wl_top;
               wl.wl_flags |= WLO_ResetVert;
               if (wl.wl_flags & WLO_TileVert)
                  wl.wl_flags |= WLO_ReTile;

               if (wl.wl_flags & WLO_ResetHoriz ||
                   !wl.wl_xInc ||
                   (wloc->wl_left & WLO_UnderMouse))
               {
                  origRecurse++;
                  wl.wl_flags &= ~(WLO_ResetHoriz | WLO_ResetVert);
               }
            }

            if (left + ((width)?width:win->Width) > screen->Width)
            {
               if (left == wl.wl_left)
                  break;

               left = wl.wl_left;
               wl.wl_flags |= WLO_ResetHoriz;
               if (wl.wl_flags & WLO_TileHoriz)
                  wl.wl_flags |= WLO_ReTile;
               if (wl.wl_flags & WLO_ResetVert ||
                   !wl.wl_yInc ||
                   (wloc->wl_top & WLO_UnderMouse))
               {
                  origRecurse++;
                  wl.wl_flags &= ~(WLO_ResetHoriz | WLO_ResetVert);
               }
            }

            recurse = origRecurse;
            win = NULL;
         }
      }
   }

   tag[0].ti_Data = left;
   tag[1].ti_Data = top;
   tag[2].ti_Data = (wl.wl_width)?wl.wl_width:1;
   tag[3].ti_Data = (wl.wl_height)?wl.wl_height:1;

   UnlockIBase(ibaseLock);
   QuickDropString(name);
   UnlockPubScreen(NULL, screen);

   return TRUE;
}

/*
 * METH_INIT
 */
ARGUMENT_TAG  REF_WinOpenMethod[] = {
                                     {'JOBJ', sizeof(void *), SHADOW_OBJECT},
                                     {'JSTR', sizeof(char *), 0},
                                     {'JOBJ', sizeof(void *), SHADOW_OBJECT},
                                     {'JSTR', sizeof(char *), 0},
                                     {'TAGL', sizeof(void *),
                                              sizeof(struct TagItem)},
                                     {'JOBJ', sizeof(OBJECT), SHADOW_OBJECT},
                                     {TAG_END, SHADOW_RETURN_OBJECT, 0}
                                  };

void *WinOpenMethod(METHOD_ARGS, OBJECT parent,
                                 char *name,
                                 OBJECT out_object,
                                 char *out_method,
                                 struct TagItem *tags,
                                 OBJECT wlObject)
{
   struct WindowObject *wobj;
   struct WindowLocation *wl;
   struct TagItem tag[5];

   tag[0].ti_Tag = tag[4].ti_Tag = TAG_MORE;
   tag[0].ti_Data = tag[4].ti_Data = (ULONG)tags;

   if (!CalculateWindowPosition(wl = (void *)GetTagData(WLO_Location,
                                                        NULL,
                                                        tags),
                                tag,
                                name))
   {
      DropObject(UseObject(object));
      return NULL;
   }

   UseObject(object);
   wobj = FindAttribute(object, ATTR_WINDOW);
   name = UseString(name);

   if (wobj->wo_window = OpenWindowTags(NULL, WA_Flags, 0xf,
                                              WA_Title, name,
                                              TAG_MORE, tag))
   {
      struct GuiProcess *gui;

      gui = FindAttribute(FindTask(NULL)->tc_UserData, ATTR_GUIPROCESS);

      wobj->wo_window->UserPort = gui->guip_port;
      wobj->wo_window->UserData = (void *)object;

      /*
       * Would require V37 to check ModifyIDCMP!
       */

      ModifyIDCMP(wobj->wo_window, LISTVIEWIDCMP | CLOSEWINDOW |
                                   REFRESHWINDOW | INACTIVEWINDOW |
                                   ACTIVEWINDOW);

      {
         if (wobj->wo_vi = GetVisualInfo(wobj->wo_window->WScreen, TAG_END))
         {
            if (wobj->wo_lastGadget = CreateContext(&wobj->wo_rootGadget))
            {
               AddGList(wobj->wo_window, wobj->wo_rootGadget, -1, -1, NULL);

               /*
                * Force tags to NULL -- ick, I hate optimizers.
                */

               ForceMethodEnd(out_method);

               if (CallSuper())
               {
                  /*
                   * Used twice, once for return, once in window structure.
                   */

                  /*
                   * Name is in superClass under gui->gui_moniker
                   */
                  DropString(name);
                  wobj->wo_wl = wl;

                  if (wl && (wl->wl_flags & WLO_Backstore) && wlObject)
                  {
                     wl->wl_localLeft = wobj->wo_window->LeftEdge;
                     wl->wl_localTop = wobj->wo_window->TopEdge;
                     wl->wl_localWidth = wobj->wo_window->Width;;
                     wl->wl_localHeight = wobj->wo_window->Height;
                  }
                  DropObject(SetObject(&wobj->wo_wlObject,
                                       UseObject(wlObject)));
                  return object;
               }
            }
         }
      }
      DropString(name);
      DoShadow(object, NULL, METH_WINDOW_CLOSE, METHOD_END);
      return NULL;
   }
   DropString(name);
   DropObject(object);
   return NULL;
}

void WinDestroyMethod(METHOD_ARGS)
{
   struct WindowObject *wobj = FindAttribute(object, ATTR_WINDOW);
   char *localWindowName = wobj->wo_localWindowName;
   struct Window *window;

   if (window = wobj->wo_window)
   {
      if (wobj->wo_rootGadget)
      {
         FreeGadgets(wobj->wo_rootGadget);
      }
      CloseWindow(window);
   }

   FreeVisualInfo(wobj->wo_vi);

   CallSuper();

   if (localWindowName)
      FreeMem(localWindowName, strlen(localWindowName) + 1);
}

void WinUpdateMethod(METHOD_ARGS)
{
   struct WindowObject *wo;
   struct WindowLocation *wl;
   OBJECT wlObject;

   wo = FindAttribute(object, ATTR_WINDOW);

   /*
    * Figure out what to do with the location stuff, if anything.
    */
   /*
    * Reset leftedge/topedge if -modified- from original setting set
    *  NOAUTO!
    */
   if ((wlObject = GetObject(&wo->wo_wlObject)) &&
       (wl = wo->wo_wl) &&
       (wl->wl_flags & WLO_Backstore))
   {
      if (wo->wo_window->LeftEdge != wl->wl_localLeft ||
          wo->wo_window->TopEdge != wl->wl_localTop   ||
          wo->wo_window->Width != wl->wl_localWidth   ||
          wo->wo_window->Height != wl->wl_localHeight)
      {
         wl->wl_left = wo->wo_window->LeftEdge;
         wl->wl_width = wo->wo_window->Width;
         wl->wl_top = wo->wo_window->TopEdge;
         wl->wl_height = wo->wo_window->Height;
         wl->wl_flags |= WLO_NoAuto;
      }
   }
   DropObject(wlObject);

}

void WinCloseMethod(METHOD_ARGS)
{
   struct WindowObject *wo;
   struct Window *window;

   wo = FindAttribute(object, ATTR_WINDOW);

   /*
    * Update window locations.
    */
   DoShadow(object, NULL, METH_WINDOW_UPDATE, METHOD_END);
   DropObject(SetObject(&wo->wo_wlObject, NULL));

   /*
    * Should remove all child gadgets.
    */

   if (window = wo->wo_window)
   {
      RemoveGList(window, wo->wo_rootGadget, -1);
      RemoveWinSafely(window);      /* Unuses object from UserData field */
   }
   CallSuper();
}

ARGUMENT_TAG REF_MoveWin[] = {'APTR', 4, sizeof(ULONG) * 4, TAG_END};

void MoveWin(METHOD_ARGS, long *pos)
{
   struct WindowObject *wo;

   if (!pos)
      return;

   wo = FindAttribute(object, ATTR_WINDOW);
   ChangeWindowBox(wo->wo_window, pos[0], pos[1], pos[2], pos[3]);
}

ARGUMENT_TAG REF_PreTitleWindow[] = {'JSTR', 4, 0, TAG_END};

/*
 * ASYNC, so the return is ignored, but just in case....
 */
BOOL PreTitleWindow(METHOD_ARGS, char *string)
{
   struct GUIStruct *gui = FindAttribute(object, ATTR_GUISTRUCT);
   struct WindowObject *wo = FindAttribute(object, ATTR_WINDOW);
   char *title;
   int length;

   if ( (length = strlen(string) + strlen(gui->gui_moniker)) > 250)
   {
      return FALSE;
   }
   PSem(&wo->wo_localWindowName, SSEM_WRITE);
   if (wo->wo_localWindowName)
      FreeMem(wo->wo_localWindowName, strlen(wo->wo_localWindowName) + 1);
   if (title = wo->wo_localWindowName = AllocMem(length + 4, MEMF_PUBLIC))
   {
      strcpy(title, string);
      strcat(title, " : ");
      strcat(title, gui->gui_moniker);
      SetWindowTitles(wo->wo_window, title, (char *)-1);
      VSem(&wo->wo_localWindowName);
      return TRUE;
   }

   VSem(&wo->wo_localWindowName);
   return FALSE;
}

/*
 *
 * GADGT METHODS
 *
 */

ARGUMENT_TAG REF_GadgTOpenMethod[] =
                                    {
                                       'JOBJ', sizeof(OBJECT),
                                               SHADOW_OBJECT,
                                       'JSTR', sizeof(char *), 0,
                                       'JOBJ', sizeof(void *),
                                               SHADOW_OBJECT,
                                       'JSTR', sizeof(char *), 0,
                                       'NGAD', sizeof(struct NewGadget *),
                                               sizeof(struct NewGadget),
                                       'type', sizeof(long), 0,
                                       'TAGL', sizeof(void *),
                                               sizeof(struct TagItem),
                                       {TAG_END, SHADOW_RETURN_OBJECT, 0}
                                    };

void *GadgTOpenMethod(METHOD_ARGS, OBJECT window,
                                   char *name,
                                   OBJECT out_object,
                                   char *out_method,
                                   struct NewGadget *ng,
                                   long gadType,
                                   struct TagItem *tags)
{
   struct GadgetObject *gobj;
   struct WindowObject *windowObj;

   UseObject(object);
   if (!window || !ng)
   {
      DropObject(object);
      return NULL;
   }

   gobj = FindAttribute(object, ATTR_GADGET);
   if (!(windowObj = FindAttribute(window, ATTR_WINDOW)))
   {
      DropObject(object);
      return NULL;
   }

   ng->ng_TextAttr = &ta;
   ng->ng_VisualInfo = windowObj->wo_vi;
   ng->ng_UserData = object;
   ng->ng_GadgetText = UseString(name);
   ng->ng_GadgetID = gadType;

   RemoveGList(windowObj->wo_window, windowObj->wo_rootGadget, -1);

   if (gobj->go_gadget = CreateGadgetA(gadType, windowObj->wo_lastGadget, ng, tags))
   {
      AddGList(windowObj->wo_window, windowObj->wo_rootGadget, -1, -1, NULL);

      ForceMethodEnd(ng);
      if (CallSuper())
      {
         RefreshGList(windowObj->wo_lastGadget, windowObj->wo_window, NULL, ((UWORD)-1));
         windowObj->wo_lastGadget = gobj->go_gadget;

         GT_RefreshWindow(windowObj->wo_window, NULL);

         /*
          * name used by superClass, can drop it here.
          * Otherwise would have to subclass METH_DESTROY, which would suck.
          */
         DropString(name);
         DropObject(object);
         return object;
      }
   } else
      AddGList(windowObj->wo_window, windowObj->wo_rootGadget, -1, -1, NULL);
   DropObject(object);
   return NULL;
}

ARGUMENT_TAG REF_GadgTChangeMethod[] =
                                    {
                                       'TAGL', sizeof(void *),
                                               sizeof(struct TagItem),
                                       TAG_END
                                    };
void GadgTChangeMethod(METHOD_ARGS, struct TagItem *tags)
{
   struct GadgetObject *gobj;
   struct GUIStruct *gui;
   struct WindowObject *windowObj;

   gobj = FindAttribute(object, ATTR_GADGET);
   gui = FindAttribute(object, ATTR_GUISTRUCT);
   windowObj = FindAttribute(gui->gui_parent, ATTR_WINDOW);

   GT_SetGadgetAttrsA(gobj->go_gadget, windowObj->wo_window, NULL, tags);
}

/*
 *
 * ASL METHODS
 *
 */

ARGUMENT_TAG REF_AslOpenMethod[] =
                                    {
                                       'JOBJ', sizeof(OBJECT),
                                               SHADOW_OBJECT,
                                       'JSTR', sizeof(char *), 0,
                                       'JOBJ', sizeof(void *),
                                               SHADOW_OBJECT,
                                       'JSTR', sizeof(char *), 0,
                                       'type', sizeof(long), 0,
                                       'TAGL', sizeof(void *),
                                               sizeof(struct TagItem),
                                       {TAG_END, SHADOW_RETURN_OBJECT, 0}
                                    };

void *AslOpenMethod(METHOD_ARGS, OBJECT window,
                                 char *name,
                                 OBJECT out_object,
                                 char *out_method,
                                 long gadType,
                                 struct TagItem *tags)
{
   struct AslRequest *aslR;
   struct WindowObject *windowObj;
   struct TagItem lTags[10], *t = lTags, *t2;

   aslR = FindAttribute(object, ATTR_ASLREQUEST);

   aslR->ar_gadType = gadType;

   if (!(t2 = FindTagItem(ASL_Window, tags)) &&
       (windowObj = FindAttribute(window, ATTR_WINDOW)))
   {
      t->ti_Tag = ASL_Window,
      t->ti_Data = (ULONG)windowObj->wo_window;
      t++;
   } else if (t2)
   {
      struct Window *win;

      win = (struct Window *)t2->ti_Data;
      *(OBJECT *)((ULONG)&window) = (OBJECT)win->UserData;
   }

   if (!FindTagItem(ASL_Hail, tags))
   {
      t->ti_Tag = ASL_Hail;
      t->ti_Data = (ULONG)UseString(name);
      t++;
   } else UseString(name);

   if (t2 = FindTagItem(ASL_FuncFlags, tags))
   {
      t2->ti_Data |=
         ((gadType == ASL_FileRequest)?FILF_NEWIDCMP:FONF_NEWIDCMP);
   } else
   {
      t->ti_Tag = ASL_FuncFlags;
      t->ti_Data = (gadType == ASL_FileRequest)?FILF_NEWIDCMP:FONF_NEWIDCMP;
      t++;
   }

   t->ti_Tag = TAG_MORE;
   t->ti_Data = (ULONG)tags;

   if (aslR->ar_Requester = AllocAslRequest(gadType, lTags))
   {
      ForceMethodEnd(gadType);
      if (CallSuper())
      {
         /*
          * name used by superClass, can drop it here.
          * Otherwise would have to subclass METH_DESTROY, which would suck.
          */
         DropString(name);
         aslR->ar_ParentWindow = UseObject(window);
         return object;
      }
      FreeAslRequest(aslR->ar_Requester);
      aslR->ar_Requester = NULL;
   }
   DropString(name);
   DropObject(UseObject(object));
   return NULL;
}

ARGUMENT_TAG REF_AslBeginMethod[] =   {
                                       'TAGL', sizeof(void *),
                                               sizeof(struct TagItem),
                                       TAG_END
                                    };
void AslBeginMethod(METHOD_ARGS, struct TagItem *tags)
{
   struct AslRequest *ar = FindAttribute(object, ATTR_ASLREQUEST);
   struct TagItem *t;


   if (ar->ar_OpenFlag & (ASL_FLAG_BEGUN | ASL_FLAG_REMOVE))
      return;

   ar->ar_OpenFlag |= ASL_FLAG_BEGUN;

   if (t = FindTagItem(ASL_Window, tags))
   {
      struct Window *win;

      win = (struct Window *)t->ti_Data;
      DropObject(SetObject(&ar->ar_LocalWindow,
                           UseObject((OBJECT)win->UserData)));
      DropObject(SetObject(&ar->ar_ParentWindow, NULL));
   }

   if ((ar->ar_gadType == ASL_FontRequest) &&
       (t = FindTagItem(ASL_FontName, tags)))
      t->ti_Data = (ULONG)(ar->ar_FontName = UseString((char *)t->ti_Data));

   if (ar->ar_gadType == ASL_FileRequest)
   {
      if (t = FindTagItem(ASL_File, tags))
         t->ti_Data = (ULONG)(ar->ar_File = UseString((char *)t->ti_Data));
      if (t = FindTagItem(ASL_Dir, tags))
         t->ti_Data = (ULONG)(ar->ar_Dir = UseString((char *)t->ti_Data));
   }

   if (t = FindTagItem(ASL_OKText, tags))
      t->ti_Data = (ULONG)(ar->ar_OKText = UseString((char *)t->ti_Data));

   if (t = FindTagItem(ASL_CancelText, tags))
      t->ti_Data = (ULONG)(ar->ar_CancelText = UseString((char *)t->ti_Data));

   DoShadow(object, NULL, METH_ASL_LAUNCH, tags, METHOD_END);
}

void AslLaunchMethod(METHOD_ARGS, struct TagItem *tags)
{
   struct AslRequest *ar = FindAttribute(object, ATTR_ASLREQUEST);

   DoShadow(object,
                NULL,
                METH_ASL_DONE,
                (void *)AslRequest(ar->ar_FileRequester, tags),
                METHOD_END);
}

ARGUMENT_TAG REF_AslDoneMethod[] =  {
                                    'long', 4, 0,
                                    TAG_END
                                 };

void AslDoneMethod(METHOD_ARGS, long succeed)
{
   OBJECT output;
   struct AslRequest *ar;
   struct OutputStruct *io;

   ar = FindAttribute(object, ATTR_ASLREQUEST);

   DropString(ar->ar_FontName);
   DropString(ar->ar_File);
   DropString(ar->ar_Dir);
   DropString(ar->ar_OKText);
   DropString(ar->ar_CancelText);
   DropObject(SetObject(&ar->ar_LocalWindow, NULL));

   ar->ar_FontName = NULL;
   ar->ar_File = NULL;
   ar->ar_Dir = NULL;
   ar->ar_OKText = NULL;
   ar->ar_CancelText = NULL;

   ar->ar_OpenFlag &= ~ASL_FLAG_BEGUN;

   io = FindAttribute(object, ATTR_GUIOUTPUT);
   output = GetObject(&io->out_object);

   DoShadow(output, NULL, io->out_method, object, succeed, METHOD_END);
   DropObject(output);

   if (ar->ar_OpenFlag & ASL_FLAG_REMOVE)
   {
      DropObject(SetObject(&ar->ar_ParentWindow, NULL));
   }
}

void AslRemoveMethod(METHOD_ARGS)
{
   struct AslRequest *ar;

   ar = FindAttribute(object, ATTR_ASLREQUEST);

   ar->ar_OpenFlag |= ASL_FLAG_REMOVE;
   if (!(ar->ar_OpenFlag & ASL_FLAG_BEGUN))
   {
      DropObject(SetObject(&ar->ar_LocalWindow, NULL));
      DropObject(SetObject(&ar->ar_ParentWindow, NULL));
   }
   CallSuper();
}

void AslDestroyMethod(METHOD_ARGS)
{
   struct AslRequest *ar;

   ar = FindAttribute(object, ATTR_ASLREQUEST);

   FreeAslRequest(ar->ar_Requester);
   ar->ar_Requester = NULL;
   CallSuper();
}

/*
 ==============================================================================
 =                                                                            =
 =                            SUPPLEMENTARY                                   =
 =                                                                            =
 ==============================================================================
 */
void HandleIntuiMessage(struct IntuiMessage *intui)
{
   OBJECT winObject, gadObject;
   int class;

   if (!intui)
      return;

   winObject = UseObject((OBJECT)intui->IDCMPWindow->UserData);

   switch(class = intui->Class) {

      case NEWSIZE:
         DoShadow(winObject,
                      NULL,
                      METH_GUI_RESIZE,
                      (void *)intui->IDCMPWindow->LeftEdge,
                      (long)intui->IDCMPWindow->TopEdge,
                      (long)intui->IDCMPWindow->Width,
                      (long)intui->IDCMPWindow->Height,
                      METHOD_END);
         break;

      case CLOSEWINDOW:
      {
         struct IntuiMessage intui2 = *intui;

         GT_ReplyIMsg(intui);
         DoShadow(winObject,
                      NULL,
                      METH_WINDOW_CLOSE,
                      &intui2.Class,
                      winObject,
                      METHOD_END);
         break;
      }

      case NEWPREFS:
      case DISKINSERTED:
      case DISKREMOVED:
      case ACTIVEWINDOW:
      case INACTIVEWINDOW:
      case CHANGEWINDOW:
         DoShadow(winObject,
                      NULL,
                      METH_GUI_STATE,
                      &intui->Class,
                      winObject,
                      METHOD_END);
         break;

      case MOUSEBUTTONS:
      case MOUSEMOVE:
      case RAWKEY:
      case DELTAMOVE:
      case VANILLAKEY:
      case INTUITICKS:
         gadObject = GetObject(&__GlobalFocus);
         DoShadow((gadObject)?gadObject:winObject,
                      NULL,
                      METH_GUI_STATE,
                      &intui->Class,
                      winObject,
                      METHOD_END);
         DropObject(gadObject);
         break;

      case REFRESHWINDOW:
         GT_BeginRefresh(intui->IDCMPWindow);
         DoShadow(winObject,
		      NULL,
		      METH_WINDOW_REFRESH,
		      &intui->Class,
		      winObject,
		      METHOD_END);
         GT_EndRefresh(intui->IDCMPWindow, TRUE);
         break;

      case GADGETDOWN:
      case GADGETUP:
         gadObject = GetObject((OBJECT *)&
                                ((struct Gadget *)intui->IAddress)->UserData);
         DoShadow(gadObject, NULL, METH_GUI_STATE,
                                       &intui->Class,
                                       winObject,
                                       METHOD_END);
         DropObject(gadObject);
         break;

      default:
         break;
   }

   if (class != CLOSEWINDOW)
      GT_ReplyIMsg(intui);

   DropObject(winObject);
}

void RemoveWinSafely(struct Window *win)
{
   void *object;

   object = win->UserData;
   if (win->UserPort)
   {
      Forbid();
      StripIntuiMessages(win->UserPort, win);
      win->UserPort = NULL;
      ModifyIDCMP(win, NULL);
      win->UserData = NULL;
      Permit();

      /*
       * stop using this object in window structure.
       */
      DropObject(object);
   }
}

void StripIntuiMessages(struct MsgPort *port, struct Window *win)
{
   struct IntuiMessage *msg;
   struct Node *succ;

   msg = (struct IntuiMessage *)port->mp_MsgList.lh_Head;

   while(succ = msg->ExecMessage.mn_Node.ln_Succ)
   {
      if (msg->IDCMPWindow == win)
      {
         Remove(msg);
         ReplyMsg(msg);
      }
      msg = (struct IntuiMessage *)succ;
   }
}
