/*
 * WBPrinter - Put a printer icon on the workbench screen
 * 
 *
 * Copyright (c) 1992, Mike Ruble
 *
 * Permission is hereby granted to distribute this program for any purposes
 * whatsoever, so long as this notice, including the above copyright, is
 * included with the distribution.
 *
 * 04/25/92 Written by Mike Ruble using SAS (Lattice) C 5.10b
 *
 */


#include "WBPrinter.h"


/********** Code begins **********/
void main(int argc, char *argv)
{

/* First make sure we are running from Workbench */
   if(argc)
      exit(0);

/* Then see if WBPrinter is already running */
   if(FindPort("WBPrinter"))
      exit(0);


/* Close any stdio files that might be open */
   if(stdin) fclose(stdin);
   if(stderr) fclose(stderr);

   SetUp();
   StartPrintTask();
   Do_MainFunc();
   done(0);
}


void Do_MainFunc(void)
{
   BPTR                  infile,
                         outfile,
                         oldcd;
   char                 *Copybuffer;
   struct FileNode      *namenode;
   struct AppMessage    *amsg;
   struct WBArg         *argptr;
   struct FileRequester *FileReq;
   int                   bytesread;
   int                   quit;
   int                   i;

   quit = 0;
   filecount = 1;

   while(!quit)
   {
      WaitPort(AppPort);
      while ((amsg = (struct AppMessage *)GetMsg(AppPort)) != NULL)
      {
         if (amsg->am_NumArgs == 0)
         {
            ObtainSemaphore(print_q_semaphore);
            quit = Do_AppWindow();
            ReleaseSemaphore(print_q_semaphore);
            break;
         }
         argptr = amsg->am_ArgList;
         if(!spooldir)
         {
            FileReq = AllocAslRequestTags(ASL_FileRequest,
                              ASL_Hail, &"CHOOSE SPOOL DIRECTORY",
                              ASL_Window, Wnd,
                              ASL_Dir, spooldir,
                              ASL_ExtFlags1, FIL1F_NOFILES,
                              TAG_DONE);

            if(FileReq)
            {
               if(AslRequest(FileReq, NULL))
               {
                  spooldir = AllocMem(strlen(((struct FileRequester *)FileReq)->rf_Dir) + 1, MEMORY_TYPE);
                  if(!spooldir)
                     break;
                  strcpy(spooldir,
                      ((struct FileRequester *)FileReq)->rf_Dir);
               };
               FreeAslRequest(FileReq);
               FileReq = NULL;
            };
         };
         for (i = 0; i < amsg->am_NumArgs; i++)
         {
            if (*(argptr->wa_Name))
            {
               if((namenode = 
                     (struct FileNode *)AllocMem(sizeof(struct FileNode),
                     MEMORY_TYPE)) == NULL)
               {
                  break;
               };
               if((namenode->nn_Node.ln_Name =
                     (char *)AllocMem(strlen(argptr->wa_Name)+1,
                     MEMORY_TYPE)) == NULL)
               {
                  break;
               };
               namenode->nn_Node.ln_Type = PRINT_FILE;
               strcpy(namenode->nn_Node.ln_Name, argptr->wa_Name);
               sprintf(Name_Buffer, "%s%ld", FilePrefix, filecount);
               if((namenode->nn_SpooledName =
                     (char *)AllocMem(strlen(Name_Buffer)+1,
                     MEMORY_TYPE)) == NULL)
               {
                  break;
               };
               strcpy(namenode->nn_SpooledName, Name_Buffer);
               strcpy(Name_Buffer, spooldir);
               AddPart(Name_Buffer, namenode->nn_SpooledName, 255);

               oldcd = CurrentDir(argptr->wa_Lock);
               infile = Open(argptr->wa_Name, MODE_OLDFILE);
               if(infile == NULL)
               {
                  break;
               };
               outfile = Open(Name_Buffer, MODE_NEWFILE);
               if(outfile == NULL)
               {
                  Close(infile);
                  break;
               };
               if((Copybuffer =
                    (char *)AllocMem(8192, MEMORY_TYPE)) == NULL)
               {
                  Close(infile);
                  Close(outfile);
                  break;
               };
               do
               {
                  bytesread = Read(infile, Copybuffer, 8192);
                  Write(outfile, Copybuffer, bytesread);
               }
               while(bytesread == 8192);
               Close(infile);
               Close(outfile);
               FreeMem(Copybuffer, 8192);
               CurrentDir(oldcd);

               ObtainSemaphore(print_q_semaphore);
               AddTail(Print_Q, (struct Node *)namenode);
               ReleaseSemaphore(print_q_semaphore);
               filecount ++;
            }
            argptr++;
         }
         Tell_Print_Task(PRINTS_READY);
         ReplyMsg((struct Message *) amsg);
      }
   }
   WaitPort(start_msg->msg.mn_ReplyPort);
   GetMsg(start_msg->msg.mn_ReplyPort);
   DeletePort(start_msg->msg.mn_ReplyPort);
   FreeMem(start_msg, sizeof(struct ProcMsg));
   Clear_Print_Q();
}


/*
 * SetUp - Allocate memory and open Libraries
 */
void SetUp(void)
{
   struct Task  *Me;
   char         *tooltype;
   LONG          icon_left,
                 icon_top;


   window_top = window_left = 0;

/* Initialize print List */
   Print_Q =
         (struct List *)AllocMem(sizeof(struct List),
                                 MEMORY_TYPE);
   if(!Print_Q)
      done(20);
   NewList(Print_Q);

/* Initialize Semaphore */
   print_q_semaphore =
         (struct SignalSemaphore *)AllocMem(sizeof(struct SignalSemaphore),
                                            MEMORY_TYPE);
   if(!print_q_semaphore)
      done(20);
   InitSemaphore(print_q_semaphore);

/* get space for preferences */
   prefs = (struct Preferences *)
      AllocMem((ULONG)sizeof(struct Preferences), MEMORY_TYPE);
   if(!prefs)
      done(20);

/* Open libraries */
   IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 36L);
   if(IntuitionBase == NULL)
      done(20);

   GfxBase = OpenLibrary("graphics.library", 36L);
   if(GfxBase == NULL)
      done(20);

   IconBase = OpenLibrary("icon.library", 36L);
   if(IconBase == NULL)
      done(20);

   WorkbenchBase = OpenLibrary("workbench.library", 36L);
   if(WorkbenchBase == NULL)
      done(20);

   AslBase = OpenLibrary("asl.library", 36L);
   if(AslBase == NULL)
      done(20);

/* Create port for AppIcon */
   AppPort = CreatePort("WBPrinter", 0L);
   if(AppPort == NULL)
      done(20);

/* Try to find my icon */
   Me = FindTask(NULL);

   icon = GetDiskObject((char *)Me->tc_Node.ln_Name);
   if(icon == NULL)
      done(20);

/* find out which directory to use for spooling */
   spooldir = NULL;
   tooltype = FindToolType(icon->do_ToolTypes, "SPOOLDIR");
   if(!tooltype)
      tooltype = (char *)&"RAM:";
   spooldir = AllocMem(strlen(tooltype) + 1, MEMORY_TYPE);
   if(spooldir);
      strcpy(spooldir, tooltype);

/* let's see about Skip Perf and Page Eject */
   tooltype = FindToolType(icon->do_ToolTypes, "SKIP_PERF");
   if(tooltype)
   {
      if(stricmp(tooltype, "FALSE"))
         PrtPrefs.pp_SkipPerf = TRUE;
      else
         PrtPrefs.pp_SkipPerf = FALSE;
   }
   else
      PrtPrefs.pp_SkipPerf = TRUE;
   tooltype = FindToolType(icon->do_ToolTypes, "EJECT_PAGE");
   if(tooltype)
   {
      if(stricmp(tooltype, "FALSE"))
         PrtPrefs.pp_EjectPage = TRUE;
      else
         PrtPrefs.pp_EjectPage = FALSE;
   }
   else
      PrtPrefs.pp_EjectPage = TRUE;

/* let's see where the user wants to put the icon */
   icon_left = NO_ICON_POSITION;
   icon_top  = NO_ICON_POSITION;
   tooltype = FindToolType(icon->do_ToolTypes, "ICON_LEFT_EDGE");
   if(tooltype)
      icon_left = atol(tooltype);
   tooltype = FindToolType(icon->do_ToolTypes, "ICON_TOP_EDGE");
   if(tooltype)
      icon_top = atol(tooltype);

/* see if the user wants to use a different icon */
   tooltype = FindToolType(icon->do_ToolTypes, "ICON");

   if(tooltype)
   {
      icon = GetDiskObject(tooltype);
      if(icon == NULL)
         done(20);
   };

   icon->do_CurrentX = icon_left;
   icon->do_CurrentY = icon_top;

   Appicon = AddAppIconA(0, 0, "Printer", AppPort, NULL, icon, NULL);
   if(Appicon == NULL)
      done(20);

   GetPrefs(prefs, sizeof(struct Preferences));

   if(prefs->PrintSpacing == SIX_LPI)
      PrtPrefs.pp_LinesPerInch = 0;
   else
      PrtPrefs.pp_LinesPerInch = 1;

   if(prefs->PrintQuality)
      PrtPrefs.pp_PrintQuality = 1;
   else
      PrtPrefs.pp_PrintQuality = 0;

   if(prefs->PrintPitch == PICA)
      PrtPrefs.pp_PrintPitch = 0;
   if(prefs->PrintPitch == ELITE)
      PrtPrefs.pp_PrintPitch = 1;
   if(prefs->PrintPitch == FINE)
      PrtPrefs.pp_PrintPitch = 2;

   PrtPrefs.pp_LeftMargin = (UWORD)prefs->PrintLeftMargin;

   PrtPrefs.pp_RightMargin = (UWORD)prefs->PrintRightMargin;

   return;
}


/*
 * Send a message to the print task
 */
void Tell_Print_Task(WORD tell)
{
   struct PrtMsg   *mess;
   struct MsgPort  *tport;
   struct MsgPort  *rport;


   tport = FindPort("WBPrinter Printer");
   if(!tport)
      return;

   rport = CreatePort(NULL, NULL);
   if(!rport)
      return;

   mess = (struct PrtMsg *)AllocMem(sizeof(struct PrtMsg), MEMORY_TYPE);
   if(!mess)
   {
      DeletePort(rport);
      return;
   };

   mess->pm_Command = tell;
   mess->pm_Message.mn_Node.ln_Type = NT_MESSAGE;
   mess->pm_Message.mn_ReplyPort    = rport;
   mess->pm_Message.mn_Length       = 2;

   PutMsg(tport, (struct Message *)mess);
   WaitPort(rport);
   GetMsg(rport);

   FreeMem(mess, sizeof(struct PrtMsg));
   DeletePort(rport);

   return;
}


/*
 * Clear_Print_Q - remove all unprinted files from spool dir 
 *                 and free list nodes.
 */
void Clear_Print_Q(void)
{
   BPTR             lock,
                    oldcd;

   struct FileNode *fn;

   lock = Lock(spooldir, ACCESS_READ);
   if(!lock)
      return;

   oldcd = CurrentDir(lock);

   while(fn = (struct FileNode *)RemHead(Print_Q))
   {
      DeleteFile(fn->nn_SpooledName);
      FreeMem(fn->nn_SpooledName, (strlen(fn->nn_SpooledName) + 1));
      FreeMem(fn->nn_Node.ln_Name, (strlen(fn->nn_Node.ln_Name) + 1));
      FreeMem(fn, sizeof(struct FileNode));
   }

   CurrentDir(oldcd);
}


/*
 * done - just clean up that which is open, and then leave.
 */
void done(int how)
{

   if(Appicon) RemoveAppIcon(Appicon);
   if(AppPort) DeletePort(AppPort);
   if(icon) FreeDiskObject(icon);
   if(IconBase) CloseLibrary(IconBase);
   if(GfxBase) CloseLibrary(GfxBase);
   if(WorkbenchBase) CloseLibrary(WorkbenchBase);
   if(AslBase) CloseLibrary(AslBase);
   if(prefs) FreeMem(prefs, sizeof(struct Preferences));

   if(IntuitionBase)
   {
      OpenWorkBench();         /* As requested */
      CloseLibrary((struct Library *)IntuitionBase);
   };

   if(Print_Q) FreeMem(Print_Q, sizeof(struct List));
   if(print_q_semaphore) FreeMem(print_q_semaphore, sizeof(struct SignalSemaphore));
   if(spooldir) FreeMem(spooldir, strlen(spooldir) + 1);

   exit(how);
}


int Do_AppWindow(void)
{
   struct IntuiMessage  *IMsg;
   struct Gadget        *Gad;
   struct FileNode      *fn;
   struct FileRequester *FileReq;
   WORD                  selected;
   int                   i;


   if(Make_AppWindow())
      return(0);

   selected = -1;
   while(1)
   {
      WaitPort(Wnd->UserPort);
      while(IMsg = GT_GetIMsg(Wnd->UserPort))
      {
         if(IMsg->Class == IDCMP_CLOSEWINDOW)
         {
            GT_ReplyIMsg(IMsg);
            Remove_AppWindow();
            return(0);
         };
         if(IMsg->Class == IDCMP_GADGETUP)
         {
            Gad = (struct Gadget *)(IMsg->IAddress);
            switch(Gad->GadgetID)
            {
               case GD_LPI_Gad:
                  PrtPrefs.pp_LinesPerInch = IMsg->Code;
                  break;

               case GD_Skip_Perf_Gad:
                  if(Gad->Flags & SELECTED)
                     PrtPrefs.pp_SkipPerf = 1;
                  else
                     PrtPrefs.pp_SkipPerf = 0;
                  break;

               case GD_Page_Eject_Gad:
                  if(Gad->Flags & SELECTED)
                     PrtPrefs.pp_EjectPage = TRUE;
                  else
                     PrtPrefs.pp_EjectPage = FALSE;
                  break;

               case GD_Quality_Gad:
                  PrtPrefs.pp_PrintQuality = IMsg->Code;
                  break;

               case GD_Pitch_Gad:
                  PrtPrefs.pp_PrintPitch = IMsg->Code;
                  break;

               case GD_L_Marg_Gad:
                  PrtPrefs.pp_LeftMargin =
                     (UWORD)((struct StringInfo *)(Gad->SpecialInfo))->LongInt;
                  break;

               case GD_R_Marg_Gad:
                  PrtPrefs.pp_RightMargin =
                     (UWORD)((struct StringInfo *)(Gad->SpecialInfo))->LongInt;
                  break;

               case GD_Pref_Gad:
                  GetPrefs(prefs, sizeof(struct Preferences));
                  if(prefs->PrintSpacing == SIX_LPI)
                     PrtPrefs.pp_LinesPerInch = 0;
                  else
                     PrtPrefs.pp_LinesPerInch = 1;
                  if(prefs->PrintQuality)
                     PrtPrefs.pp_PrintQuality = 1;
                  else
                     PrtPrefs.pp_PrintQuality = 0;
                  if(prefs->PrintPitch == PICA)
                     PrtPrefs.pp_PrintPitch = 0;
                  if(prefs->PrintPitch == ELITE)
                     PrtPrefs.pp_PrintPitch = 1;
                  if(prefs->PrintPitch == FINE)
                     PrtPrefs.pp_PrintPitch = 2;
                  PrtPrefs.pp_LeftMargin  = (UWORD)prefs->PrintLeftMargin;
                  PrtPrefs.pp_RightMargin = (UWORD)prefs->PrintRightMargin;
                  GT_SetGadgetAttrs(Gadgets[GD_LPI_Gad], Wnd, NULL,
                                 GTCY_Active, (ULONG)PrtPrefs.pp_LinesPerInch,
                                 TAG_DONE);
                  GT_SetGadgetAttrs(Gadgets[GD_Quality_Gad], Wnd, NULL,
                                 GTCY_Active, (ULONG)PrtPrefs.pp_PrintQuality,
                                 TAG_DONE);
                  GT_SetGadgetAttrs(Gadgets[GD_Pitch_Gad], Wnd, NULL,
                                 GTCY_Active, (ULONG)PrtPrefs.pp_PrintPitch,
                                 TAG_DONE);
                  GT_SetGadgetAttrs(Gadgets[GD_L_Marg_Gad], Wnd, NULL,
                                 GTIN_Number, (ULONG)PrtPrefs.pp_LeftMargin,
                                 TAG_DONE);
                  GT_SetGadgetAttrs(Gadgets[GD_R_Marg_Gad], Wnd, NULL,
                                 GTIN_Number, (ULONG)PrtPrefs.pp_RightMargin,
                                 TAG_DONE);
                  GT_RefreshWindow(Wnd, NULL);
                  break;

               case GD_Spool_Gad:
                  FileReq = AllocAslRequestTags(ASL_FileRequest,
                                    ASL_Hail, &"CHOOSE SPOOL DIRECTORY",
                                    ASL_Window, Wnd,
                                    ASL_Dir, spooldir,
                                    ASL_ExtFlags1, FIL1F_NOFILES,
                                    TAG_DONE);

                  if(FileReq)
                  {
                     if(AslRequest(FileReq, NULL))
                     {
                        if(spooldir)
                           FreeMem(spooldir, strlen(spooldir) + 1);
                        spooldir = AllocMem(strlen(FileReq->rf_Dir) + 1, MEMORY_TYPE);
                        if(!spooldir)
                           break;
                        strcpy(spooldir,
                            ((struct FileRequester *)FileReq)->rf_Dir);
                     };
                     FreeAslRequest(FileReq);
                     FileReq = NULL;
                  };
                  break;

               case GD_Next_Gad:
                  if(selected >= 0)
                  {
                     i = 0;
                     ObtainSemaphore(print_q_semaphore);
                     for(fn = (struct FileNode *)Print_Q->lh_Head;
                         i++ < selected;
                         fn = (struct FileNode *)fn->nn_Node.ln_Succ);
                     if(fn->nn_Node.ln_Type == PRINT_FILE)
                     {
                        Remove((struct Node *)fn);
                        if(Print_Q->lh_Head->ln_Type == PRINT_FILE)
                        {
                           AddHead(Print_Q, (struct Node *)fn);
                           selected = 0;
                        }
                        else
                        {
                           Insert(Print_Q, (struct Node *)fn, Print_Q->lh_Head);
                           selected = 1;
                        };
                        GT_SetGadgetAttrs(Gadgets[GD_Job_List_Gad], Wnd, NULL,
                                          GTLV_Selected, (ULONG)selected,
                                          TAG_DONE);
                     }
                     GT_RefreshWindow(Wnd, NULL);
                     ReleaseSemaphore(print_q_semaphore);
                  };
                  break;

               case GD_Cancel_Gad:
                  if(selected >= 0)
                  {
                     i = 0;
                     ObtainSemaphore(print_q_semaphore);
                     for(fn = (struct FileNode *)Print_Q->lh_Head;
                         i++ < selected;
                         fn = (struct FileNode *)fn->nn_Node.ln_Succ);
                     if(fn->nn_Node.ln_Type == PRINTING_FILE)
                        Tell_Print_Task(CANCEL_PRINT);
                     Remove((struct Node *)fn);
                     if(fn->nn_Node.ln_Type != PRINTING_FILE)
                     {
                        strcpy(Name_Buffer, spooldir);
                        AddPart(Name_Buffer, fn->nn_SpooledName, 255);
                        DeleteFile(Name_Buffer);
                     };
                     FreeMem(fn->nn_SpooledName,
                            (strlen(fn->nn_SpooledName) + 1));
                     FreeMem(fn->nn_Node.ln_Name,
                            (strlen(fn->nn_Node.ln_Name) + 1));
                     FreeMem(fn, sizeof(struct FileNode));

                     GT_SetGadgetAttrs(Gadgets[GD_Job_List_Gad], Wnd, NULL,
                                       GTLV_Selected, (ULONG)~0,
                                       TAG_DONE);
                     GT_RefreshWindow(Wnd, NULL);
                     ReleaseSemaphore(print_q_semaphore);
                  };
                  break;

               case GD_Job_List_Gad:
                  selected = IMsg->Code;
                  break;

               case GD_Quit_Gad:
                  GT_ReplyIMsg(IMsg);
                  Tell_Print_Task(CANCEL_AND_DIE);
                  Remove_AppWindow();
                  return(20);
                  break;
            };
         };
         GT_ReplyIMsg(IMsg);
      };
   };
}

/*
 *  Source generated with GadToolsBox V1.0
 *  which is (c) Copyright 1991 Jaba Development
 *
 *
 *  Source modified by Mike Ruble to handle dynamic gadget placements
 *  and sizes based on the current screen font.
 *
 */
int Make_AppWindow( void )
{
    struct NewGadget     ng;
    struct Gadget       *g;
    WORD                 button_height;
    WORD                 integer_height;
    WORD                 gadget_top;
    WORD                 gadget_width;
    WORD                 integer_width;


    GadToolsBase  = OpenLibrary("gadtools.library", 36L);
    if(!GadToolsBase)
       return(20);

/* Get address of Default Public Screen */
    if ( NOT( Scr = LockPubScreen( NULL )))
        return( 1l );

/* Set Screen address for Window */
    WindowTags[ 8 ].ti_Data = (ULONG)Scr;

/* Set Gadget heights based on text height */
    button_height  = (Scr->Font)->ta_YSize + 4;
    integer_height = button_height + 1;

/* where Gadgets should begin - also based on font height */
    gadget_top     = button_height + 1;

/* determine width for gadgets by finding pixel length of longest string */
    gadget_width   = (WORD)TextLength(&(Scr->RastPort), "Set Spool Directory", 19);
    gadget_width  += 10;
    integer_width  = (WORD)TextLength(&(Scr->RastPort), "MMMM", 4);
    integer_width += 12;

/* alter window size and position to fit gadgets */
    WindowTags[ 2 ].ti_Data = (LONG)((gadget_width * 2) + 34);
    WindowTags[ 3 ].ti_Data = (LONG)((button_height * 7) + (integer_height * 2)
                                     + gadget_top + 25);
    if(window_left)
       WindowTags[ 0 ].ti_Data = window_left;
    else
       WindowTags[ 0 ].ti_Data = (ULONG)((struct IntuitionBase *)IntuitionBase)->MouseX + 100;
    if(window_top)
       WindowTags[ 1 ].ti_Data = window_top;
    else
       WindowTags[ 1 ].ti_Data = (ULONG)((struct IntuitionBase *)IntuitionBase)->MouseY - (WindowTags[ 3 ].ti_Data / 2);

    if ( NOT( VisualInfo = GetVisualInfo( Scr, TAG_DONE )))
        return( 2l );

    if ( NOT( g = CreateContext( &GList )))
        return( 3l );

    ng.ng_LeftEdge        =    12;
    ng.ng_TopEdge         =    gadget_top;
    ng.ng_Width           =    gadget_width;
    ng.ng_Height          =    button_height;
    ng.ng_GadgetText      =    0l;
    ng.ng_TextAttr        =    Scr->Font;
    ng.ng_GadgetID        =    GD_LPI_Gad;
    ng.ng_Flags           =    0;
    ng.ng_VisualInfo      =    VisualInfo;

    g = CreateGadget( CYCLE_KIND, g, &ng, GTCY_Labels, LPI_GadLabels,
                                          GTCY_Active, (ULONG)PrtPrefs.pp_LinesPerInch,
                                          TAG_DONE );

    Gadgets[GD_LPI_Gad] = g;

    ng.ng_TopEdge         +=   button_height;
    ng.ng_GadgetText      =    0l;
    ng.ng_GadgetID        =    GD_Quality_Gad;

    g = CreateGadget( CYCLE_KIND, g, &ng, GTCY_Labels, Quality_GadLabels,
                                          GTCY_Active, (ULONG)PrtPrefs.pp_PrintQuality,
                                          TAG_DONE );

    Gadgets[GD_Quality_Gad] = g;

    ng.ng_TopEdge         +=   button_height;
    ng.ng_GadgetText      =    0l;
    ng.ng_GadgetID        =    GD_Pitch_Gad;

    g = CreateGadget( CYCLE_KIND, g, &ng, GTCY_Labels, Pitch_GadLabels,
                                          GTCY_Active, (ULONG)PrtPrefs.pp_PrintPitch,
                                          TAG_DONE );

    Gadgets[GD_Pitch_Gad] = g;

    ng.ng_LeftEdge        +=   (gadget_width - integer_width);
    ng.ng_TopEdge         +=   (button_height + 5);
    ng.ng_Width           =    integer_width;
    ng.ng_Height          =    integer_height;
    ng.ng_GadgetText      =    "Left  Margin:";
    ng.ng_GadgetID        =    GD_L_Marg_Gad;
    ng.ng_Flags           =    PLACETEXT_LEFT;

    g = CreateGadget( INTEGER_KIND, g, &ng, GTIN_Number, (ULONG)PrtPrefs.pp_LeftMargin,
                                            GTIN_MaxChars, 10,
                                            TAG_DONE );

    Gadgets[GD_L_Marg_Gad] = g;

    ng.ng_TopEdge         +=   integer_height;
    ng.ng_GadgetText      =    "Right Margin:";
    ng.ng_GadgetID        =    GD_R_Marg_Gad;

    g = CreateGadget( INTEGER_KIND, g, &ng, GTIN_Number, (ULONG)PrtPrefs.pp_RightMargin,
                                            GTIN_MaxChars, 10,
                                            TAG_DONE );

    Gadgets[GD_R_Marg_Gad] = g;

    ng.ng_LeftEdge        =    12;
    ng.ng_TopEdge         +=   (integer_height + 5);
    ng.ng_Width           =    gadget_width;
    ng.ng_Height          =    button_height;
    ng.ng_GadgetText      =    "From Preferences";
    ng.ng_GadgetID        =    GD_Pref_Gad;
    ng.ng_Flags           =    PLACETEXT_IN;

    g = CreateGadget( BUTTON_KIND, g, &ng, TAG_DONE );

    Gadgets[GD_Pref_Gad] = g;

    ng.ng_LeftEdge        +=   (gadget_width - 26);
    ng.ng_TopEdge         +=   (integer_height + 5);
    ng.ng_Width           =    25;
    ng.ng_Height          =    button_height;
    ng.ng_GadgetText      =    "Skip Perforation";
    ng.ng_GadgetID        =    GD_Skip_Perf_Gad;
    ng.ng_Flags           =    PLACETEXT_LEFT;

    g = CreateGadget( CHECKBOX_KIND, g, &ng, GTCB_Checked, (ULONG)PrtPrefs.pp_SkipPerf, TAG_DONE );

    Gadgets[GD_Skip_Perf_Gad] = g;

    ng.ng_TopEdge         +=   button_height;
    ng.ng_GadgetText      =    "Eject Page";
    ng.ng_GadgetID        =    GD_Page_Eject_Gad;

    g = CreateGadget( CHECKBOX_KIND, g, &ng, GTCB_Checked, (ULONG)PrtPrefs.pp_EjectPage, TAG_DONE );

    Gadgets[GD_Page_Eject_Gad] = g;

    ng.ng_LeftEdge        =    ((WindowTags[2].ti_Data / 2) - (gadget_width / 2));
    ng.ng_TopEdge         +=   (button_height + 5);
    ng.ng_Width           =    gadget_width;
    ng.ng_Height          =    button_height;
    ng.ng_GadgetText      =    "Quit WBPrinter";
    ng.ng_GadgetID        =    GD_Quit_Gad;
    ng.ng_Flags           =    PLACETEXT_IN;

    g = CreateGadget( BUTTON_KIND, g, &ng, TAG_DONE );

    Gadgets[GD_Quit_Gad] = g;

    ng.ng_LeftEdge        =    12 + (gadget_width + 10);
    ng.ng_TopEdge         -=   (button_height + 5);
    ng.ng_GadgetText      =    "Set Spool Directory";
    ng.ng_GadgetID        =    GD_Spool_Gad;

    g = CreateGadget( BUTTON_KIND, g, &ng, TAG_DONE );

    Gadgets[GD_Spool_Gad] = g;

    ng.ng_TopEdge         -=   (button_height + 5);
    ng.ng_Width           =    (gadget_width / 2);
    ng.ng_GadgetText      =    "NEXT";
    ng.ng_GadgetID        =    GD_Next_Gad;

    g = CreateGadget( BUTTON_KIND, g, &ng, TAG_DONE );

    Gadgets[GD_Next_Gad] = g;

    ng.ng_LeftEdge        +=   ng.ng_Width;
    ng.ng_Width           =    (gadget_width - ng.ng_Width);
    ng.ng_GadgetText      =    "CANCEL";
    ng.ng_GadgetID        =    GD_Cancel_Gad;

    g = CreateGadget( BUTTON_KIND, g, &ng, TAG_DONE );

    Gadgets[GD_Cancel_Gad] = g;

    ng.ng_LeftEdge        =    12 + (gadget_width + 10);
    ng.ng_Height          =    (ng.ng_TopEdge - gadget_top);
    ng.ng_TopEdge         =    gadget_top;
    ng.ng_Width           =    gadget_width;
    ng.ng_GadgetText      =    0l;
    ng.ng_GadgetID        =    GD_Job_List_Gad;
    ng.ng_Flags           =    0;

    g = CreateGadget( LISTVIEW_KIND, g, &ng, GTLV_Labels, Print_Q, GTLV_ShowSelected, 0l, TAG_DONE );

    Gadgets[GD_Job_List_Gad] = g;


    if ( NOT g )
        return( 4l );

    WindowTags[ 6 ].ti_Data = (ULONG)GList;

    if ( NOT( Wnd = OpenWindowTagList( 0l, WindowTags )))
        return( 5l );

    GT_RefreshWindow( Wnd, 0l );

    return( 0l );
}

void Remove_AppWindow( void )
{
    struct Message *msg;

    if ( Wnd        )
    {
        window_left = (ULONG)Wnd->LeftEdge;
        window_top  = (ULONG)Wnd->TopEdge;
        while(msg = GetMsg(Wnd->UserPort))
           ReplyMsg(msg);
        CloseWindow( Wnd );
        Wnd = NULL;
    }

    if ( GList      )
    {
        FreeGadgets( GList );
        GList = NULL;
    }

    if ( VisualInfo )
    {
        FreeVisualInfo( VisualInfo );
        VisualInfo = NULL;
    }

    if ( Scr        )
    {
        UnlockPubScreen( NULL, Scr );
        Scr = NULL;
    }

    if ( GadToolsBase )
    {
        CloseLibrary( GadToolsBase );
        GadToolsBase = NULL;
    }
}
   

/*
 * Start up the print task
 */
void StartPrintTask( void )
{
   struct MsgPort *child_port;
   struct Process *child_proc;
   struct TagItem  proc_tags[3];
   
   /* Allocate memory for both fake seglist and startup message */
   /* If either fail we can return, before the CreateProc()     */ 
   start_msg = (struct ProcMsg *)AllocMem(sizeof(struct ProcMsg), MEMORY_TYPE);
   if (start_msg == NULL)
      return;


   proc_tags[0].ti_Tag  = NP_Entry;
   proc_tags[0].ti_Data = (ULONG)&PrintFiles;
   proc_tags[1].ti_Tag  = NP_Name;
   proc_tags[1].ti_Data = (ULONG)&"WBPrinter_Print";
   proc_tags[2].ti_Tag  = TAG_DONE;
   proc_tags[2].ti_Data = NULL;

   if((child_proc = CreateNewProc(&proc_tags[0])) == NULL)
   {
      /* error, cleanup and abort */
      FreeMem(start_msg, sizeof(*start_msg));
      return;
   }
   child_port = &(child_proc->pr_MsgPort);
   
   /* Create the startup message */
   start_msg->msg.mn_Length = sizeof(struct ProcMsg) - sizeof(struct Message);
   start_msg->msg.mn_ReplyPort = CreatePort(0,0);
   start_msg->msg.mn_Node.ln_Type = NT_MESSAGE;
   
   start_msg->global_data = (void *)getreg(REG_A4);  /* save global data reg (A4) */
   
   /* Fill in user fields here */
   
   
   /* send startup message to child */
   PutMsg(child_port, (struct Message *)start_msg);
   
   return;
}


/*
 * Send file to PRT:
 */
__saveds void PrintFiles()
{
   struct Process  *proc;
   struct ProcMsg  *mess;
   struct PrtMsg   *pmsg;
   struct FileNode *fnode;
   struct MsgPort  *child_msg_port;
   FILE   *infile,
          *printer;
   long   lcount;
   char   *buff;
   char   file_name[255];
   BOOL   print_done;
   BOOL   kill_task;
   BOOL   canceled;
   int    i;

         
   proc = (struct Process *)FindTask((char *)NULL);

   /* get the startup message */
   WaitPort(&proc->pr_MsgPort);
   mess = (struct ProcMess *)GetMsg(&proc->pr_MsgPort);

   child_msg_port = CreatePort("WBPrinter Printer", 0L);
   if(child_msg_port == NULL)
      goto endprint;

   kill_task = canceled = FALSE;
   while(!kill_task)
   {
      ObtainSemaphore(print_q_semaphore);
      fnode = (struct FileNode *)Print_Q->lh_Head;
      ReleaseSemaphore(print_q_semaphore);
      while(fnode->nn_Node.ln_Succ)
      {
         ObtainSemaphore(print_q_semaphore);
         fnode->nn_Node.ln_Type = PRINTING_FILE;
         strcpy(file_name, spooldir);
         AddPart(file_name, fnode->nn_SpooledName, 255);
         ReleaseSemaphore(print_q_semaphore);

         if((infile = fopen(file_name, "r")) == NULL)
            return;

         if((printer = fopen("PRT:", "a+")) == NULL)
         {
            fclose(infile);
            return;
         }
         if((buff = (char *)AllocMem(1024, MEMF_PUBLIC)) == NULL)
         {
            fclose(infile);
            fclose(printer);
            return;
         }
         strcpy(buff, PrinterSetup[LPI   + PrtPrefs.pp_LinesPerInch]);
         strcat(buff, PrinterSetup[SKIP  + PrtPrefs.pp_SkipPerf]);
         if(buff[6] == 'n')
            buff[6] = (char)((PrtPrefs.pp_LinesPerInch + 3) * 2) + '0';
         strcat(buff, PrinterSetup[QUAL  + PrtPrefs.pp_PrintQuality]);
         strcat(buff, PrinterSetup[PITCH + PrtPrefs.pp_PrintPitch]);
         sprintf(&buff[17], "\x1b[%d;%ds",
                 PrtPrefs.pp_LeftMargin, PrtPrefs.pp_RightMargin);
         i = 17 + strlen(&buff[17]);
         fwrite(buff, i, 1, printer);

         lcount = 0;
         print_done = FALSE;
         while(!print_done)
         {
            if(fgets(buff, 1024, infile) == NULL)
               print_done = TRUE;
            else
               fputs(buff, printer);
            if(++lcount == 10)
            {
               lcount = 0;
               while(pmsg = (struct PrtMsg *)GetMsg(child_msg_port))
               {
                  switch(pmsg->pm_Command)
                  {
                     case CANCEL_AND_DIE:
                        kill_task  = TRUE;
                        print_done = TRUE;
                        break;
                     case CANCEL_PRINT:
                        print_done = TRUE;
                        canceled   = TRUE;
                        break;
                  };
                  ReplyMsg((struct Message *)pmsg);
               };
            };
         };
         fclose(infile);
         if(PrtPrefs.pp_EjectPage)
         {
            buff[0] = '\x0c';
            buff[1] = '\0';
            fputs(buff, printer);
         };
         fclose(printer);
         FreeMem(buff, 1024);
         DeleteFile(file_name);
         while(AttemptSemaphore(print_q_semaphore) == FALSE)
         {
            Delay(120);
            while(pmsg = (struct PrtMsg *)GetMsg(child_msg_port))
            {
               switch(pmsg->pm_Command)
               {
                  case CANCEL_AND_DIE:
                     kill_task  = TRUE;
                     break;
                  case CANCEL_PRINT:
                     canceled   = TRUE;
                     break;
               };
               ReplyMsg((struct Message *)pmsg);
            };
         };
         if(!canceled) /* Do_AppWindow already Removed this Node if TRUE */
         {
            Remove((struct Node *)fnode);
            FreeMem(fnode->nn_SpooledName, (strlen(fnode->nn_SpooledName) + 1));
            FreeMem(fnode->nn_Node.ln_Name, (strlen(fnode->nn_Node.ln_Name) + 1));
            FreeMem(fnode, sizeof(struct FileNode));
         };
         canceled = FALSE;
         fnode = (struct FileNode *)Print_Q->lh_Head;
         ReleaseSemaphore(print_q_semaphore);
      };
      WaitPort(child_msg_port);
      while(pmsg = (struct PrtMsg *)GetMsg(child_msg_port))
      {
         switch(pmsg->pm_Command)
         {
            case CANCEL_AND_DIE:
               kill_task  = TRUE;
               break;
            case CANCEL_PRINT:
            case PRINTS_READY:
               break;
         };
         ReplyMsg((struct Message *)pmsg);
      };
   };   

endprint:
   /* Reply so process who spawed us knows we're done */   
   if(child_msg_port) DeletePort(child_msg_port);
   ReplyMsg((struct Message *)mess);
}
