/*
 *  WICONIFY    A utility that allows you to iconify any Intuition window
 *              on any screen, and to open WB windows on any screen.
 *
 *  wIconify.c  Main loader code.
 *
 *  Copyright 1990 by Davide P. Cervone, all rights reserved.
 *  You may use this code, provided this copyright notice is kept intact.
 */

#include <intuition/intuitionbase.h>
#include <devices/input.h>
#include "wIconify.h"
#include "wSetup.h"
#include "wMenu.h"
#include <libraries/dosextens.h>

extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;
struct LayersBase *LayersBase;
extern struct SysBase *SysBase;
extern struct DOSBase *DOSBase;

static char *program   = PROGRAM;
static char *copyright = COPYRIGHT;

static char *handler   = HANDLERCODE2;      /* The name of the handler file */
static char *HANDLER   = HANDLERCODE1;

static char *InitFile = INITFILENAME2;      /* the Init file */
static char *INITFILE = INITFILENAME1;

#define DEFAULTCOMMAND      "NEWSHELL"      /* the default CLI command */
#define K                   *1024           /* for things like 2K */

static struct HandlerData *HandlerData;     /* data shared with handler */
static long Segment;                        /* The loaded handler segment */
static APTR HandlerTask;                    /* The process created */

static struct MsgPort *InputPort;           /* To talk to Input.Device */
static struct IOStdReq *InputBlock;         /* IO block for Input.Device */
static int    InputDevice;                  /* Is Input.Device open? */
static int    VectorsSet;                   /* TRUE after SetFunction */
static int    HandlerAdded;                 /* TRUE after TellInputDevice */
static int    AllOK;                        /* TRUE after ActivateIconify */


#define vSETFUNC(lvo,func)  SetFunction(IntuitionBase,&lvo,var(func))
#define VSETFUNC(lvo,func)  SetFunction(IntuitionBase,&lvo,VAR(func))

#define HANDLERPROC     ((struct Process *)HandlerTask)


struct Menu *wMenuBar;              /* The wIconify window's menu bar */
struct wMenuItem *OpenWindowMenu;   /* the OpenOn sub-menu */
char *HiResCLICommand;              /* The HIRES NewCLI command string */
char *LoResCLICommand;              /* The LOWRES NewCLI command string */
long StackSize;                     /* The CLI command stack size */
struct Image *DefaultImage;         /* Image for icons that don't give one */
struct Image *DefaultSelect;        /* Select image for icons without one */
struct Image *DefaultMask;          /* Default mask for Image or Select */
struct Image *DefaultScreenImage;   /* Image for screens that don't give one */
struct Image *DefaultScreenSelect;  /* Select image for screenss without one */
struct Image *DefaultScreenMask;    /* Default mask for screen icons */
ULONG DefaultFlags;                 /* Icon flags default icons */
ULONG DefaultScreenFlags;           /* Icon flags default screen icons */
struct Ignore *IgnoreScreen;        /* List of screen titles to ignore */
UBYTE IconifyKey = WICONIFYKEY;     /* Key for iconifying active window */
UBYTE ActivateKey = WACTIVEKEY;     /* Key for activating wIconify window */
UWORD IconifyQuals = WQUALIFIERS;   /* Qualifiers for iconifying a window */
UWORD IconifyDisquals;              /* Qualifiers that prevent iconifying */
UWORD IconifyChange = WCHANGEQUALS; /* Qualifiers for changing refresh type */
UWORD ActivateQuals = WACTIVEQUAL;  /* Qualifiers for activating wIconify */
int IconifyPriority;                /* Priority of handler as a process */
int HandlerPriority = 51;           /* Priority of Input Handler in chain */
UWORD *ScreenColors;                /* Default New Screen color map */
int AutoResize = TRUE;              /* Size windows to fit screen? */
int ScreenType = OW_ACTIVESCRN;     /* Where to open WB windows */


/*
 *  SetWindowMenu()
 *
 *  Set the menu flags for the OpenOn submenu so that the proper ones
 *  are checked.
 */

static void SetWindowMenu(ScreenType,SizeToFit)
int ScreenType,SizeToFit;
{
   short i;

   if (ScreenType != NOCHANGE)
   {
      for (i=OW_ACTIVESCRN; i<=OW_REALWB; i++)
      {
         if (i == ScreenType)
           OpenWindowMenu[i].Item.Flags |=  CHECKED;
          else
           OpenWindowMenu[i].Item.Flags &= ~CHECKED;
      }
   }
   if (SizeToFit != NOCHANGE)
   {
      if (SizeToFit)
         OpenWindowMenu[OW_AUTORESIZE].Item.Flags |=  CHECKED;
        else
         OpenWindowMenu[OW_AUTORESIZE].Item.Flags &= ~CHECKED;
   }
}


/*
 *  FreeImage()
 *
 *  If the image is not the defualt image (which was not allocated dynamically),
 *  then free any image data bitplanes, and free the image structure itself.
 */

static void FreeImage(theImage)
struct Image *theImage;
{
   if (theImage != var(DefaultIcon) && theImage != var(DefaultScreenIcon))
   {
      if (theImage->ImageData) FreeRaster(theImage->ImageData,
         theImage->Width,theImage->Height*theImage->Depth);
      FREESTRUCT(Image,theImage);
   }
}


/*
 *  CleanUpDefaults()
 *
 *  Free any allocated memory, specifically, the NewCLI strings, the
 *  default images, and the ignored-screen title list.
 */

static void CleanUpDefaults()
{
   struct Ignore *nextIgnore;

   if (HiResCLICommand)     FREECHAR(HiResCLICommand);
   if (LoResCLICommand)     FREECHAR(LoResCLICommand);
   if (DefaultImage)        FreeImage(DefaultImage);
   if (DefaultSelect)       FreeImage(DefaultSelect);
   if (DefaultMask)         FreeImage(DefaultMask);
   if (DefaultScreenImage)  FreeImage(DefaultScreenImage);
   if (DefaultScreenSelect) FreeImage(DefaultScreenSelect);
   if (DefaultScreenMask)   FreeImage(DefaultScreenMask);
   while (IgnoreScreen)
   {
      nextIgnore = IgnoreScreen->Next;
      if (IgnoreScreen->Title) FREECHAR(IgnoreScreen->Title);
      FREESTRUCT(Ignore,IgnoreScreen);
      IgnoreScreen = nextIgnore;
   }
}


/*
 *  DoExit()
 *
 *  General purpose error-exit routine.  Print an error message if one was
 *  supplied (it can have up to three parameters), and then clean up any
 *  memory, libraries, etc. that need to be handled before exiting.
 */

void DoExit(s,x1,x2,x3)
char *s, *x1, *x2, *x3;
{
   long status = EXIT_OK;
   extern int UnSetVectors();
   extern int TellInputDevice();
   
   if (s != NULL)
   {
      printf(s,x1,x2,x3);
      printf("\n");
      status = EXIT_ERROR;
   }

   if (VectorsSet) if (!UnSetVectors())
      printf("Fatal Error:  Can't remove SetFunction Vectors!"),
      Segment = NULL;
   if (HandlerAdded)
   {
      HandlerAdded = FALSE;
      if (!TellInputDevice(IND_REMHANDLER))
         printf("Fatal Error:  Can't remove Input Handler!"),
         Segment = NULL;
   }

   if (HandlerTask)
   {
      Signal(HandlerTask,CANCELSIGNAL);
      Wait(OKSIGNAL| CANCELSIGNAL);
   }
   if (!AllOK)        CleanUpDefaults();
   if (Segment)       UnLoadSeg(Segment), printf("wIconify Removed\n");
   if (InputDevice)   CloseDevice(InputBlock);
   if (InputBlock)    DeleteStdIO(InputBlock);
   if (InputPort)     DeletePort(InputPort);
   if (IntuitionBase) CloseLibrary(IntuitionBase);
   if (GfxBase)       CloseLibrary(GfxBase);
   if (LayersBase)    CloseLibrary(LayersBase);
   exit(status);
}


/*
 *  CheckLibOpen()
 *
 *  Call OpenLibrary() for the specified library, and check that the 
 *  open succeeded.
 */

static void CheckLibOpen(lib,name,rev)
APTR *lib;
char *name;
int rev;
{
   extern APTR OpenLibrary();

   if ((*lib = OpenLibrary(name,(LONG)rev)) == NULL)
      DoExit("Can't open %s",name);
}


/*
 *  TellInputDevice()
 *
 *  Create a port and I/O block, then open the input device.  Set up the
 *  I/O block to add or remove the input handler, and send the request
 *  to the input device.  Finally, close the device and delete the
 *  I/O block and port.
 */
 
static int TellInputDevice(function)
int function;
{
   long status;
   extern struct MsgPort *CreatePort();
   extern struct IOStdReq *CreateStdIO();

   if ((InputPort = CreatePort(NULL,0)) == NULL) return(FALSE);
   if ((InputBlock = CreateStdIO(InputPort)) == NULL) return(FALSE);
   InputDevice = (OpenDevice("input.device",0,InputBlock,0) == 0);
   if (InputDevice == FALSE) return(FALSE);
   
   InputBlock->io_Command = (long) function;
   InputBlock->io_Data    = (APTR) var(Handler_Interrupt);
   if (status = DoIO(InputBlock)) return(FALSE);

   CloseDevice(InputBlock); InputDevice = FALSE;
   DeleteStdIO(InputBlock); InputBlock = NULL;
   DeletePort(InputPort);   InputPort = NULL;
   return(TRUE);
}


/*
 *  SetDefaults()
 *
 *  If the initialization file did not specify an iconify key or an
 *  activation key, set them to the defaults.  Set the default image
 *  If none was given.  Set the default HIRES command if none was
 *  provided.  Check the Image and Select image sizes to see that they
 *  match, and give a warning of not.
 */

static void SetDefaults()
{
   if (IconifyKey == 0)
   {
      IconifyKey = WICONIFYKEY;
      IconifyQuals = WQUALIFIERS;
      IconifyDisquals = 0;
   }
   if (ActivateKey == 0)
   {
      ActivateKey = WACTIVEKEY;
      ActivateQuals = WACTIVEQUAL;
   }
   if (DefaultImage == NULL)       DefaultImage = var(DefaultIcon);
   if (DefaultScreenImage == NULL) DefaultScreenImage = var(DefaultScreenIcon);
   if (HiResCLICommand == NULL)
   {
      if (NEWCHAR(HiResCLICommand,strlen(DEFAULTCOMMAND)))
         strcpy(HiResCLICommand,DEFAULTCOMMAND);
   }
   if (DefaultSelect)
   {
      if (DefaultImage->Width  != DefaultSelect->Width ||
          DefaultImage->Height != DefaultSelect->Height)
        printf("Warning: DEFAULT_IMAGE and DEFAULT_SELECT sizes don't match\n");
   }
   if (DefaultScreenSelect)
   {
      if (DefaultScreenImage->Width  != DefaultScreenSelect->Width ||
          DefaultScreenImage->Height != DefaultScreenSelect->Height)
        printf("Warning:  SCREEN_IMAGE and SCREEN_SELECT sizes don't match\n");
   }
   if (DefaultMask)
   {
      if (DefaultImage->Width  != DefaultMask->Width ||
          DefaultImage->Height != DefaultMask->Height)
      {
         printf("Error:  DEFAULT_IMAGE and DEFAULT_MASK sizes don't match\n");
         FreeImage(DefaultMask); DefaultMask = NULL;
      }
   }
   if (DefaultScreenMask)
   {
      if (DefaultScreenImage->Width  != DefaultScreenMask->Width ||
          DefaultScreenImage->Height != DefaultScreenMask->Height)
      {
         printf("Error:  SCREEN_IMAGE and SCREEN_MASK sizes don't match\n");
         FreeImage(DefaultScreenMask); DefaultScreenMask = NULL;
      }
   }
   if (StackSize == 0) StackSize = 8K; else
   if (StackSize < 2K) StackSize = 2K;
   var(Handler_Interrupt)->is_Node.ln_Pri = HandlerPriority;
}



/*
 *  SetVectors()
 *
 *  Set the Intuition library vectors for the Intuition functions
 *  to the routines specified by the handler.  Save the old routine
 *  pointers for later replacement.
 */

static void SetVectors()
{
   VAR(OldOpenWindow)      = vSETFUNC(LVOOpenWindow,aOpenWindow);
   VAR(OldCloseWindow)     = vSETFUNC(LVOCloseWindow,aCloseWindow);
   VAR(OldOpenScreen)      = vSETFUNC(LVOOpenScreen,aOpenScreen);
   VAR(OldCloseScreen)     = vSETFUNC(LVOCloseScreen,aCloseScreen);
   VAR(OldSetWindowTitles) = vSETFUNC(LVOSetWindowTitles,aSetWindowTitles);
   VAR(OldWindowToFront)   = vSETFUNC(LVOWindowToFront,aWindowToFront);
   VAR(OldWindowToBack)    = vSETFUNC(LVOWindowToBack,aWindowToBack);
   VAR(OldActivateWindow)  = vSETFUNC(LVOActivateWindow,aActivateWindow);
   VAR(OldBuildSysRequest) = vSETFUNC(LVOBuildSysRequest,aBuildSysRequest);
   VAR(OldFreeSysRequest)  = vSETFUNC(LVOFreeSysRequest,aFreeSysRequest);
   VAR(OldAutoRequest)     = vSETFUNC(LVOAutoRequest,aAutoRequest);
   VectorsSet = TRUE;
}


/*
 *  UnSetVectors()
 *
 *  Replace the old Intuition library vectors, but make sure that no one
 *  else has changed them behind our back.  If they are not the same as
 *  what we set them to originally, then put back the ones that we found,
 *  and return an error status.
 */

static int UnSetVectors()
{
   long NewOpenWindow,NewCloseWindow;
   long NewOpenScreen,NewCloseScreen;
   long NewSetWindowTitles;
   long NewWindowToFront,NewWindowToBack,NewActivateWindow;
   long NewBuildSysRequest,NewFreeSysRequest,NewAutoRequest;
   int status = TRUE;
 
   NewOpenWindow      = VSETFUNC(LVOOpenWindow,OldOpenWindow);
   NewCloseWindow     = VSETFUNC(LVOCloseWindow,OldCloseWindow);
   NewOpenScreen      = VSETFUNC(LVOOpenScreen,OldOpenScreen);
   NewCloseScreen     = VSETFUNC(LVOCloseScreen,OldCloseScreen);
   NewSetWindowTitles = VSETFUNC(LVOSetWindowTitles,OldSetWindowTitles);
   NewWindowToFront   = VSETFUNC(LVOWindowToFront,OldWindowToFront);
   NewWindowToBack    = VSETFUNC(LVOWindowToBack,OldWindowToBack);
   NewActivateWindow  = VSETFUNC(LVOActivateWindow,OldActivateWindow);
   NewBuildSysRequest = VSETFUNC(LVOBuildSysRequest,OldBuildSysRequest);
   NewFreeSysRequest  = VSETFUNC(LVOFreeSysRequest,OldFreeSysRequest);
   NewAutoRequest     = VSETFUNC(LVOAutoRequest,OldAutoRequest);

   if (NewOpenWindow      != (long) var(aOpenWindow)      ||
       NewCloseWindow     != (long) var(aCloseWindow)     ||
       NewOpenScreen      != (long) var(aOpenScreen)      ||
       NewCloseScreen     != (long) var(aCloseScreen)     ||
       NewSetWindowTitles != (long) var(aSetWindowTitles) ||
       NewWindowToFront   != (long) var(aWindowToFront)   ||
       NewWindowToBack    != (long) var(aWindowToBack)    ||
       NewActivateWindow  != (long) var(aActivateWindow)  ||
       NewBuildSysRequest != (long) var(aBuildSysRequest) ||
       NewFreeSysRequest  != (long) var(aFreeSysRequest)  ||
       NewAutoRequest     != (long) var(aAutoRequest))
   {
      SetFunction(IntuitionBase,&LVOOpenWindow,NewOpenWindow);
      SetFunction(IntuitionBase,&LVOCloseWindow,NewCloseWindow);
      SetFunction(IntuitionBase,&LVOOpenScreen,NewOpenScreen);
      SetFunction(IntuitionBase,&LVOCloseScreen,NewCloseScreen);
      SetFunction(IntuitionBase,&LVOSetWindowTitles,NewSetWindowTitles);
      SetFunction(IntuitionBase,&LVOWindowToFront,NewWindowToFront);
      SetFunction(IntuitionBase,&LVOWindowToBack,NewWindowToBack);
      SetFunction(IntuitionBase,&LVOActivateWindow,NewActivateWindow);
      SetFunction(IntuitionBase,&LVOBuildSysRequest,NewBuildSysRequest);
      SetFunction(IntuitionBase,&LVOFreeSysRequest,NewFreeSysRequest);
      SetFunction(IntuitionBase,&LVOAutoRequest,NewAutoRequest);
      VectorsSet = status = FALSE;
   }
   return(status);
}


/*
 *  GetVariables()
 *
 *  Get copies of the Handler variables that the loader will need during
 *  the setup process.
 */

static void GetVariables()
{
   wMenuBar = var(wMenu);
   OpenWindowMenu = var(OpenWindowMenu);
   ScreenColors = var(Colors);
}


/*
 *  SetVariables()
 *
 *  Once the loader has does its initialization, set the variables
 *  required by the handler.
 */

static void SetVariables()
{
   VAR(IntuitionBase)       = IntuitionBase;
   VAR(GfxBase)             = GfxBase;
   VAR(LayersBase)          = LayersBase;
   VAR(SysBase)             = SysBase;
   VAR(DOSBase)             = DOSBase;
   VAR(HiResCLICommand)     = HiResCLICommand;
   VAR(LoResCLICommand)     = LoResCLICommand;
   VAR(StackSize)           = StackSize;
   VAR(DefaultImage)        = DefaultImage;
   VAR(DefaultSelect)       = DefaultSelect;
   VAR(DefaultMask)         = DefaultMask;
   VAR(DefaultScreenImage)  = DefaultScreenImage;
   VAR(DefaultScreenSelect) = DefaultScreenSelect;
   VAR(DefaultScreenMask)   = DefaultScreenMask;
   VAR(DefaultFlags)        = DefaultFlags;
   VAR(DefaultScreenFlags)  = DefaultScreenFlags;
   VAR(IgnoreScreen)        = IgnoreScreen;
   VAR(IconifyKey)          = IconifyKey;
   VAR(ActivateKey)         = ActivateKey;
   VAR(IconifyQuals)        = IconifyQuals;
   VAR(IconifyDisquals)     = IconifyDisquals;
   VAR(IconifyChange)       = IconifyChange;
   VAR(ActivateQuals)       = ActivateQuals;
   SetWindowMenu(ScreenType,AutoResize);
}


/*
 *  GetIconifyVars()
 *
 *  When it comes time to remove the handler, recover the initialized
 *  data from the HandlerData structure, and set the flags so that cleanup
 *  will proceed properly.
 */

static void GetIconifyVars()
{
   IntuitionBase       = VAR(IntuitionBase);
   GfxBase             = VAR(GfxBase);
   LayersBase          = VAR(LayersBase);
   HiResCLICommand     = VAR(HiResCLICommand);
   LoResCLICommand     = VAR(LoResCLICommand);
   DefaultImage        = VAR(DefaultImage);
   DefaultSelect       = VAR(DefaultSelect);
   DefaultMask         = VAR(DefaultMask);
   DefaultScreenImage  = VAR(DefaultScreenImage);
   DefaultScreenSelect = VAR(DefaultScreenSelect);
   DefaultScreenMask   = VAR(DefaultScreenMask);
   IgnoreScreen        = VAR(IgnoreScreen);
   Segment             = var(Segment);
   VectorsSet          = TRUE;
   HandlerAdded        = TRUE;
   AllOK               = FALSE;
   HandlerTask         = NULL;
}


/*
 *  LoadIconify()
 *
 *  Attempt to load the handler code (try different directories if not found).
 *  Call the handler's setup routine and get the HandlerData pointer.
 *  Check the version of the handler to be sure it's OK to use with this 
 *  loader.  Set the Segment and ParentTask pointer of the HandlerData.
 */

static void LoadIconify()
{
   struct HandlerData *(*Setup)();

   if ((Segment = LoadSeg(HANDLER)) == NULL)
      if ((Segment = LoadSeg(handler)) == NULL)
         DoExit("Can't load %s",handler);
   Setup = (struct HandlerData *(*)()) ((Segment << 2) + 4);
   HandlerData = (*Setup)(MAJLOADVERS,MINLOADVERS);
   if (HandlerData)
   {
      if (var(MajVers) < MAJICONVERS ||
         (var(MajVers) == MAJICONVERS && var(MinVers) < MINICONVERS))
             DoExit("Version mismatch with %s",HANDLER);
   } else {
      DoExit("%s reports a version mismatch",HANDLER);
   }
   var(Segment)    = Segment;
   var(ParentTask) = FindTask(NULL);
}


/*
 *  CreateIconify()
 *
 *  Once the handler is loader, attempt to create a process from it.
 *  Get a pointer to the handler process, and clear its console task
 *    since inheriting this pointer can cause errors in the NewCLI command.
 *    (this is a kludge, and should really be done by CreateProc()).
 *  Wait for the handler to signal that it is ready to go, or for a user
 *    initiated cancel.
 */

static void CreateIconify()
{
   ULONG Signal;
   int Pri = IconifyPriority;
   static char *HandlerName = " wIconify-Handler ";

   if (CreateProc(HandlerName,Pri,Segment,STACKSIZE) == NULL)
      DoExit("Can't create wIconify-Handler process");
   HandlerTask = FindTask(HandlerName);
   if (HandlerTask == NULL) DoExit("Can't Find Handler Task");
   HANDLERPROC->pr_ConsoleTask = NULL;
   Signal = Wait(OKSIGNAL| CANCELSIGNAL);
   if (Signal & CANCELSIGNAL)
      DoExit("wIconify-Handler can't be initialized");
}


/*
 *  ActivateIconify()
 *
 *  Signal the handler that it can proceed, and set the flags so that
 *  DoExit() knows that everything went smoothly (i.e., so that it will
 *  not free the allocated memory, etc).
 */

static void ActivateIconify()
{
   Signal(HandlerTask,OKSIGNAL);
   HandlerTask = NULL; Segment = NULL;
   HandlerAdded = FALSE; VectorsSet = FALSE;
   IntuitionBase = NULL;
   GfxBase = NULL;
   LayersBase = NULL;
   AllOK = TRUE;
}


/*
 *  SetupScreens()
 *
 *  Look through the intuition list of screens and call the handler's
 *  OpenScreen code for each one.  This causes each screen to be processed
 *  by the handler as though it were just openned, hence it will get a
 *  backdrop wIconify window, etc.
 */

static void SetupScreens()
{
   struct Screen *theScreen;
   void (*cOpenScreen)() = var(cOpenScreen);

   Forbid();
   theScreen = IntuitionBase->FirstScreen;
   while (theScreen)
   {
      (*cOpenScreen)(theScreen);
      theScreen = theScreen->NextScreen;
   }
   Permit();
}


/*
 *  main()
 *
 *  if wIconify is already running, then
 *    Attempt to end wIconify.
 *    If contact was made, wait for wIconify to confirm that it is done.
 *    If the user cancelled the wait, print a message,
 *    Otherwise, get the initialized variables for clean up
 *  Otherwise, wIconify is not already running, so
 *    Check if the program was called correctly
 *    Load the handler code,
 *    Get the variables needed for setup
 *    Open the libraries
 *    Read the init file, if any
 *    Set the default values for anything not defined in the file
 *    Set the variables to their initialized values
 *    Create the iconify task
 *    Have the handler process all the existing screens
 *    Add the Input Device handler and set the function traps
 *    Report that wIconify is installed.
 *  Exit with clean up
 */

void main(argc,argv)
int argc;
char **argv;
{
   ULONG Signals;
   extern struct HandlerData *wEndIconify();

   if (wIconifyActive())
   {
      HandlerData = wEndIconify();
      if (HandlerData == NULL) DoExit("Can't get HandlerData from Handler");
      printf("Requesting wIconify to stop...");
      Signals = Wait(OKSIGNAL| CANCELSIGNAL);
      if ((Signals & CANCELSIGNAL) == FALSE)
         GetIconifyVars(), printf("\n");
        else
         printf("[Cancelled]\n");
   } else {
      if (argc > 2) DoExit("Usage:  '%s'",USAGE);
      LoadIconify();
      GetVariables();
      CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV);
      CheckLibOpen(&GfxBase,"graphics.library",GRAPHICS_REV);
      CheckLibOpen(&LayersBase,"layers.library",LAYERS_REV);
      if (argc == 2) ReadInitFile(argv[1],NULL);
         else ReadInitFile(INITFILENAME1,INITFILENAME2);
      SetDefaults();
      SetVariables();
      CreateIconify();
      SetupScreens();
      if (TellInputDevice(IND_ADDHANDLER)) HandlerAdded = TRUE;
        else DoExit("Can't add Input Handler");
      SetVectors();
      ActivateIconify();
      printf("%s v%d.%d.%d installed\n",
         program,var(MajVers),var(MinVers),MAJLOADVERS);
   }
   DoExit(NULL);
}
