#include <exec/types.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <dos/dos.h>
#include <dos/dostags.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <intuition/gadgetclass.h>
#include <intuition/sghooks.h>
#include <intuition/imageclass.h>
#include <libraries/gadtools.h>
#include <libraries/diskfont.h>
#include <libraries/commodities.h>
#include <libraries/locale.h>
#include <libraries/asl.h>
#include <libraries/altclass.h>
#include <workbench/workbench.h>
#include <workbench/startup.h>

#include <string.h>
#include <stdlib.h>
#include <clib/alib_protos.h>
#include <clib/icon_protos.h>
#include <clib/graphics_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/exec_protos.h>
#include <clib/commodities_protos.h>
#include <clib/locale_protos.h>
#include <clib/wb_protos.h>
#include <clib/diskfont_protos.h>
#include <clib/utility_protos.h>
#include <clib/asl_protos.h>
#include <clib/keymap_protos.h>

#define VERSION "1.1"

UBYTE *ver="\0$VER: CommandList "VERSION" ("__COMMODORE_DATE__")";

/* Locale stuff */

struct Library *LocaleBase;
struct Locale *locale;
struct Catalog *catalog;

#define CATCOMP_BLOCK
#define CATCOMP_NUMBERS
#include "CommandList_locale.h"
#undef CATCOMP_BLOCK

/* slightly modified version of getString() generated by catcomp */

char *getString(ULONG MsgID)
{
LONG   *l;
UWORD  *w;
char *builtIn;

   l = (LONG *)CatCompBlock;

   while (*l != MsgID )
   {
           w = (UWORD *)((ULONG)l + 4);
           l = (LONG *)((ULONG)l + (ULONG)*w + 6);
   }
   builtIn = (char *)((ULONG)l + 6);
   if (LocaleBase)
           return (GetCatalogStr(catalog, MsgID, builtIn));
   return(builtIn);
}


/* Commodity stuff */

struct NewBroker newbroker = {    NB_VERSION,
                                  "CommandList", /* string to identify this broker */
                                  "CommandList "VERSION" ("__COMMODORE_DATE__")",
                                  "", /* description set later */
                                  NBU_UNIQUE | NBU_NOTIFY,
                                  COF_SHOW_HIDE,
                                  0,
                                  NULL,
                                  0
};

struct Library *CxBase;
CxObj *broker;

#define POPKEY_EVENT 4711


/* MainWindow stuff */

struct NewMenu MainWindowNewMenus[12];
struct Menu *MainWindowMenus;

struct Window *MainWindow;
struct Gadget *glist;
struct Gadget *listviewgad;
APTR vi;

ULONG MainWindowMinWidth;
ULONG MainWindowMinHeight;
ULONG InnerHeight;
ULONG InnerWidth;
ULONG ListViewHeight;
ULONG XOff,YOff;

struct NewGadget gadgets[1];

/* Config stuff */

struct Window *CfgWindow;
struct AppWindow *appwindow;
struct Gadget *cfgglist;
struct TextFont *textfont;
struct FileInfoBlock *cfgfib;
ULONG CfgWindowMinHeight,CfgWindowMinWidth;
Class *altclass;
APTR getfileimg;

LONG cfglastitem;
struct MyNode *cfglastnode;

/* Raw */

#define ESC      69
#define TAB      66
#define ENTER    67
#define RETURN   68

#define NUMPAD_1  0x1d
#define NUMPAD_7  0x3d
#define NUMPAD_2  0x1e
#define NUMPAD_8  0x3e
#define NUMPAD_3  0x1f
#define NUMPAD_9  0x3f

#define QUAL_SHIFT (IEQUALIFIER_RSHIFT|IEQUALIFIER_LSHIFT)


/* WindowPtr */

struct Window *windowptr;
struct Process *myproc;


/* PubScreen */

UBYTE *PubScreenName;
struct Screen *PubScreen;


/* Libraries */

extern struct ExecBase *SysBase;
extern struct IntuitionBase *IntuitionBase;
extern struct Library *GadToolsBase;
extern struct Library *DOSBase;
struct Library *KeymapBase;

/* Config */

UBYTE cfg_Settings[100]="PROGDIR:CommandList.prefs";

ULONG cfg_InnerWidth=100;
ULONG cfg_Lines=10;
ULONG cfg_CfgInnerWidth=100;
ULONG cfg_CfgLines=5;
UBYTE cfg_Popkey[50]="alt tab";
BOOL cfg_Popup=FALSE;
LONG lastitem;

struct List CommandList;
ULONG maxlist;

struct MyNode
{
   struct Node Node;
   UBYTE Type;
   ULONG Stack;
   UBYTE Name[40];
   UBYTE Hotkey[40];
   UBYTE Command[200];
   CxObj *cx;
};


/* CLI arguments */

#define CX_POPUP    0
#define CX_POPKEY   1
#define CX_PRIORITY 2
#define SETTINGS    3

UBYTE *argstr="CX_POPUP/S,CX_POPKEY/K,CX_PRIORITY/K/N,SETTINGS/K";
ULONG argarray[4]={NULL,NULL,NULL,NULL};

struct RDArgs *rdargs;


/* Workbench args */

void _waitwbmsg(void);
routine_that_is_never_called() { _waitwbmsg(); }
extern struct WBStartup *_WBMsg;

#define WORKBENCH 1
#define CLI 2

ULONG wbapps;
struct MsgPort *WBReplyPort;
struct MsgPort *WBAppPort;
struct AddMenuItem *appmenuitem;

ULONG cxsigflag,wbsigflag,wbappsigflag;

/* Requester */

struct EasyStruct es = { sizeof(struct EasyStruct),
                         0,
                         "",
                         "",
                         ""  };

BOOL OpenAsl(UBYTE *file,UBYTE *title,BOOL save);
UBYTE asl_buf[300];

/* String EditHook */

#define IEQUALIFIER_SHIFT     (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)

__asm __geta4 ULONG StrEditHookEntry (register __a0 struct Hook *hook,register __a2 struct SGWork *sgw,register __a1 ULONG *msg)
{
   int qual,rawcode;

   if (msg[0] == SGH_KEY)
   {
      rawcode = sgw->IEvent->ie_Code;
      qual = sgw->IEvent->ie_Qualifier;
      if (sgw->EditOp == EO_INSERTCHAR   || sgw->EditOp == EO_REPLACECHAR  || sgw->EditOp == EO_BADFORMAT    ||
         (sgw->EditOp == EO_NOOP && sgw->Actions == (SGA_USE|SGA_BEEP) && sgw->NumChars == (sgw->StringInfo->MaxChars - 1)))
      {
         if ((qual & IEQUALIFIER_RCOMMAND) || sgw->Code == 27)
         {
            sgw->Actions &= ~(SGA_USE|SGA_BEEP|SGA_REDISPLAY);
            sgw->IEvent->ie_Qualifier &= ~IEQUALIFIER_RCOMMAND;

            if (!(qual & IEQUALIFIER_REPEAT))
            {
               sgw->Actions |= SGA_REUSE|SGA_END;
               /* sgw->Code = KEYB_SHORTCUT; */
            }
         }
      }
      return (TRUE);
   }
   return (FALSE);
}

struct Hook stredithook = { { NULL }, StrEditHookEntry, NULL, NULL };

/* Protos */

void UnLockWindow(struct Window *win);
BOOL LockWindow(struct Window *win);
void Config(void);
void Popup(void);
void CleanUpCfg(void);
BOOL MayExit(void);
void HandleCx(void);
BOOL FakePress(struct Gadget *gad,struct Window *win,UBYTE rawcode);
void CreateHotkeys(void);
void RemoveHotkeys(void);
BOOL LaunchCommand(struct MyNode *mynode);

/* Clean up basic stuff */

void CleanUp(int err)
{
   struct MyNode *mynode;
   struct AppMessage *appmsg;

   if(KeymapBase)
      CloseLibrary(KeymapBase);

   if(WBReplyPort)
      DeleteMsgPort(WBReplyPort);

   if(appmenuitem)
      RemoveAppMenuItem(appmenuitem);

   if(WBAppPort)
   {
      while(appmsg=(struct AppMessage *)GetMsg(WBAppPort))
         ReplyMsg((struct Message *)appmsg);

      DeleteMsgPort(WBAppPort);
   }

   if(broker)
      DeleteCxObjAll(broker);

   if(newbroker.nb_Port)
      DeleteMsgPort(newbroker.nb_Port);

   if(CxBase)
      CloseLibrary(CxBase);

   if(catalog)
      CloseCatalog(catalog);

   if(locale)
      CloseLocale(locale);

   if(LocaleBase)
      CloseLibrary(LocaleBase);

   if(rdargs)
      FreeArgs(rdargs);

   while(mynode=(struct MyNode *)RemHead(&CommandList))
      FreeMem(mynode,sizeof(struct MyNode));

   _exit(err);
}

/* Clean up main window */

void CleanUpMain(void)
{
   myproc->pr_WindowPtr=windowptr;

   if(textfont) CloseFont(textfont);

   if(MainWindowMenus)
   {
		ClearMenuStrip(MainWindow);
		FreeMenus(MainWindowMenus);
   }

   if(MainWindow)
   {
      if(MainWindow->FirstRequest)
         UnLockWindow(MainWindow);

      CloseWindow(MainWindow);
   }

   if(glist)      FreeGadgets(glist);
   if(vi)         FreeVisualInfo(vi);
   if(PubScreen)  UnlockPubScreen(NULL,PubScreen);

   textfont=NULL;
   MainWindowMenus=NULL;
   PubScreen=NULL;
   MainWindow=NULL;
   glist=NULL;
   vi=NULL;
}


/* Load/save configuration */

void LoadConfig(UBYTE *file)
{
   BPTR fh;
   UBYTE buf[200],buf2[250],buf3[250];
   struct MyNode *mynode;
   ULONG c;

   maxlist=0;

   if(!(fh=Open(file,MODE_OLDFILE)))
   {
      es.es_Title=getString(REQ_ERRTITLE_STR);
      es.es_TextFormat=getString(ERR_READ_SETTINGS_STR);
      es.es_GadgetFormat=getString(REQ_PROCEED_STR);

      if(MainWindow)
         LockWindow(MainWindow);

      EasyRequest(NULL,&es,NULL,file);

      if(MainWindow)
         UnLockWindow(MainWindow);

      return;
   }

   while(FGets(fh,buf,199))
   {
      if(buf[0]!=0)
         buf[strlen(buf)-1]=0;

      if(strcmp(buf,"END")==0)
         break;

      if(strncmp(buf,"WIDTH",5)==0)
         cfg_InnerWidth=atoi(&buf[6]);

      if(strncmp(buf,"LINES",5)==0)
         cfg_Lines=atoi(&buf[6]);

      if(strncmp(buf,"CFGWIDTH",8)==0)
         cfg_CfgInnerWidth=atoi(&buf[9]);

      if(strncmp(buf,"CFGLINES",8)==0)
         cfg_CfgLines=atoi(&buf[9]);
   }

   while(FGets(fh,buf,199))
   {
      FGets(fh,buf2,249);
      buf3[0]=0;

      if(buf2[0]==':')
      {
         strcpy(buf3,&buf2[1]);
         FGets(fh,buf2,249);
      }

      if(buf[0]!=0)
         buf[strlen(buf)-1]=0;

      if(buf2[0]!=0)
         buf2[strlen(buf2)-1]=0;

      if(buf3[0]!=0)
         buf3[strlen(buf3)-1]=0;

      if(!(mynode=AllocMem(sizeof(struct MyNode),MEMF_CLEAR)))
         CleanUpMain();

      if(strncmp(buf2,"WB:",3)==0)
      {
         mynode->Type=WORKBENCH;
         c=3;
         mynode->Stack=4000;
      }
      else
      {
         mynode->Type=CLI;

         for(c=0;c<strlen(buf2);c++)
            if(buf2[c]==':') break;

         buf2[c]=0;
         mynode->Stack=atoi(buf2);

         if(mynode->Stack==0)
            mynode->Stack=4000;

         c++;
      }

      strcpy(mynode->Name,buf);
      strcpy(mynode->Command,&buf2[c]);
      strcpy(mynode->Hotkey,buf3);
      mynode->Node.ln_Name=mynode->Name;

      AddTail(&CommandList,(struct Node *)mynode);
      maxlist++;
   }
   Close(fh);
}

void SaveConfig(UBYTE *file)
{
   BPTR fh;
   struct MyNode *mynode;
   ULONG c;

   if(!(fh=Open(file,MODE_NEWFILE)))
   {
      es.es_Title=getString(REQ_ERRTITLE_STR);
      es.es_TextFormat=getString(ERR_SAVE_SETTINGS_STR);
      es.es_GadgetFormat=getString(REQ_PROCEED_STR);

      if(MainWindow)
         LockWindow(MainWindow);

      EasyRequest(NULL,&es,NULL,file);

      if(MainWindow)
         UnLockWindow(MainWindow);

      return;
   }

   FPrintf(fh,"WIDTH %lu\n",cfg_InnerWidth);
   FPrintf(fh,"LINES %lu\n",cfg_Lines);
   FPrintf(fh,"CFGWIDTH %lu\n",cfg_CfgInnerWidth);
   FPrintf(fh,"CFGLINES %lu\n",cfg_CfgLines);
   FPuts(fh,"END\n");

   mynode=(struct MyNode *)CommandList.lh_Head;

   for(c=0;c<maxlist;c++)
   {
      FPrintf(fh,"%s\n",mynode->Name);

      if(mynode->Hotkey[0])
         FPrintf(fh,":%s\n",mynode->Hotkey);

      if(mynode->Type==WORKBENCH)
         FPrintf(fh,"WB:%s\n",mynode->Command);

      else
         FPrintf(fh,"%lu:%s\n",mynode->Stack,mynode->Command);

      mynode=(struct MyNode *)mynode->Node.ln_Succ;
   }

   Close(fh);
}

/* Commodity handling */

void Appear(void)
{
   if(CfgWindow)
   {
      ScreenToFront(PubScreen);
      WindowToFront(CfgWindow);
      ActivateWindow(CfgWindow);
   }
   else if(MainWindow)
   {
      ScreenToFront(PubScreen);
      WindowToFront(MainWindow);
      ActivateWindow(MainWindow);
   }
   else
   {
      Popup();
   }
}

void HandleCx(void)
{
   ULONG msgid,msgtype,c;
   struct MyNode *mynode;
   CxMsg *msg;

   while(msg = (CxMsg *)GetMsg(newbroker.nb_Port))
   {
      msgid = CxMsgID(msg);
      msgtype = CxMsgType(msg);
      ReplyMsg((struct Message *)msg);

      switch(msgtype)
      {
         case CXM_IEVENT:  if(msgid == POPKEY_EVENT)
                           {
                              Appear();
                           }
                           else if(msgid>0 && msgid<=maxlist)
                           {
                              msgid--;

                              mynode=CommandList.lh_Head;

                              for(c=0;c<msgid;c++)
                                 mynode=mynode->Node.ln_Succ;

                              LaunchCommand(mynode);
                           }
                           break;

         case CXM_COMMAND: switch(msgid)
                           {
                              case CXCMD_UNIQUE:
                              case CXCMD_APPEAR:    Appear();
                                                    break;
                              case CXCMD_DISAPPEAR: if(CfgWindow)  CleanUpCfg();
                                                    if(MainWindow) CleanUpMain();
                                                    return;
                              case CXCMD_DISABLE:   ActivateCxObj(broker,0);
                                                    break;
                              case CXCMD_ENABLE:    ActivateCxObj(broker,1);
                                                    break;
                              case CXCMD_KILL:      if(MayExit())
                                                    {
                                                       if(CfgWindow)  CleanUpCfg();
                                                       if(MainWindow) CleanUpMain();
                                                       CleanUp(0);
                                                    }
                                                    break;
                           }
      }
   }
}

/***** Launching of CLI and Workbench commands ******/

BOOL LaunchCommand(struct MyNode *mynode)
{
   UBYTE *screenname;
   struct Screen *s;
   ULONG lock;
   struct PubScreenNode *psnode;

   lock = LockIBase(0);
   s=IntuitionBase->FirstScreen;
   UnlockIBase(lock);

   screenname=NULL;
   if(s->Flags & WBENCHSCREEN)
   {
      screenname="Workbench";
   }
   else
   {
      if(s->Flags & PUBLICSCREEN)
      {
         /* s is a public screen so find its name */

         psnode=(struct PubScreenNode *)LockPubScreenList();

         while ((psnode) && !(screenname))
         {
            if((psnode->psn_Flags != PSNF_PRIVATE) && (psnode->psn_Screen == s))
            {
               /* found it */
               screenname = psnode->psn_Node.ln_Name;
            }
            else
            {
               /* check next one */
               psnode = (struct PubScreenNode *)psnode->psn_Node.ln_Succ;
            }
         }
         UnlockPubScreenList();
      }
   }

   if(mynode->Type==WORKBENCH)
   {
      struct WBStartup *wbst;
      BPTR segment,dirlock;
      struct MsgPort *procport;
      struct WBArg *wba;
      char *app_name,*what;
      UBYTE name[200];
      struct DiskObject *dobj;
      ULONG stack;
      BYTE pri;

      if(!(dobj=GetDiskObject(mynode->Command)))
      {
         es.es_Title=getString(REQ_ERRTITLE_STR);
         es.es_TextFormat=getString(ERR_LAUNCH_NOICON_STR);
         es.es_GadgetFormat=getString(REQ_PROCEED_STR);
         LockWindow(MainWindow);
         EasyRequest(NULL,&es,NULL,mynode->Command);
         UnLockWindow(MainWindow);
         return(FALSE);
      }

      stack=0;
      pri=0;

      if(dobj->do_Type==WBTOOL)
      {
         stack=dobj->do_StackSize;

         if(stack==0)
            stack=4096;

         if(what=FindToolType(dobj->do_ToolTypes,"TOOLPRI"))
            pri=atoi(what);
      }
      FreeDiskObject(dobj);

      strcpy(name,mynode->Command);
      *PathPart(name) = '\0'; /* get directory name: V36 and up only! */

      if(!(dirlock=Lock(name,SHARED_LOCK)))
      {
         es.es_Title=getString(REQ_ERRTITLE_STR);
         es.es_TextFormat=getString(ERR_LAUNCH_NODIR_STR);
         es.es_GadgetFormat=getString(REQ_PROCEED_STR);
         LockWindow(MainWindow);
         EasyRequest(NULL,&es,NULL,name);
         UnLockWindow(MainWindow);
         return(FALSE);
      }

      if(!(wbst=( struct WBStartup * )AllocMem( sizeof( struct WBStartup ), MEMF_CLEAR)))
      {
         DisplayBeep(NULL);
         UnLock(dirlock);
         return(FALSE);
      }

      if(!(segment=LoadSeg(mynode->Command)))
      {
         UnLock(dirlock);
         FreeMem(wbst,sizeof( struct WBStartup));
         es.es_Title=getString(REQ_ERRTITLE_STR);
         es.es_TextFormat=getString(ERR_LAUNCH_NOTFOUND_STR);
         es.es_GadgetFormat=getString(REQ_PROCEED_STR);
         LockWindow(MainWindow);
         EasyRequest(NULL,&es,NULL,mynode->Command);
         UnLockWindow(MainWindow);
         return(FALSE);
      }

      if(!(wba=(struct WBArg *)AllocMem(sizeof(struct WBArg),MEMF_CLEAR )))
      {
         UnLock(dirlock);
         UnLoadSeg(segment );
         FreeMem(wbst,sizeof(struct WBStartup));
         DisplayBeep(NULL);
         return(FALSE);
      }

      app_name=FilePart(mynode->Command);  /* V36 and above only! */

      Forbid();
      if(!(procport=(struct MsgPort *)CreateProc(app_name,pri,segment,stack)))
      {
         Permit();
         UnLoadSeg(segment);
         FreeMem( wbst, sizeof( struct WBStartup ) );
         UnLock(dirlock);
         es.es_Title=getString(REQ_ERRTITLE_STR);
         es.es_TextFormat=getString(ERR_LAUNCH_CREATEPROC_STR);
         es.es_GadgetFormat=getString(REQ_PROCEED_STR);
         LockWindow(MainWindow);
         EasyRequest(NULL,&es,NULL,NULL);
         UnLockWindow(MainWindow);
         return(FALSE);
      }

      ((struct Process *)procport->mp_SigTask)->pr_HomeDir=dirlock;
      ((struct Process *)procport->mp_SigTask)->pr_WindowPtr=NULL;
      ((struct Process *)procport->mp_SigTask)->pr_ConsoleTask=NULL;
      Permit();

      wba -> wa_Lock = dirlock;
      wba -> wa_Name = app_name;   /* application name (same as in CreateProc()) */

      wbst -> sm_Message.mn_ReplyPort = WBReplyPort;  /* main() must supply a MsgPort! */
      wbst -> sm_Message.mn_Length = sizeof( struct WBStartup );
      wbst -> sm_Process = procport;
      wbst -> sm_Segment = segment;
      wbst -> sm_NumArgs = 1;
      wbst -> sm_ArgList = wba;
      wbst -> sm_ToolWindow = NULL;

      PutMsg(procport,(struct Message * )wbst);
      wbapps++;
   }
   else
   {
      ULONG c,d;
      UBYTE conspec[200];
      UBYTE command[512];
      UBYTE *cmd;
      BPTR winfh;

      cmd=mynode->Command;

      d=0;
      for(c=0;c<strlen(cmd);c++)
      {
         if(cmd[c]=='%' && (cmd[c+1]|32)=='s')
         {
            strcpy(&command[d],screenname);
            d+=strlen(screenname);
            c++;
         }
         else command[d++]=cmd[c];
      }
      command[d]=0;

      strcpy(conspec,"CON:0/25//150/");
      strcat(conspec,getString(CON_TITLE_STR));
      strcat(conspec,"/AUTO/WAIT/SCREEN");
      strcat(conspec,screenname);

      if(winfh=Open(conspec,MODE_READWRITE))
      {
         SystemTags(command,SYS_Input,winfh,
                            SYS_Output,NULL,
                            SYS_Asynch,TRUE,
                            SYS_UserShell, TRUE,
                            NP_StackSize,mynode->Stack,
                            TAG_END);
      }
   }
   return(TRUE);
}

void ProcessWorkbench(void)
{
   struct WBStartup *wbst;

   while(wbst=(struct WBStartup *)GetMsg(WBReplyPort))
   {
      wbapps--;

      if(wbst->sm_Segment)
         UnLoadSeg(wbst->sm_Segment);

      if(wbst->sm_ArgList)
      {
         if(wbst->sm_ArgList->wa_Lock)
            UnLock(wbst->sm_ArgList->wa_Lock);
      }
      FreeMem(wbst->sm_ArgList,sizeof(struct WBArg));
      FreeMem(wbst,sizeof(struct WBStartup));
   }
}

void RemoveHotkeys(void)
{
   struct MyNode *mynode;
   int c;

   mynode=(struct MyNode *)CommandList.lh_Head;

   for(c=0;c<maxlist;c++)
   {
      if(mynode->cx)
      {
         DeleteCxObj(mynode->cx);
         mynode->cx=NULL;
      }
      mynode=(struct MyNode *)mynode->Node.ln_Succ;
   }
}

void CreateHotkeys(void)
{
   struct MyNode *mynode;
   int c;

   mynode=(struct MyNode *)CommandList.lh_Head;

   for(c=0;c<maxlist;c++)
   {
      if(mynode->Hotkey[0])
      {
         if(!(mynode->cx = HotKey(mynode->Hotkey,newbroker.nb_Port,c+1)))
         {
            es.es_Title=getString(REQ_ERRTITLE_STR);
            es.es_TextFormat=getString(ERR_INVALID_ITEM_HOTKEY_STR);
            es.es_GadgetFormat=getString(REQ_PROCEED_STR);

            if(MainWindow)
               EasyRequest(MainWindow,&es,NULL,mynode->Hotkey,mynode->Name);
            else
               EasyRequest(NULL,&es,NULL,mynode->Hotkey,mynode->Name);
         }
         else
         {
            AttachCxObj(broker,mynode->cx);
         }
      }
      mynode=(struct MyNode *)mynode->Node.ln_Succ;
   }
}

BOOL MayExit(void)
{
   if(wbapps == 0)
      return(TRUE);

   es.es_Title=getString(REQ_ERRTITLE_STR);
   es.es_TextFormat=getString(ERR_LAUNCH_STILLWORKBENCH_STR);
   es.es_GadgetFormat=getString(REQ_PROCEED_STR);

   if(CfgWindow)
      LockWindow(CfgWindow);

   else if(MainWindow)
      LockWindow(MainWindow);

   EasyRequest(NULL,&es,NULL,wbapps);

   if(CfgWindow)
      UnLockWindow(CfgWindow);

   else if(MainWindow)
      UnLockWindow(MainWindow);

   return(FALSE);
}


/***** Main Window *****/

int ListViewTop(struct Gadget *gadget, struct Window *window)
{
   ULONG top;

   if (GadToolsBase->lib_Version < 39)
      top = *(UWORD *)(((char *)gadget) + sizeof(struct Gadget) + 4);
   else
      GT_GetGadgetAttrs(gadget, window, NULL, GTLV_Top, &top, TAG_DONE);

   return (top);
}

void MakeVisible(ULONG vis,ULONG lines,struct Gadget *gadget, struct Window *window)
{
   ULONG top;

   if (GadToolsBase->lib_Version < 39)
   {
      top=ListViewTop(gadget,window);

      if(vis < top)
      {
         while(vis < top)
            top--;
      }
      else
      {
         while(vis > top+lines-1)
            top++;
      }

      GT_SetGadgetAttrs(gadget,window,NULL,GTLV_Top,top,TAG_END);
   }
   else
   {
      GT_SetGadgetAttrs(gadget,window,NULL,GTLV_MakeVisible,vis,TAG_END);
   }
}

void DrawMainGUI(void)
{
   struct Gadget *lastgad=NULL;

   InnerHeight=MainWindow->Height-MainWindow->BorderTop-MainWindow->BorderBottom;
   InnerWidth=MainWindow->Width-MainWindow->BorderLeft-MainWindow->BorderRight;

   XOff=MainWindow->BorderLeft;
   YOff=MainWindow->BorderTop;

   ListViewHeight=InnerHeight-2;

   if(GadToolsBase->lib_Version < 39)
      cfg_Lines=(ListViewHeight-8)/PubScreen->Font->ta_YSize-1;

   else
      cfg_Lines=(ListViewHeight-4)/PubScreen->Font->ta_YSize;

   cfg_InnerWidth=MainWindow->Width-MainWindow->BorderLeft-MainWindow->BorderRight;

   glist=NULL;

   lastgad=(struct Gadget *)CreateContext(&glist);

   gadgets[0].ng_LeftEdge=XOff+2;
   gadgets[0].ng_TopEdge=YOff+1;
   gadgets[0].ng_Height=ListViewHeight;
   gadgets[0].ng_Width=InnerWidth-4;
   gadgets[0].ng_TextAttr=PubScreen->Font;
   gadgets[0].ng_VisualInfo=vi;

   lastgad = CreateGadget(LISTVIEW_KIND,lastgad,&gadgets[0],GTLV_ShowSelected,NULL,
                                                            GTLV_Labels,&CommandList,
                                                            TAG_END);

   listviewgad=lastgad;

   AddGList(MainWindow,glist,-1,-1,NULL);
   RefreshGList(glist,MainWindow,NULL,-1);
   GT_RefreshWindow(MainWindow,NULL);

   if(maxlist!=0)
   {
      GT_SetGadgetAttrs(listviewgad,MainWindow,NULL,GTLV_Selected,lastitem,TAG_END);
      MakeVisible(lastitem,cfg_Lines,listviewgad,MainWindow);
   }
}

void Popup(void)
{
   struct Screen *s;
   ULONG lock,c,sigs;
   struct PubScreenNode *psnode;
   struct IntuiMessage *IntuiMessage;
   ULONG class,InnerHeight,xpos,ypos,code,secs,micros,oldsecs,oldmicros,qualifier,num;
   struct MyNode *mynode;
   struct MenuItem *menuitem;
   struct AppMessage *appmsg;
   BOOL action;

   windowptr=myproc->pr_WindowPtr;

   /* Choose a public screen to open our window */
   lock = LockIBase(0);
   s=IntuitionBase->FirstScreen;
   UnlockIBase(lock);

   PubScreenName = NULL;
   if ( s->Flags & WBENCHSCREEN )
   {
      PubScreenName = "Workbench" ;
   }
   else
   {
      if ( s->Flags & PUBLICSCREEN )
      {
         /* s is a public screen so find its name */

         psnode=(struct PubScreenNode *)LockPubScreenList();

         while ((psnode) && !(PubScreenName))
         {
            if ((psnode->psn_Flags != PSNF_PRIVATE) && (psnode->psn_Screen == s))
            {
               /* found it */
               PubScreenName = psnode->psn_Node.ln_Name;
            }
            else
            {
               /* check next one */
               psnode = (struct PubScreenNode *)psnode->psn_Node.ln_Succ;
            }
         }
         UnlockPubScreenList();
      }
   }

   if(!(PubScreen=LockPubScreen(PubScreenName)))
      return;

   ScreenToFront(PubScreen);

   if(!(textfont=OpenFont(PubScreen->Font)))
   {
      DisplayBeep(NULL);
      CleanUpMain();
      return;
   }

   if(!(vi=(APTR)GetVisualInfo(PubScreen,TAG_END)))
   {
      DisplayBeep(NULL);
      CleanUpMain();
      return;
   }

   if(GadToolsBase->lib_Version < 39)
      InnerHeight=(cfg_Lines+1)*PubScreen->Font->ta_YSize+8+2;

   else
      InnerHeight=cfg_Lines*PubScreen->Font->ta_YSize+4+2;

   ypos=PubScreen->MouseY-PubScreen->WBorTop-PubScreen->Font->ta_YSize-1-1-2-PubScreen->Font->ta_YSize/2;

   if(ypos<0)
      ypos=0;

   xpos=PubScreen->MouseX-20;

   if(xpos<0)
      xpos=0;

   if(!(MainWindow=OpenWindowTags(NULL,WA_Left,               xpos,
                                       WA_Top,                ypos,
                                       WA_InnerWidth,         cfg_InnerWidth,
                                       WA_InnerHeight,        InnerHeight,
                                       WA_MinWidth,           -1,
                                       WA_MinHeight,          -1,
                                       WA_MaxWidth,           -1,
                                       WA_MaxHeight,          -1,
                                       WA_AutoAdjust,         TRUE,
                                       WA_Flags,              WFLG_SIZEGADGET|WFLG_SIZEBBOTTOM|WFLG_ACTIVATE|WFLG_CLOSEGADGET|WFLG_DEPTHGADGET|WFLG_DRAGBAR|WFLG_NEWLOOKMENUS,
                                       WA_IDCMP,              IDCMP_NEWSIZE|IDCMP_CLOSEWINDOW|LISTVIEWIDCMP|IDCMP_RAWKEY|IDCMP_MENUPICK,
                                       WA_Title,              "CommandList "VERSION" © 1994 Johan Billing",
                                       WA_PubScreenName,      PubScreenName,
                                       WA_PubScreenFallBack,  TRUE,
                                       TAG_END)))
   {
      DisplayBeep(NULL);
      CleanUpMain();
      return;
   }

   SetFont(MainWindow->RPort,textfont);

   myproc->pr_WindowPtr=MainWindow;

   MainWindowMinWidth=100+MainWindow->BorderLeft+MainWindow->BorderRight;

   if(GadToolsBase->lib_Version < 39)
      MainWindowMinHeight=(5+1)*PubScreen->Font->ta_YSize+8+2+MainWindow->BorderTop+MainWindow->BorderBottom;

   else
      MainWindowMinHeight=5*PubScreen->Font->ta_YSize+4+2+MainWindow->BorderTop+MainWindow->BorderBottom;

   WindowLimits(MainWindow,MainWindowMinWidth,MainWindowMinHeight,-1,-1);

   MainWindowNewMenus[0].nm_Type    = NM_TITLE;
   MainWindowNewMenus[0].nm_Label   = getString(MAIN_MENU_PROJECT_STR);

   MainWindowNewMenus[1].nm_Type    = NM_ITEM;
   MainWindowNewMenus[1].nm_Label   = getString(MAIN_MENU_ABOUT_STR);
   MainWindowNewMenus[1].nm_CommKey = getString(MAIN_MENU_ABOUT_KEY);

   MainWindowNewMenus[2].nm_Type    = NM_ITEM;
   MainWindowNewMenus[2].nm_Label   = (STRPTR)NM_BARLABEL;

   MainWindowNewMenus[3].nm_Type    = NM_ITEM;
   MainWindowNewMenus[3].nm_Label   = getString(MAIN_MENU_HIDE_STR);
   MainWindowNewMenus[3].nm_CommKey = getString(MAIN_MENU_HIDE_KEY);

   MainWindowNewMenus[4].nm_Type    = NM_ITEM;
   MainWindowNewMenus[4].nm_Label   = getString(MAIN_MENU_QUIT_STR);
   MainWindowNewMenus[4].nm_CommKey = getString(MAIN_MENU_QUIT_KEY);

   MainWindowNewMenus[5].nm_Type    = NM_TITLE;
   MainWindowNewMenus[5].nm_Label   = getString(MAIN_MENU_SETTINGS_STR);

   MainWindowNewMenus[6].nm_Type    = NM_ITEM;
   MainWindowNewMenus[6].nm_Label   = getString(MAIN_MENU_EDITCOMMANDS_STR);
   MainWindowNewMenus[6].nm_CommKey = getString(MAIN_MENU_EDITCOMMANDS_KEY);

   MainWindowNewMenus[7].nm_Type    = NM_ITEM;
   MainWindowNewMenus[7].nm_Label   = (STRPTR)NM_BARLABEL;

   MainWindowNewMenus[8].nm_Type    = NM_ITEM;
   MainWindowNewMenus[8].nm_Label   = getString(MAIN_MENU_LOADSETTINGS_STR);
   MainWindowNewMenus[8].nm_CommKey = getString(MAIN_MENU_LOADSETTINGS_KEY);

   MainWindowNewMenus[9].nm_Type    = NM_ITEM;
   MainWindowNewMenus[9].nm_Label   = getString(MAIN_MENU_SAVESETTINGS_STR);
   MainWindowNewMenus[9].nm_CommKey = getString(MAIN_MENU_SAVESETTINGS_KEY);

   MainWindowNewMenus[10].nm_Type    = NM_ITEM;
   MainWindowNewMenus[10].nm_Label   = getString(MAIN_MENU_SAVESETTINGSAS_STR);
   MainWindowNewMenus[10].nm_CommKey = getString(MAIN_MENU_SAVESETTINGSAS_KEY);

   MainWindowNewMenus[11].nm_Type    = NM_END;

	if(!(MainWindowMenus=CreateMenus(MainWindowNewMenus,GTMN_FrontPen,0L,TAG_DONE)))
   {
      DisplayBeep(NULL);
      CleanUpMain();
      return;
   }

	LayoutMenus(MainWindowMenus,vi,GTMN_TextAttr,PubScreen->Font,GTMN_NewLookMenus,TRUE,TAG_DONE);
	SetMenuStrip(MainWindow,MainWindowMenus);

   DrawMainGUI();

   oldsecs=0;
   oldmicros=0;

   for(;;)
   {
      sigs = Wait(1<<MainWindow->UserPort->mp_SigBit | cxsigflag | wbsigflag | SIGBREAKF_CTRL_C | wbappsigflag);

      while(IntuiMessage=(struct IntuiMessage *)GT_GetIMsg(MainWindow->UserPort))
      {
         class=IntuiMessage->Class;
         code=IntuiMessage->Code;
         secs=IntuiMessage->Seconds;
         micros=IntuiMessage->Micros;
         qualifier=IntuiMessage->Qualifier;
         GT_ReplyIMsg(IntuiMessage);

         switch(class)
         {
            case IDCMP_CLOSEWINDOW:   CleanUpMain();
                                      return;

            case IDCMP_MENUPICK:      num=code;
                                      while(num!=MENUNULL)
                                      {
                                         if(MENUNUM(num)==0)
                                         {
                                            switch(ITEMNUM(num))
                                            {
                                               case 0: LockWindow(MainWindow);
                                                       es.es_Title=getString(REQ_ABOUTTITLE_STR);
                                                       es.es_TextFormat=getString(REQ_ABOUTTEXT_STR);
                                                       es.es_GadgetFormat=getString(REQ_OK_STR);
                                                       EasyRequest(NULL,&es,NULL,VERSION,__COMMODORE_DATE__,cfg_Popkey,wbapps);
                                                       UnLockWindow(MainWindow);
                                                       break;
                                               case 2: CleanUpMain();
                                                       return;
                                               case 3: if(MayExit())
                                                       {
                                                          CleanUpMain();
                                                          CleanUp(0);
                                                       }
                                            }
                                         }
                                         if(MENUNUM(num)==1)
                                         {
                                            switch(ITEMNUM(num))
                                            {
                                               case 0:
                                                  LockWindow(MainWindow);
                                                  GT_SetGadgetAttrs(listviewgad,MainWindow,NULL,GTLV_Labels,~0,TAG_END);
                                                  RemoveHotkeys();
                                                  Config();

                                                  if(MainWindow==NULL)
                                                     return;

                                                  CreateHotkeys();
                                                  GT_SetGadgetAttrs(listviewgad,MainWindow,NULL,GTLV_Labels,&CommandList,TAG_END);
                                                  lastitem=0;
                                                  GT_SetGadgetAttrs(listviewgad,MainWindow,NULL,GTLV_Selected,lastitem,TAG_END);
                                                  MakeVisible(lastitem,cfg_Lines,listviewgad,MainWindow);
                                                  UnLockWindow(MainWindow);
                                                  break;
                                               case 2:
                                                  if(OpenAsl(asl_buf,getString(MAIN_MENU_LOADSETTINGS_STR),FALSE))
                                                  {
                                                     struct MyNode *mynode;

                                                     while(mynode=(struct MyNode *)RemHead(&CommandList))
                                                        FreeMem(mynode,sizeof(struct MyNode));

                                                     NewList(&CommandList);

                                                     GT_SetGadgetAttrs(listviewgad,MainWindow,NULL,GTLV_Labels,~0,TAG_END);
                                                     RemoveHotkeys();
                                                     LoadConfig(asl_buf);
                                                     CreateHotkeys();
                                                     GT_SetGadgetAttrs(listviewgad,MainWindow,NULL,GTLV_Labels,&CommandList,TAG_END);
                                                     lastitem=0;
                                                     GT_SetGadgetAttrs(listviewgad,MainWindow,NULL,GTLV_Selected,lastitem,TAG_END);
                                                     MakeVisible(lastitem,cfg_Lines,listviewgad,MainWindow);
                                                  }
                                                  break;
                                               case 3:
                                                  SaveConfig(cfg_Settings);
                                                  break;
                                               case 4:
                                                  if(OpenAsl(asl_buf,getString(MAIN_MENU_SAVESETTINGSAS_STR),TRUE))
                                                  {
                                                     GT_SetGadgetAttrs(listviewgad,MainWindow,NULL,GTLV_Labels,~0,TAG_END);
                                                     SaveConfig(asl_buf);
                                                     GT_SetGadgetAttrs(listviewgad,MainWindow,NULL,GTLV_Labels,&CommandList,TAG_END);
                                                     lastitem=0;
                                                     GT_SetGadgetAttrs(listviewgad,MainWindow,NULL,GTLV_Selected,lastitem,TAG_END);
                                                     MakeVisible(lastitem,cfg_Lines,listviewgad,MainWindow);
                                                  }
                                                  break;
                                            }
                                         }
                                         menuitem=ItemAddress(MainWindowMenus,num);
                                         num=menuitem->NextSelect;
                                      }

                                      break;

            case IDCMP_RAWKEY:        action=TRUE;

                                      if((code == CURSORUP && (qualifier & QUAL_SHIFT)) || code == NUMPAD_9)
                                      {
                                         if(ListViewTop(listviewgad,MainWindow)==lastitem)
                                            lastitem-=cfg_Lines-1;

                                         else
                                            lastitem=ListViewTop(listviewgad,MainWindow);

                                         if(lastitem<0)
                                            lastitem=0;
                                      }
                                      else if((code == CURSORUP && (qualifier & IEQUALIFIER_CONTROL)) || code == NUMPAD_7)
                                      {
                                         lastitem=0;
                                      }
                                      else if(code == CURSORUP || code == NUMPAD_8)
                                      {
                                         if(lastitem>0)
                                            lastitem--;
                                      }
                                      else if((code == CURSORDOWN && (qualifier & QUAL_SHIFT)) || code == NUMPAD_3)
                                      {
                                         if(ListViewTop(listviewgad,MainWindow)+cfg_Lines-1==lastitem)
                                            lastitem+=cfg_Lines-1;

                                         else
                                           lastitem=ListViewTop(listviewgad,MainWindow)+cfg_Lines-1;

                                         if(lastitem>=maxlist)
                                           lastitem=maxlist-1;
                                      }
                                      else if((code == CURSORDOWN && (qualifier & IEQUALIFIER_CONTROL)) || code == NUMPAD_1)
                                      {
                                         lastitem=maxlist-1;
                                      }
                                      else if(code == CURSORDOWN || code == NUMPAD_2)
                                      {
                                         if(lastitem<maxlist-1)
                                            lastitem++;
                                      }
                                      else if(code == ESC)
                                      {
                                         CleanUpMain();
                                         return;
                                      }
                                      else if(code == ENTER || code == RETURN)
                                      {
                                         mynode=CommandList.lh_Head;

                                         for(c=0;c<lastitem;c++)
                                            mynode=mynode->Node.ln_Succ;

                                         if(LaunchCommand(mynode))
                                         {
                                           CleanUpMain();
                                           return;
                                         }
                                      }
                                      else
                                      {
                                         action=FALSE;
                                      }

                                      if(action)
                                      {
                                         GT_SetGadgetAttrs(listviewgad,MainWindow,NULL,GTLV_Selected,lastitem,TAG_END);
                                         MakeVisible(lastitem,cfg_Lines,listviewgad,MainWindow);
                                      }

                                      break;

            case IDCMP_GADGETUP:      if(code==lastitem)
                                         if(DoubleClick(oldsecs,oldmicros,secs,micros))
                                         {
                                            mynode=CommandList.lh_Head;

                                            for(c=0;c<code;c++)
                                               mynode=mynode->Node.ln_Succ;

                                            if(LaunchCommand(mynode))
                                            {
                                               CleanUpMain();
                                               return;
                                            }
                                         }
                                      lastitem=code;
                                      oldsecs=secs;
                                      oldmicros=micros;
                                      break;

            case IDCMP_NEWSIZE:       RemoveGList(MainWindow,glist,-1);
                                      FreeGadgets(glist);
                                      Move(MainWindow->RPort,0,0);
                                      ClearScreen(MainWindow->RPort);
                                      RefreshWindowFrame(MainWindow);
                                      DrawMainGUI();
                                      break;

            case IDCMP_REFRESHWINDOW: GT_BeginRefresh(MainWindow);
                                      GT_EndRefresh(MainWindow,TRUE);
         }
      }

      if(sigs & wbsigflag)
      {
         ProcessWorkbench();
      }

      if(sigs & SIGBREAKF_CTRL_C)
      {
         if(MayExit())
         {
            CleanUpMain();
            CleanUp(0);
         }
      }

      if(sigs & wbappsigflag)
      {
         action=FALSE;

         while(appmsg = (struct AppMessage *)GetMsg(WBAppPort))
         {
            if(appmsg->am_Type == AMTYPE_APPMENUITEM)
               action=TRUE;

            ReplyMsg((struct Message *)appmsg);
         }

         if(action)
         {
            Appear();
         }
      }

      if(sigs & cxsigflag)
      {
         HandleCx();

         if(!MainWindow)
            return;
      }
   }
}

/* Initialization and background */

myputs(UBYTE *str)
{
   Write(Output(),str,strlen(str));
}

#include "wb2cli.h"

_main()
{
   ULONG sigs;
   struct AppMessage *appmsg;
   CxObj *tmpobj;
   BOOL action;

   WB2CLI(_WBMsg,4000,(struct DosLibrary *)DOSBase); /* Copy path etc */

   if(SysBase->LibNode.lib_Version<37)
   {
      if(!_WBMsg)
         myputs("Sorry! This program requires Kickstart 2.04 or higher\n");

      _exit(0);
   }

   NewList(&CommandList);

   if(!(KeymapBase=OpenLibrary("keymap.library",37)))
      CleanUp(10);

   if(!(CxBase=OpenLibrary("commodities.library",37)))
      CleanUp(10);

   if(LocaleBase=OpenLibrary("locale.library",37))
   {
      if (!(locale=OpenLocale(NULL)))
      {
         es.es_Title="CommandList Error";
         es.es_TextFormat="No locale set";
         es.es_GadgetFormat="Quit";
         EasyRequest(NULL,&es,NULL,NULL);
         CloseLibrary(LocaleBase);
         LocaleBase = NULL;
      }

      catalog=OpenCatalog(locale,"CommandList.catalog",OC_BuiltInLanguage, "english",
                                                       OC_Version,  0L,
                                                       TAG_DONE );
   }

   myproc=(struct Process *)FindTask(NULL);

   if(_WBMsg)
   {
      struct DiskObject *dobj;
      UBYTE *what;
      BPTR olddir;

      olddir=CurrentDir(_WBMsg->sm_ArgList->wa_Lock);

      if(!(dobj=GetDiskObject(_WBMsg->sm_ArgList->wa_Name)))
      {
         CurrentDir(olddir);
         CleanUp(10);
      }

      if(what=FindToolType(dobj->do_ToolTypes,"CX_POPKEY"))
      {
         strncpy(cfg_Popkey,what,48);
         cfg_Popkey[49]=0;
      }

      if(what=FindToolType(dobj->do_ToolTypes,"SETTINGS"))
      {
         strncpy(cfg_Settings,what,99);
         cfg_Settings[99]=0;
      }

      if(what=FindToolType(dobj->do_ToolTypes,"CX_POPUP"))
         if(stricmp(what,"YES")==0) cfg_Popup=TRUE;

      if(what=FindToolType(dobj->do_ToolTypes,"CX_PRIORITY"))
         newbroker.nb_Pri=atoi(what);

      FreeDiskObject(dobj);
      CurrentDir(olddir);
   }
   else
   {
      if(!(rdargs=(struct RDArgs *)ReadArgs(argstr,argarray,NULL)))
      {
         PrintFault(IoErr(),NULL);
         CleanUp(10);
      }

      if(argarray[CX_POPUP])
         cfg_Popup=TRUE;

      if(argarray[CX_POPKEY])
      {
         strncpy(cfg_Popkey,(UBYTE *)argarray[CX_POPKEY],48);
         cfg_Popkey[49]=0;
      }

      if(argarray[SETTINGS])
      {
         strncpy(cfg_Settings,(UBYTE *)argarray[SETTINGS],99);
         cfg_Settings[99]=0;
      }

      if(argarray[CX_PRIORITY])
         newbroker.nb_Pri=*(ULONG *)argarray[CX_PRIORITY];
   }

   LoadConfig(cfg_Settings);
   strcpy(asl_buf,cfg_Settings);

   newbroker.nb_Descr=getString(EXCHANGE_DESCR_STR);

   if(!(WBReplyPort = CreateMsgPort()))
   {
      DisplayBeep(NULL);
      CleanUp(10);
   }

   if(!(WBAppPort = CreateMsgPort()))
   {
      DisplayBeep(NULL);
      CleanUp(10);
   }

   if(!(newbroker.nb_Port = CreateMsgPort()))
   {
      DisplayBeep(NULL);
      CleanUp(10);
   }

   cxsigflag = 1 << newbroker.nb_Port->mp_SigBit;
   wbsigflag = 1 << WBReplyPort->mp_SigBit;
   wbappsigflag = 1 << WBAppPort->mp_SigBit;

   if(!(broker=CxBroker(&newbroker, NULL)))
   {
      /* Is already running, other copy automatically notified */
      CleanUp(0);
   }

   if(!(tmpobj = HotKey(cfg_Popkey,newbroker.nb_Port,POPKEY_EVENT)))
   {
      es.es_Title=getString(REQ_ERRTITLE_STR);
      es.es_TextFormat=getString(ERR_INVALID_HOTKEY_STR);
      es.es_GadgetFormat=getString(REQ_QUIT_STR);

      EasyRequest(NULL,&es,NULL,cfg_Popkey);
      CleanUp(10);
   }

   AttachCxObj(broker,tmpobj);
   CreateHotkeys();
   ActivateCxObj(broker,1);

   appmenuitem=AddAppMenuItem(0,NULL,"CommandList...",WBAppPort,TAG_END);

   if(cfg_Popup)
      Popup();

   for(;;)
   {
      sigs = Wait(SIGBREAKF_CTRL_C | cxsigflag | wbsigflag | wbappsigflag);

      if(sigs & SIGBREAKF_CTRL_C)
      {
         if(MayExit())
            CleanUp(0);
      }

      if(sigs & wbappsigflag)
      {
         action=FALSE;

         while(appmsg = (struct AppMessage *)GetMsg(WBAppPort))
         {
            if(appmsg->am_Type == AMTYPE_APPMENUITEM)
               action=TRUE;

            ReplyMsg((struct Message *)appmsg);
         }

         if(action)
         {
            Appear();
         }
      }

      if(sigs & wbsigflag)
      {
         ProcessWorkbench();
      }

      if(sigs & cxsigflag)
      {
         HandleCx();
      }
   }
}

struct Gadget *commandgadget,*cyclegadget,*stackgadget,*namegadget,*deletegadget,*addgadget,*hotkeygadget;
struct Gadget *upgadget,*downgadget,*listviewgadget;

struct NewGadget cfggadgets[12];

STRPTR cfgcyclestrings[3];

void ActivateNode(struct MyNode *mynode)
{
   GT_SetGadgetAttrs(hotkeygadget,CfgWindow,NULL,GTST_String,mynode->Hotkey,TAG_END);
   GT_SetGadgetAttrs(commandgadget,CfgWindow,NULL,GTST_String,mynode->Command,TAG_END);

   if(mynode->Type == WORKBENCH)
   {
      GT_SetGadgetAttrs(cyclegadget,CfgWindow,NULL,GTCY_Active,0,TAG_END);
      GT_SetGadgetAttrs(stackgadget,CfgWindow,NULL,GA_Disabled,TRUE,0,TAG_END);
   }
   else
   {
      GT_SetGadgetAttrs(cyclegadget,CfgWindow,NULL,GTCY_Active,1,TAG_END);
      GT_SetGadgetAttrs(stackgadget,CfgWindow,NULL,GA_Disabled,FALSE,0,TAG_END);
      GT_SetGadgetAttrs(stackgadget,CfgWindow,NULL,GTIN_Number,mynode->Stack,TAG_END);
   }

   if(mynode!=(struct MyNode *)CommandList.lh_TailPred)
   {
      GT_SetGadgetAttrs(downgadget,CfgWindow,NULL,GA_Disabled,FALSE,0,TAG_END);
   }
   else
   {
      GT_SetGadgetAttrs(downgadget,CfgWindow,NULL,GA_Disabled,TRUE,0,TAG_END);
   }

   if(mynode!=(struct MyNode *)CommandList.lh_Head)
   {
      GT_SetGadgetAttrs(upgadget,CfgWindow,NULL,GA_Disabled,FALSE,0,TAG_END);
   }
   else
   {
      GT_SetGadgetAttrs(upgadget,CfgWindow,NULL,GA_Disabled,TRUE,0,TAG_END);
   }

   return;
}

int Widest(int old,UBYTE *text,struct RastPort *rport)
{
   struct TextExtent te;

   TextExtent(rport,text,strlen(text),&te);

   if(te.te_Width > old)
      return(te.te_Width);

   return(old);
}

#define CFG_NAME      1
#define CFG_LISTVIEW  2
#define CFG_HOTKEY    3
#define CFG_COMMAND   4
#define CFG_GETFILE   5
#define CFG_CYCLE     6
#define CFG_STACK     7
#define CFG_ADD       8
#define CFG_DELETE    9
#define CFG_UP        10
#define CFG_DOWN      11

#define getgadgetstring(g) ((struct StringInfo *)g->SpecialInfo)->Buffer
#define getgadgetvalue(g)  ((struct StringInfo *)g->SpecialInfo)->LongInt

void CfgDisableAll(void)
{
   GT_SetGadgetAttrs(namegadget,CfgWindow,NULL,GA_Disabled,TRUE,0,TAG_END);
   GT_SetGadgetAttrs(hotkeygadget,CfgWindow,NULL,GA_Disabled,TRUE,0,TAG_END);
   GT_SetGadgetAttrs(commandgadget,CfgWindow,NULL,GA_Disabled,TRUE,0,TAG_END);
   GT_SetGadgetAttrs(cyclegadget,CfgWindow,NULL,GA_Disabled,TRUE,0,TAG_END);
   GT_SetGadgetAttrs(stackgadget,CfgWindow,NULL,GA_Disabled,TRUE,0,TAG_END);
   GT_SetGadgetAttrs(deletegadget,CfgWindow,NULL,GA_Disabled,TRUE,0,TAG_END);
   GT_SetGadgetAttrs(upgadget,CfgWindow,NULL,GA_Disabled,TRUE,0,TAG_END);
   GT_SetGadgetAttrs(downgadget,CfgWindow,NULL,GA_Disabled,TRUE,0,TAG_END);
}

void CfgEnableAll(void)
{
   GT_SetGadgetAttrs(namegadget,CfgWindow,NULL,GA_Disabled,FALSE,0,TAG_END);
   GT_SetGadgetAttrs(hotkeygadget,CfgWindow,NULL,GA_Disabled,FALSE,0,TAG_END);
   GT_SetGadgetAttrs(commandgadget,CfgWindow,NULL,GA_Disabled,FALSE,0,TAG_END);
   GT_SetGadgetAttrs(cyclegadget,CfgWindow,NULL,GA_Disabled,FALSE,0,TAG_END);
   GT_SetGadgetAttrs(stackgadget,CfgWindow,NULL,GA_Disabled,FALSE,0,TAG_END);
   GT_SetGadgetAttrs(deletegadget,CfgWindow,NULL,GA_Disabled,FALSE,0,TAG_END);
   GT_SetGadgetAttrs(upgadget,CfgWindow,NULL,GA_Disabled,FALSE,0,TAG_END);
   GT_SetGadgetAttrs(downgadget,CfgWindow,NULL,GA_Disabled,FALSE,0,TAG_END);
}

void DrawCfgGUI(void)
{
   struct Gadget *lastgad=NULL;
   ULONG listviewheight;
   ULONG buttonwidth=0,c;

   InnerHeight=CfgWindow->Height-CfgWindow->BorderTop-CfgWindow->BorderBottom;
   InnerWidth=CfgWindow->Width-CfgWindow->BorderLeft-CfgWindow->BorderRight;

   XOff=CfgWindow->BorderLeft;
   YOff=CfgWindow->BorderTop;

   buttonwidth=Widest(buttonwidth,getString(CFG_GAD_ADD_STR),CfgWindow->RPort);
   buttonwidth=Widest(buttonwidth,getString(CFG_GAD_DELETE_STR),CfgWindow->RPort);
   buttonwidth=Widest(buttonwidth,getString(CFG_GAD_UP_STR),CfgWindow->RPort);
   buttonwidth=Widest(buttonwidth,getString(CFG_GAD_DOWN_STR),CfgWindow->RPort);

   buttonwidth+=8+20;

   listviewheight=InnerHeight
                  -2                                     /* Mellanrum nere */
                  -3-PubScreen->Font->ta_YSize-3         /* Gadgetrad */
                  -4                                     /* Mellanrum */
                  -PubScreen->Font->ta_YSize             /* Text      */
                  -4                                     /* Mellanrum */
                  -3-PubScreen->Font->ta_YSize-3         /* Gadgetrad */
                  -4                                     /* Mellanrum */
                  -PubScreen->Font->ta_YSize             /* Text      */
                  -4
                  -3-PubScreen->Font->ta_YSize-3         /* Gadgetrad */
                  -4                                     /* Mellanrum */
                  -PubScreen->Font->ta_YSize             /* Text      */
                  -8                                     /* Mellanrum */
                  -2;                                    /* Mellanrum uppe */

   cfg_CfgLines=(listviewheight-4-6)/PubScreen->Font->ta_YSize-1;
   cfg_CfgInnerWidth=CfgWindow->Width-CfgWindow->BorderLeft-CfgWindow->BorderRight;

   cfgglist=NULL;

   lastgad=(struct Gadget *)CreateContext(&cfgglist);

   for(c=0;c<12;c++)
   {
      cfggadgets[c].ng_TextAttr=PubScreen->Font;
      cfggadgets[c].ng_VisualInfo=vi;
      cfggadgets[c].ng_GadgetID=c+1;
   }

   cfggadgets[0].ng_LeftEdge=0;
   cfggadgets[0].ng_TopEdge=0;
   cfggadgets[0].ng_Height=PubScreen->Font->ta_YSize+6;
   cfggadgets[0].ng_Width=InnerWidth-4-2-buttonwidth;

   lastgad = CreateGadget(STRING_KIND,lastgad,&cfggadgets[0],GTST_EditHook, &stredithook,GTST_MaxChars,39,TAG_END);
   namegadget=lastgad;

   cfggadgets[1].ng_LeftEdge=XOff+2;
   cfggadgets[1].ng_TopEdge=YOff+2;
   cfggadgets[1].ng_Height=listviewheight;
   cfggadgets[1].ng_Width=InnerWidth-4-2-buttonwidth;

   lastgad = CreateGadget(LISTVIEW_KIND,lastgad,&cfggadgets[1],GTLV_ShowSelected,lastgad,
                                                               GTLV_Labels,&CommandList,
                                                               TAG_END);
   listviewgadget=lastgad;

   cfggadgets[2].ng_LeftEdge=XOff+2;
   cfggadgets[2].ng_TopEdge=YOff+InnerHeight-2-PubScreen->Font->ta_YSize-6-4-PubScreen->Font->ta_YSize-4-PubScreen->Font->ta_YSize-6-PubScreen->Font->ta_YSize-6-4-PubScreen->Font->ta_YSize-4;
   cfggadgets[2].ng_Height=PubScreen->Font->ta_YSize+6;
   cfggadgets[2].ng_Width=InnerWidth-4;
   cfggadgets[2].ng_GadgetText=getString(CFG_GAD_HOTKEY_STR);
   cfggadgets[2].ng_Flags=PLACETEXT_ABOVE;

   lastgad = CreateGadget(STRING_KIND,lastgad,&cfggadgets[2],GTST_EditHook, &stredithook,GT_Underscore,'_',
                                                             GTST_MaxChars,199,TAG_END);
   hotkeygadget=lastgad;

   cfggadgets[3].ng_LeftEdge=XOff+2;
   cfggadgets[3].ng_TopEdge=YOff+InnerHeight-2-PubScreen->Font->ta_YSize-6-4-PubScreen->Font->ta_YSize-4-PubScreen->Font->ta_YSize-6;
   cfggadgets[3].ng_Height=PubScreen->Font->ta_YSize+6;
   cfggadgets[3].ng_Width=InnerWidth-4-20;

   lastgad = CreateGadget(STRING_KIND,lastgad,&cfggadgets[3],GTST_EditHook, &stredithook,GT_Underscore,'_',
                                                             GTST_MaxChars,199,TAG_END);
   commandgadget=lastgad;

   cfggadgets[4].ng_LeftEdge=XOff+2+InnerWidth-4-20;
   cfggadgets[4].ng_TopEdge=YOff+InnerHeight-2-PubScreen->Font->ta_YSize-6-4-PubScreen->Font->ta_YSize-4-PubScreen->Font->ta_YSize-6;
   cfggadgets[4].ng_Height=PubScreen->Font->ta_YSize+6;
   cfggadgets[4].ng_Width=20;

   lastgad = CreateGadget(GENERIC_KIND,lastgad,&cfggadgets[4],TAG_END);

   getfileimg = NewObject(altclass, NULL, IA_Width,  20,
                                          IA_Height, PubScreen->Font->ta_YSize+6,
                                          ALT_Image, ALTI_GetFile,
                                          TAG_END);

   lastgad->GadgetRender = getfileimg;
   lastgad->SelectRender = getfileimg;
   lastgad->Flags       |= GFLG_GADGIMAGE | GFLG_GADGHIMAGE;
   lastgad->Activation  |= GACT_RELVERIFY;
   lastgad->GadgetType  |= GTYP_BOOLGADGET;

   cfgcyclestrings[0]=getString(CFG_GAD_WB_STR);
   cfgcyclestrings[1]=getString(CFG_GAD_CLI_STR);
   cfgcyclestrings[2]=NULL;

   cfggadgets[5].ng_LeftEdge=XOff+2;
   cfggadgets[5].ng_TopEdge=YOff+InnerHeight-2-PubScreen->Font->ta_YSize-6;
   cfggadgets[5].ng_Height=PubScreen->Font->ta_YSize+6;
   cfggadgets[5].ng_Width=(InnerWidth-4-2)/2;
   cfggadgets[5].ng_GadgetText=getString(CFG_GAD_TYPE_STR);
   cfggadgets[5].ng_Flags=PLACETEXT_ABOVE;

   lastgad = CreateGadget(CYCLE_KIND,lastgad,&cfggadgets[5],GT_Underscore,'_',GTCY_Labels,cfgcyclestrings,TAG_END);
   cyclegadget=lastgad;

   cfggadgets[6].ng_LeftEdge=XOff+InnerWidth-2-(InnerWidth-4-2)/2;
   cfggadgets[6].ng_TopEdge=YOff+InnerHeight-2-PubScreen->Font->ta_YSize-6;
   cfggadgets[6].ng_Height=PubScreen->Font->ta_YSize+6;
   cfggadgets[6].ng_Width=(InnerWidth-4-2)/2;
   cfggadgets[6].ng_GadgetText=getString(CFG_GAD_STACK_STR);
   cfggadgets[6].ng_Flags=PLACETEXT_ABOVE;

   lastgad = CreateGadget(INTEGER_KIND,lastgad,&cfggadgets[6],GTIN_EditHook,&stredithook,GT_Underscore,'_',TAG_END);
   stackgadget=lastgad;

   cfggadgets[7].ng_LeftEdge=XOff+InnerWidth-2-buttonwidth;
   cfggadgets[7].ng_TopEdge=YOff+2;
   cfggadgets[7].ng_Height=PubScreen->Font->ta_YSize+4;
   cfggadgets[7].ng_Width=buttonwidth;
   cfggadgets[7].ng_GadgetText=getString(CFG_GAD_ADD_STR);

   lastgad = CreateGadget(BUTTON_KIND,lastgad,&cfggadgets[7],GT_Underscore,'_',TAG_END);
   addgadget=lastgad;

   cfggadgets[8].ng_LeftEdge=XOff+InnerWidth-2-buttonwidth;
   cfggadgets[8].ng_TopEdge=YOff+2+PubScreen->Font->ta_YSize+4+2;
   cfggadgets[8].ng_Height=PubScreen->Font->ta_YSize+4;
   cfggadgets[8].ng_Width=buttonwidth;
   cfggadgets[8].ng_GadgetText=getString(CFG_GAD_DELETE_STR);

   lastgad = CreateGadget(BUTTON_KIND,lastgad,&cfggadgets[8],GT_Underscore,'_',TAG_END);
   deletegadget=lastgad;

   cfggadgets[9].ng_LeftEdge=XOff+InnerWidth-2-buttonwidth;
   cfggadgets[9].ng_TopEdge=YOff+2+PubScreen->Font->ta_YSize+4+2+PubScreen->Font->ta_YSize+4+2;
   cfggadgets[9].ng_Height=PubScreen->Font->ta_YSize+4;
   cfggadgets[9].ng_Width=buttonwidth;
   cfggadgets[9].ng_GadgetText=getString(CFG_GAD_UP_STR);

   lastgad = CreateGadget(BUTTON_KIND,lastgad,&cfggadgets[9],GT_Underscore,'_',TAG_END);
   upgadget=lastgad;

   cfggadgets[10].ng_LeftEdge=XOff+InnerWidth-2-buttonwidth;
   cfggadgets[10].ng_TopEdge=YOff+2+PubScreen->Font->ta_YSize+4+2+PubScreen->Font->ta_YSize+4+2+PubScreen->Font->ta_YSize+4+2;
   cfggadgets[10].ng_Height=PubScreen->Font->ta_YSize+4;
   cfggadgets[10].ng_Width=buttonwidth;
   cfggadgets[10].ng_GadgetText=getString(CFG_GAD_DOWN_STR);

   lastgad = CreateGadget(BUTTON_KIND,lastgad,&cfggadgets[10],GT_Underscore,'_',TAG_END);
   downgadget=lastgad;

   /* An invisible TEXT_KIND gadget. An easy way to draw a centered text
      with the shortcut underlines. */

   cfggadgets[11].ng_LeftEdge=XOff+2;
   cfggadgets[11].ng_TopEdge=YOff+InnerHeight-2-PubScreen->Font->ta_YSize-6-4-PubScreen->Font->ta_YSize-4-PubScreen->Font->ta_YSize-6-4-PubScreen->Font->ta_YSize-2;
   cfggadgets[11].ng_Height=PubScreen->Font->ta_YSize+4;
   cfggadgets[11].ng_Width=InnerWidth-4;
   cfggadgets[11].ng_GadgetText=getString(CFG_GAD_COMMAND_STR);
   cfggadgets[11].ng_Flags=PLACETEXT_IN;

   lastgad = CreateGadget(TEXT_KIND,lastgad,&cfggadgets[11],GT_Underscore,'_',TAG_END);

   AddGList(CfgWindow,cfgglist,-1,-1,NULL);
   RefreshGList(cfgglist,CfgWindow,NULL,-1);
   GT_RefreshWindow(CfgWindow,NULL);

   if(maxlist!=0)
   {
      GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Selected,cfglastitem,TAG_END);
      MakeVisible(cfglastitem,cfg_CfgLines,listviewgadget,CfgWindow);

      if(cfglastnode)
         ActivateNode(cfglastnode);

      else
      {
         ActivateNode((struct MyNode *)CommandList.lh_Head);
         cfglastnode=(struct MyNode *)CommandList.lh_Head;
      }
   }
   else
   {
      CfgDisableAll();
   }
}

void CleanUpCfg(void)
{
   if(appwindow)  RemoveAppWindow(appwindow);
   if(CfgWindow)  CloseWindow(CfgWindow);
   if(cfgglist)   FreeGadgets(cfgglist);
   if(cfgfib)     FreeMem(cfgfib,sizeof(struct FileInfoBlock));
   if(getfileimg) DisposeObject(getfileimg);
   if(altclass)   FreeClass(altclass);

   CfgWindow=NULL;
   cfgglist=NULL;
   appwindow=NULL;
   cfgfib=NULL;
   altclass=NULL;
   getfileimg=NULL;
}

void SwapMyNodes(struct MyNode *n1,struct MyNode *n2)
{
   UBYTE namebak[40],commandbak[200],keybak[40],typebak;
   ULONG stackbak;

   strcpy(namebak,n1->Name);
   strcpy(commandbak,n1->Command);
   strcpy(keybak,n1->Hotkey);
   typebak=n1->Type;
   stackbak=n1->Stack;

   strcpy(n1->Name,n2->Name);
   strcpy(n1->Command,n2->Command);
   strcpy(n1->Hotkey,n2->Hotkey);
   n1->Type=n2->Type;
   n1->Stack=n2->Stack;

   strcpy(n2->Name,namebak);
   strcpy(n2->Command,commandbak);
   strcpy(n2->Hotkey,keybak);
   n2->Type=typebak;
   n2->Stack=stackbak;
}

void CfgUp(void)
{
  if(cfglastnode == (struct MyNode *)CommandList.lh_Head)
   return;

  GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,~0,TAG_END);
  SwapMyNodes(cfglastnode,(struct MyNode *)cfglastnode->Node.ln_Pred);
  cfglastitem--;
  cfglastnode=(struct MyNode *)cfglastnode->Node.ln_Pred;
  GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,&CommandList,TAG_END);
  GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Selected,cfglastitem,TAG_END);
  MakeVisible(cfglastitem,cfg_CfgLines,listviewgadget,CfgWindow);
  ActivateNode(cfglastnode);
}

void CfgDown(void)
{
  if(cfglastnode == (struct MyNode *)CommandList.lh_TailPred)
   return;

  GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,~0,TAG_END);
  SwapMyNodes(cfglastnode,(struct MyNode *)cfglastnode->Node.ln_Succ);
  cfglastitem++;
  cfglastnode=(struct MyNode *)cfglastnode->Node.ln_Succ;
  GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,&CommandList,TAG_END);
  GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Selected,cfglastitem,TAG_END);
  MakeVisible(cfglastitem,cfg_CfgLines,listviewgadget,CfgWindow);
  ActivateNode(cfglastnode);
}

void CfgDelete(void)
{
   struct MyNode *mynode;
   UBYTE buf[50];

   LockWindow(CfgWindow);

   strcpy(buf,getString(REQ_DELETE_STR));
   strcat(buf,"|");
   strcat(buf,getString(REQ_CANCEL_STR));

   es.es_Title=getString(REQ_REQUEST_STR);
   es.es_TextFormat=getString(REQ_DELETETEXT_STR);
   es.es_GadgetFormat=buf;

   if(!(EasyRequest(NULL,&es,NULL,cfglastnode->Name)))
   {
      UnLockWindow(CfgWindow);
      return;
   }

   UnLockWindow(CfgWindow);

   GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,~0,TAG_END);

   mynode=cfglastnode;

   if(cfglastitem != maxlist-1)
   {
      cfglastnode=cfglastnode->Node.ln_Succ;
   }
   else if(cfglastitem != 0)
   {
      cfglastnode=cfglastnode->Node.ln_Pred;
      cfglastitem--;
   }
   else
   {
      cfglastnode=NULL;
      cfglastitem=0;
      CfgDisableAll();
   }

   maxlist--;
   Remove((struct Node *)mynode);
   FreeMem(mynode,sizeof(struct MyNode));
   GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,&CommandList,TAG_END);
   if(cfglastnode) ActivateNode(cfglastnode);
}

void CfgAdd(void)
{
   struct MyNode *mynode;

   if(mynode=(struct MyNode *)AllocMem(sizeof(struct MyNode),MEMF_CLEAR))
   {
      GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,~0,TAG_END);
      mynode->Type=WORKBENCH;
      mynode->Stack=4000;
      strcpy(mynode->Name,getString(CFG_NEW_ITEM_STR));
      strcpy(mynode->Command,"");
      mynode->Node.ln_Name=mynode->Name;
      AddTail(&CommandList,(struct Node *)mynode);
      maxlist++;
      cfglastitem=maxlist-1;
      cfglastnode=CommandList.lh_TailPred;
      CfgEnableAll();
      GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,&CommandList,TAG_END);
      GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Selected,cfglastitem,TAG_END);
      MakeVisible(cfglastitem,cfg_CfgLines,listviewgadget,CfgWindow);
      ActivateNode(cfglastnode);
      ActivateGadget(namegadget,CfgWindow,NULL);
   }
   else
   {
      DisplayBeep(NULL);
   }
}

void Config(void)
{
   ULONG sigs,class,code,c,qualifier,actual;
   ULONG xpos,ypos,buttonwidth=0,CfgWindowInnerHeight;
   struct IntuiMessage *IntuiMessage;
   struct AppMessage *appmsg;
   APTR iaddress;
   BOOL action;
   struct WBArg *arglist;
   BPTR l,olddir;
   struct MyNode *mynode;
   struct DiskObject *dobj;
   struct InputEvent ie;
   UBYTE buf[100];
   CxObj *tmpobj;

   if(!(altclass=InitAltClass()))
   {
      DisplayBeep(NULL);
      CleanUpCfg();
      return;
   }

   if(!(cfgfib=(struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_ANY)))
   {
      DisplayBeep(NULL);
      CleanUpCfg();
      return;
   }

   cfglastitem=0;
   cfglastnode=NULL;

   ypos=PubScreen->MouseY-PubScreen->WBorTop-PubScreen->Font->ta_YSize-1-1-2-PubScreen->Font->ta_YSize/2;

   if(ypos<0)
      ypos=0;

   xpos=PubScreen->MouseX-20;

   if(xpos<0)
      xpos=0;

   buttonwidth=Widest(buttonwidth,getString(CFG_GAD_ADD_STR),MainWindow->RPort);
   buttonwidth=Widest(buttonwidth,getString(CFG_GAD_DELETE_STR),MainWindow->RPort);
   buttonwidth=Widest(buttonwidth,getString(CFG_GAD_UP_STR),MainWindow->RPort);
   buttonwidth=Widest(buttonwidth,getString(CFG_GAD_DOWN_STR),MainWindow->RPort);

   buttonwidth+=8+20;

   CfgWindowMinWidth=buttonwidth*2+2+2+2;

   if(cfg_CfgInnerWidth < CfgWindowMinWidth)
      cfg_CfgInnerWidth=CfgWindowMinWidth;

   CfgWindowMinHeight=+2
                      +4*(PubScreen->Font->ta_YSize+4)
                      +3*2
                      +8
                      +PubScreen->Font->ta_YSize
                      +4
                      +3+PubScreen->Font->ta_YSize+3
                      +4
                      +PubScreen->Font->ta_YSize
                      +4
                      +3+PubScreen->Font->ta_YSize+3
                      +4
                      +PubScreen->Font->ta_YSize
                      +4
                      +3+PubScreen->Font->ta_YSize+3
                      +2;

   CfgWindowInnerHeight=2
                        +(cfg_CfgLines+1)*PubScreen->Font->ta_YSize+4+6
                        +8
                        +PubScreen->Font->ta_YSize
                        +4
                        +3+PubScreen->Font->ta_YSize+3
                        +4
                        +PubScreen->Font->ta_YSize
                        +4
                        +3+PubScreen->Font->ta_YSize+3
                        +4
                        +PubScreen->Font->ta_YSize
                        +4
                        +3+PubScreen->Font->ta_YSize+3
                        +2;

   if(CfgWindowInnerHeight < CfgWindowMinHeight)
      CfgWindowInnerHeight=CfgWindowMinHeight;

   if(!(CfgWindow=OpenWindowTags(NULL,WA_Left,               xpos,
                                      WA_Top,                ypos,
                                      WA_InnerWidth,         cfg_CfgInnerWidth,
                                      WA_InnerHeight,        CfgWindowInnerHeight,
                                      WA_MinWidth,           200,
                                      WA_MinHeight,          100,
                                      WA_MaxWidth,           -1,
                                      WA_MaxHeight,          -1,
                                      WA_AutoAdjust,         TRUE,
                                      WA_Flags,              WFLG_SIZEGADGET|WFLG_SIZEBBOTTOM|WFLG_ACTIVATE|WFLG_CLOSEGADGET|WFLG_DEPTHGADGET|WFLG_DRAGBAR|WFLG_NEWLOOKMENUS,
                                      WA_IDCMP,              IDCMP_NEWSIZE|IDCMP_CLOSEWINDOW|LISTVIEWIDCMP|IDCMP_RAWKEY|IDCMP_MENUPICK|IDCMP_INACTIVEWINDOW,
                                      WA_Title,              getString(MAIN_MENU_EDITCOMMANDS_STR),
                                      WA_PubScreenName,      PubScreenName,
                                      WA_PubScreenFallBack,  TRUE,
                                      TAG_END)))
   {
      DisplayBeep(NULL);
      CleanUpCfg();
      return;
   }

   CfgWindowMinWidth+=MainWindow->BorderRight+MainWindow->BorderLeft;
   CfgWindowMinHeight+=MainWindow->BorderTop+MainWindow->BorderBottom;

   WindowLimits(CfgWindow,CfgWindowMinWidth,CfgWindowMinHeight,-1,-1);

   SetFont(CfgWindow->RPort,textfont);
   DrawCfgGUI();

   appwindow=(struct AppWindow *)AddAppWindow(0,NULL,CfgWindow,WBAppPort,TAG_END);

   for(;;)
   {
      sigs = Wait(1<<CfgWindow->UserPort->mp_SigBit | cxsigflag | wbsigflag | SIGBREAKF_CTRL_C | wbappsigflag);

      while(IntuiMessage=(struct IntuiMessage *)GT_GetIMsg(CfgWindow->UserPort))
      {
         class=IntuiMessage->Class;
         code=IntuiMessage->Code;
         iaddress=IntuiMessage->IAddress;
         qualifier=IntuiMessage->Qualifier;
         GT_ReplyIMsg(IntuiMessage);

         switch(class)
         {
            case IDCMP_CLOSEWINDOW:   CleanUpCfg();
                                      return;

            case IDCMP_GADGETUP:      switch(((struct Gadget *)iaddress)->GadgetID)
                                      {
                                         case CFG_LISTVIEW:
                                            cfglastnode=CommandList.lh_Head;

                                            for(c=0;c<code;c++)
                                               cfglastnode=cfglastnode->Node.ln_Succ;

                                            ActivateNode(cfglastnode);
                                            cfglastitem=code;
                                            break;
                                         case CFG_NAME:
                                            GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,~0,TAG_END);
                                            strcpy(cfglastnode->Name,getgadgetstring(namegadget));
                                            GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,&CommandList,TAG_END);
                                            break;
                                         case CFG_HOTKEY:
                                            GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,~0,TAG_END);
                                            strcpy(cfglastnode->Hotkey,getgadgetstring(hotkeygadget));
                                            GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,&CommandList,TAG_END);

                                            if(cfglastnode->Hotkey[0])
                                            {
                                               if(!(tmpobj=HotKey(cfglastnode->Hotkey,newbroker.nb_Port,0)))
                                               {
                                                  es.es_Title=getString(REQ_ERRTITLE_STR);
                                                  es.es_TextFormat=getString(ERR_INVALID_HOTKEY_STR);
                                                  es.es_GadgetFormat=getString(REQ_PROCEED_STR);
                                                  LockWindow(CfgWindow);
                                                  EasyRequest(CfgWindow,&es,NULL,cfglastnode->Hotkey);
                                                  UnLockWindow(CfgWindow);
                                                  ActivateGadget(hotkeygadget,CfgWindow,NULL);
                                               }
                                               else
                                               {
                                                  DeleteCxObj(tmpobj);
                                               }
                                            }
                                            break;
                                         case CFG_COMMAND:
                                            GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,~0,TAG_END);
                                            strcpy(cfglastnode->Command,getgadgetstring(commandgadget));
                                            GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,&CommandList,TAG_END);
                                            break;
                                         case CFG_STACK:
                                            GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,~0,TAG_END);
                                            cfglastnode->Stack=getgadgetvalue(stackgadget);
                                            GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,&CommandList,TAG_END);
                                            break;
                                         case CFG_CYCLE:
                                            GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,~0,TAG_END);

                                            if(code == 0)
                                               cfglastnode->Type=WORKBENCH;
                                            else
                                               cfglastnode->Type=CLI;

                                            GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,&CommandList,TAG_END);
                                            ActivateNode(cfglastnode);
                                            break;
                                         case CFG_DELETE:
                                            CfgDelete();
                                            break;
                                         case CFG_ADD:
                                            CfgAdd();
                                            break;
                                         case CFG_UP:
                                            CfgUp();
                                            break;
                                         case CFG_DOWN:
                                            CfgDown();
                                            break;
                                         case CFG_GETFILE:
                                            LockWindow(CfgWindow);
                                            OpenAsl(cfglastnode->Command,getString(CFG_REQ_TITLE_STR),FALSE);
                                            UnLockWindow(CfgWindow);
                                            GT_SetGadgetAttrs(commandgadget,CfgWindow,NULL,GTST_String,cfglastnode->Command,TAG_END);
                                      }
                                      break;

            case IDCMP_RAWKEY:        action=TRUE;

                                      if((code == CURSORUP && (qualifier & QUAL_SHIFT)) || code == NUMPAD_9)
                                      {
                                         if(ListViewTop(listviewgadget,CfgWindow)==cfglastitem)
                                            cfglastitem-=cfg_CfgLines-1;

                                         else
                                            cfglastitem=ListViewTop(listviewgadget,CfgWindow);

                                         if(cfglastitem<0)
                                            cfglastitem=0;
                                      }
                                      else if((code == CURSORUP && (qualifier & IEQUALIFIER_CONTROL)) || code == NUMPAD_7)
                                      {
                                         cfglastitem=0;
                                      }
                                      else if(code == CURSORUP || code == NUMPAD_8)
                                      {
                                         if(cfglastitem>0)
                                            cfglastitem--;
                                      }
                                      else if((code == CURSORDOWN && (qualifier & QUAL_SHIFT)) || code == NUMPAD_3)
                                      {
                                         if(ListViewTop(listviewgadget,CfgWindow)+cfg_CfgLines-1==cfglastitem)
                                            cfglastitem+=cfg_CfgLines-1;

                                         else
                                           cfglastitem=ListViewTop(listviewgadget,CfgWindow)+cfg_CfgLines-1;

                                         if(cfglastitem>=maxlist)
                                           cfglastitem=maxlist-1;
                                      }
                                      else if((code == CURSORDOWN && (qualifier & IEQUALIFIER_CONTROL)) || code == NUMPAD_1)
                                      {
                                         cfglastitem=maxlist-1;
                                      }
                                      else if(code == CURSORDOWN || code == NUMPAD_2)
                                      {
                                         if(cfglastitem<maxlist-1)
                                            cfglastitem++;
                                      }
                                      else
                                      {
                                         action=FALSE;
                                      }

                                      if(action)
                                      {
                                         cfglastnode=CommandList.lh_Head;

                                         for(c=0;c<cfglastitem;c++)
                                            cfglastnode=cfglastnode->Node.ln_Succ;

                                         ActivateNode(cfglastnode);

                                         GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Selected,cfglastitem,TAG_END);
                                         MakeVisible(cfglastitem,cfg_CfgLines,listviewgadget,CfgWindow);
                                      }

                                      if(code == ESC)
                                      {
                                         CleanUpCfg();
                                         return;
                                      }

                                      if(code == TAB && maxlist!=0)
                                      {
                                         ActivateGadget(namegadget,CfgWindow,NULL);
                                      }

                                      if(!action)
                                      {
                                   	     ie.ie_Class = IECLASS_RAWKEY;
                                         ie.ie_SubClass = 0;
                                         ie.ie_Code = code;
                                         ie.ie_Qualifier = qualifier;
                                         /* recover dead key codes & qualifiers */
                                         ie.ie_EventAddress = (APTR *) *((ULONG *)iaddress);
                                         actual = MapRawKey(&ie,buf,99,0);

                                         for (c = 0; c < actual; c++)
                                         {
                                            if(ToUpper(buf[c])==*getString(CFG_GAD_COMMAND_KEY) && maxlist!=0)
                                            {
                                               ActivateGadget(commandgadget,CfgWindow,NULL);
                                            }

                                            if(ToUpper(buf[c])==*getString(CFG_GAD_HOTKEY_KEY) && maxlist!=0)
                                            {
                                               ActivateGadget(hotkeygadget,CfgWindow,NULL);
                                            }

                                            if(ToUpper(buf[c])==*getString(CFG_GAD_STACK_KEY) && maxlist!=0)
                                            {
                                               if(cfglastnode->Type == CLI)
                                                  ActivateGadget(stackgadget,CfgWindow,NULL);
                                            }

                                            if(ToUpper(buf[c])==*getString(CFG_GAD_ADD_KEY))
                                            {
                                               if(FakePress(addgadget,CfgWindow,code))
                                                  CfgAdd();
                                            }

                                            if(ToUpper(buf[c])==*getString(CFG_GAD_DELETE_KEY) && maxlist!=0)
                                            {
                                               if(FakePress(deletegadget,CfgWindow,code))
                                                  CfgDelete();
                                            }

                                            if(ToUpper(buf[c])==*getString(CFG_GAD_UP_KEY) && maxlist!=0)
                                            {
                                               if(cfglastnode!=(struct MyNode *)CommandList.lh_Head)
                                                  if(FakePress(upgadget,CfgWindow,code))
                                                     CfgUp();
                                            }

                                            if(ToUpper(buf[c])==*getString(CFG_GAD_DOWN_KEY) && maxlist!=0)
                                            {
                                               if(cfglastnode!=(struct MyNode *)CommandList.lh_TailPred)
                                                  if(FakePress(downgadget,CfgWindow,code))
                                                     CfgDown();
                                            }

                                            if(ToUpper(buf[c])==*getString(CFG_GAD_TYPE_KEY) && maxlist!=0)
                                            {
                                               if(FakePress(cyclegadget,CfgWindow,code))
                                               {
                                                  if(cfglastnode->Type==WORKBENCH)
                                                  {
                                                     cfglastnode->Type=CLI;
                                                     code=1;
                                                  }
                                                  else
                                                  {
                                                     cfglastnode->Type=WORKBENCH;
                                                     code=0;
                                                  }
                                                  ActivateNode(cfglastnode);
                                               }
                                            }
                                         }
                                      }
                                      break;

            case IDCMP_NEWSIZE:       RemoveGList(CfgWindow,cfgglist,-1);
                                      FreeGadgets(cfgglist);
                                      DisposeObject(getfileimg);
                                      Move(CfgWindow->RPort,0,0);
                                      ClearScreen(CfgWindow->RPort);
                                      RefreshWindowFrame(CfgWindow);
                                      DrawCfgGUI();
                                      break;

            case IDCMP_REFRESHWINDOW: GT_BeginRefresh(CfgWindow);
                                      GT_EndRefresh(CfgWindow,TRUE);
         }
      }

      if(sigs & wbsigflag)
      {
         ProcessWorkbench();
      }

      if(sigs & SIGBREAKF_CTRL_C)
      {
         if(MayExit())
         {
            CleanUpCfg();
            CleanUpMain();
            CleanUp(0);
         }
      }

      if(sigs & wbappsigflag)
      {
         action=FALSE;

         while(appmsg = (struct AppMessage *)GetMsg(WBAppPort))
         {
            if(appmsg->am_Type == AMTYPE_APPMENUITEM)
               action=TRUE;

            if(appmsg->am_Type = AMTYPE_APPWINDOW)
            {
               arglist=appmsg->am_ArgList;

               for(c=0;c<appmsg->am_NumArgs;c++)
               {
                  olddir=CurrentDir(arglist->wa_Lock);

                  if(l=Lock(arglist->wa_Name,SHARED_LOCK))
                  {
                     Examine(l,cfgfib);

                     if(cfgfib->fib_DirEntryType < 0)
                     {
                        if(mynode=(struct MyNode *)AllocMem(sizeof(struct MyNode),MEMF_CLEAR))
                        {
                           GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,~0,TAG_END);
                           mynode->Stack=4000;
                           NameFromLock(l,mynode->Command,199);
                           strncpy(mynode->Name,FilePart(mynode->Command),39);
                           mynode->Name[39]=0;
                           mynode->Node.ln_Name=mynode->Name;

                           if(dobj=GetDiskObject(mynode->Command))
                           {
                              mynode->Type=WORKBENCH;
                              FreeDiskObject(dobj);
                           }
                           else
                           {
                              mynode->Type=CLI;
                           }

                           AddTail(&CommandList,(struct Node *)mynode);
                           maxlist++;
                           cfglastitem=maxlist-1;
                           cfglastnode=CommandList.lh_TailPred;
                           CfgEnableAll();
                           GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Labels,&CommandList,TAG_END);
                           GT_SetGadgetAttrs(listviewgadget,CfgWindow,NULL,GTLV_Selected,cfglastitem,TAG_END);
                           MakeVisible(cfglastitem,cfg_CfgLines,listviewgadget,CfgWindow);
                           ActivateNode(cfglastnode);
                           ActivateGadget(namegadget,CfgWindow,NULL);
                        }
                        else
                        {
                           DisplayBeep(NULL);
                        }
                     }

                     UnLock(l);
                  }

                  CurrentDir(olddir);
                  arglist++;
               }
            }

            ReplyMsg((struct Message *)appmsg);
         }

         if(action)
         {
            Appear();
         }
      }

      if(sigs & cxsigflag)
      {
         HandleCx();

         if(!CfgWindow)
            return;
      }
   }
}

/* Fakepress */

/*

   Returns FALSE if the press was interrupted with either shift key,
   otherwise returns TRUE. The window should have the IDCMP_INACTIVEWINDOW
   flag set or the routine won't work properly if the window is deactivated
   before the key is released.

   Don't forget to specify the _raw_ keycode.

*/

/* Rawcodes for the shiftkeys */

#define LEFTSHIFT   0x60
#define RIGHTSHIFT  0x61

BOOL FakePress(struct Gadget *gad,struct Window *win,UBYTE rawcode)
{
   BOOL kg,res,shift;
   struct IntuiMessage *msg;

   /* Draw the selected image */

   gad->Flags|=GFLG_SELECTED;
   RefreshGList(gad,win,NULL,1);

   kg=TRUE;
   shift=FALSE;

   /* Main loop */

   while(kg)
   {
      WaitPort(win->UserPort);

      while(msg=(struct IntuiMessage *)GetMsg(win->UserPort))
      {
         /* Key released */

         if(msg->Class == IDCMP_RAWKEY && msg->Code == rawcode+128)
         {
            res=TRUE;
            kg=FALSE;
         }

         /* Shift key pressed */

         if(msg->Class == IDCMP_RAWKEY && (msg->Code==LEFTSHIFT || msg->Code==RIGHTSHIFT))
         {
            shift=TRUE;
            res=FALSE;
            kg=FALSE;
         }

         /* Window deactivated */

         if(msg->Class == IDCMP_INACTIVEWINDOW)
         {
            res=FALSE;
            kg=FALSE;
         }

         ReplyMsg((struct Message *)msg);
      }
   }

   /* Draw normal image */

   gad->Flags&=~GFLG_SELECTED;
   RefreshGList(gad,win,NULL,1);

   /* Wait for the key to be released if it was aborted with shift */

   if(shift)
   {
      kg=TRUE;

      while(kg)
      {
         WaitPort(win->UserPort);

         while(msg=(struct IntuiMessage *)GetMsg(win->UserPort))
         {
            if(msg->Class == IDCMP_RAWKEY && msg->Code == rawcode+128)
               kg=FALSE;

            ReplyMsg((struct Message *)msg);
         }
      }
   }

   return(res);
}

/* LockWindow med busypointer... */

__chip UWORD WaitPointer[] =
{
    0x0000, 0x0000,

    0x0400, 0x07C0,
    0x0000, 0x07C0,
    0x0100, 0x0380,
    0x0000, 0x07E0,
    0x07C0, 0x1FF8,
    0x1FF0, 0x3FEC,
    0x3FF8, 0x7FDE,
    0x3FF8, 0x7FBE,
    0x7FFC, 0xFF7F,
    0x7EFC, 0xFFFF,
    0x7FFC, 0xFFFF,
    0x3FF8, 0x7FFE,
    0x3FF8, 0x7FFE,
    0x1FF0, 0x3FFC,
    0x07C0, 0x1FF8,
    0x0000, 0x07E0,

    0x0000, 0x0000,		/* reserved, must be NULL */
};

struct MinMaxStruct
{
   ULONG MinWidth,MinHeight,MaxWidth,MaxHeight;
};

BOOL LockWindow(struct Window *win)
{
   struct Requester *req;
   struct MinMaxStruct *mm;

   if(!(mm=AllocMem(sizeof(struct MinMaxStruct),MEMF_ANY)))
   {
      return(FALSE);
   }

   mm->MinWidth=win->MinWidth;
   mm->MaxWidth=win->MaxWidth;
   mm->MinHeight=win->MinHeight;
   mm->MaxHeight=win->MaxHeight;

   win->UserData=mm;

   if(!(req=AllocMem(sizeof(struct Requester),MEMF_CLEAR)))
   {
      FreeMem(mm,sizeof(struct MinMaxStruct));
      return(FALSE);
   }

   req->Flags=NOREQBACKFILL|SIMPLEREQ;

   if(!(Request(req,win)))
   {
      FreeMem(mm,sizeof(struct MinMaxStruct));
      FreeMem(req,sizeof(struct Requester));
      return(FALSE);
   }

   if(IntuitionBase->LibNode.lib_Version < 39)
		SetPointer(win, WaitPointer, 16, 16, -6, 0);

   else
      SetWindowPointer(win,WA_BusyPointer,TRUE,TAG_END);

   WindowLimits(win,win->Width,win->Height,win->Width,win->Height);

   return(TRUE);
}

void UnLockWindow(struct Window *win)
{
   struct Requester *req;
   struct MinMaxStruct *mm;

   req=win->FirstRequest;

   if(!req)
      return;

   EndRequest(req,win);

   if(win->UserData)
   {
      mm=win->UserData;

/*
      win->MinWidth=mm->MinWidth;
      win->MaxWidth=mm->MaxWidth;
      win->MinHeight=mm->MinHeight;
      win->MaxHeight=mm->MaxHeight;
*/

      WindowLimits(win,mm->MinWidth,mm->MinHeight,mm->MaxWidth,mm->MaxHeight);

      FreeMem(mm,sizeof(struct MinMaxStruct));
      win->UserData=NULL;
   }

   FreeMem(req,sizeof(struct Requester));

   ClearPointer(win);
}


/* ASL filerequester */

BOOL OpenAsl(UBYTE *file,UBYTE *title,BOOL save)
{
   APTR aslreq;
   UBYTE path[200],name[100];
   BOOL res;

   strcpy(path,file);
   *PathPart(path)=0;

   strcpy(name,FilePart(file));

   aslreq=AllocAslRequestTags(ASL_FileRequest,ASLFR_TitleText,title,
                                              ASLFR_InitialFile,name,
                                              ASLFR_InitialDrawer,path,
                                              ASLFR_DoSaveMode,save,
                                              ASLFR_RejectIcons,TRUE,TAG_END);

   if(!aslreq)
   {
      DisplayBeep(NULL);
      return(FALSE);
   }

   LockWindow(MainWindow);

   res=AslRequestTags(aslreq,ASLFR_Window,MainWindow,
                             TAG_END);

   UnLockWindow(MainWindow);
   FreeAslRequest(aslreq);

   if(res)
   {
      strncpy(file,((struct FileRequester *)aslreq)->fr_Drawer,299);
      file[299]=0;
      AddPart(file,((struct FileRequester *)aslreq)->fr_File,299);
   }

   return(res);
}



/*


Snott:
------
Yak OpenWindow
ListViewTop (Bryce Dawson)
Commodity startup
WorkbenchRun
GTB
WB2CLI

Features:
---------
Cursor keys/Numpad
Open on pubscreen
CON: on pubscreen
Öppnar under muspekaren
Resizable listview och config
Lokaliserad
%s passing
AppMenu
Config
AppWindow

Beta 2
------
Klarar nu 200 tecken långa kommandon
Menyer
Stack
Kommer ihåg senaste
 Öppna/Stäng gränssnitt funkar
 Om man trycker hotkeyn/startar programmet/väljer Visa gränssnitt så flyttas
 ett redan öppnat gränssnitt fram
Öppnar nu requesters på rätt skärm
PgUp/PgDn/End/Home/Up/Down

Beta 3
------
CopyPath
2.04-kompatibelt
AppMenu
Äntligen kompatibelt med 2.04
Config
Tar hänsyn till ToolType:n TOOLPRI

Beta 4
------
Bättre simulering av tangentbordet
Går ej att resiza när fönstret är låst

*/



/*

Nästa version:
--------------
Multithreaded
Flera listor
Alt-Tab byta skärm för fönstret

Öppna lista från lista
   Enskilda hotkeys för oliak entries
   FirstScreen istället för ActiveScreen

   Kolla hotkey när den skrivs...
   Center...

   leta efter config på andra ställen
   Installerscript

   Lockup vid start med falsk hotkey och sen start? Hmm. Felaktig config finns.
   Kolla språk
*/
