/*
***************************************************************************
*
* Datei:
*    RSysSaveWindow.c
*
* Inhalt:
*    void SaveWindows(void);
*
* Bemerkungen:
*    Erzeugen einer IFF-Datei aus einem Window.
*
* Erstellungsdatum:
*    07-Jan-93    Rolf Böhme
*
* Änderungen:
*    07-Jan-93    Rolf Böhme    Erstellung
*
***************************************************************************
*/

#include "RSysDebug.h"
#include "RSysFunc.h"

   /*
    * Diese Routinen habe ich wieder mal aus der
    * "Quellen-Fundgrube" von TERM entnommen.  Danke Olaf!  Aber
    * einiges war leider falsch :-)
    */

	/* Current compression mode. */

#define DUMP		0
#define RUN		1

	/* ByteRun compression data. */

#define MINRUN		3
#define MAXRUN		128
#define MAXDAT		128

	/* Chunk types. */

#define ID_ILBM		MAKE_ID('I','L','B','M')
#define ID_ANNO		MAKE_ID('A','N','N','O')
#define ID_BMHD		MAKE_ID('B','M','H','D')
#define ID_CMAP		MAKE_ID('C','M','A','P')
#define ID_CAMG		MAKE_ID('C','A','M','G')
#define ID_BODY		MAKE_ID('B','O','D','Y')

	/* Masking technique. */

#define mskNone		0

	/* Compression techniques. */

#define cmpNone		0
#define cmpByteRun1	1

	/* A bitmap header. */

typedef struct
{
	UWORD		w,h;			/* raster width & height in pixels */
	WORD		x,y;			/* position for this image */
	UBYTE		nPlanes;		/* # source bitplanes */
	UBYTE		masking;		/* masking technique */
	UBYTE		compression;		/* compression algorithm */
	UBYTE		pad1;			/* UNUSED.  For consistency, put 0 here.*/
	UWORD		transparentColor;	/* transparent "color number" */
	UBYTE		xAspect,yAspect;	/* aspect ratio, a rational number x/y */
	WORD		pageWidth,pageHeight;	/* source "page" size in pixels */
} BitMapHeader;

	/* A single 8-bit colour register. */

typedef struct
{
	UBYTE		red,			/* red component, 0..255 */
			green,			/* green component, 0..255 */
			blue;			/* blue component, 0..255 */
} ColorRegister;


	/* Local packer data. */

static LONG		PackedBytes;
static BYTE		Buffer[MAXDAT + 1];

	/* PutDump(register PLANEPTR Destination,register LONG Count):
	 *
	 *	Output a byte dump.
	 */

static PLANEPTR
PutDump(register PLANEPTR Destination,register LONG Count)
{
	register PLANEPTR Source = (PLANEPTR)Buffer;

	*Destination++	 = Count - 1;
	 PackedBytes	+= Count + 1;

	while(Count--)
		*Destination++ = *Source++;

	return(Destination);
}

	/* PutRun(register PLANEPTR Destination,LONG Count,WORD Char):
	 *
	 *	Output a byte run.
	 */

static PLANEPTR
PutRun(register PLANEPTR Destination,LONG Count,WORD Char)
{
	*Destination++	 = -(Count - 1);
	*Destination++	 = Char;
	 PackedBytes	+= 2;

	return(Destination);
}

	/* PackRow(PLANEPTR *SourcePtr,register PLANEPTR Destination,LONG RowSize):
	 *
	 *	Pack a row of bitmap data using ByteRun compression,
	 *	based on the original "EA IFF 85" pack.c example code.
	 */

static LONG
PackRow(PLANEPTR *SourcePtr,register PLANEPTR Destination,LONG RowSize)
{
	register PLANEPTR Source = *SourcePtr;

	WORD	Buffered	= 1,
		RunStart	= 0;
	BYTE	Mode		= DUMP,
		LastChar,
		Char;

	PackedBytes = 0;

	Buffer[0] = LastChar = Char = *Source++;

	RowSize--;

	while(RowSize--)
	{
		Buffer[Buffered++] = Char = *Source++;

		if(Mode)
		{
			if((Char != LastChar) || (Buffered - RunStart > MAXRUN))
			{
				Destination	= PutRun(Destination,Buffered - 1 - RunStart,LastChar);
				Buffer[0]	= Char;
				Buffered	= 1;
				RunStart	= 0;
				Mode		= DUMP;
			}
		}
		else
		{
			if(Buffered > MAXDAT)
			{
				Destination	= PutDump(Destination,Buffered - 1);
				Buffer[0]	= Char;
				Buffered	= 1;
				RunStart	= 0;
			}
			else
			{
				if(Char == LastChar)
				{
					if(Buffered - RunStart >= MINRUN)
					{
						if(RunStart)
							Destination = PutDump(Destination,(LONG)RunStart);

						Mode = RUN;
					}
					else
					{
						if(!RunStart)
							Mode = RUN;
					}
				}
				else
					RunStart = Buffered - 1;
			}
		}

		LastChar = Char;
	}

	if(Mode)
		PutRun(Destination,Buffered - RunStart,LastChar);
	else
		PutDump(Destination,(LONG)Buffered);

	*SourcePtr = Source;

	return(PackedBytes);
}

	/* PutANNO(struct IFFHandle *Handle):
	 *
	 *	Output `ANNO' chunk.
	 */

static BYTE
PutANNO(struct IFFHandle *Handle)
{
   extern char *v;
		WORD	Len;

	Len = strlen(&v[1]);

		/* Push the `ANNO' chunk on the stack. */

	if(!PushChunk(Handle,0,ID_ANNO,(long)Len))
	{
			/* Write the creator string. */

		if(WriteChunkBytes(Handle,&v[1],(long)Len) == Len)
		{
				/* Pop the `ANNO' chunk. */

			if(!PopChunk(Handle))
				return(TRUE);
		}
	}

	return(FALSE);
}

	/* PutBMHD():
	 *
	 *	Output `BMHD' chunk.
	 */

static BYTE
PutBMHD(struct IFFHandle *Handle,struct Window *Window,UBYTE Compression)
{
	struct DisplayInfo DisplayInfo;

		/* Get the display aspect ratio. */

	if(GetDisplayInfoData(NULL,
                         (APTR)&DisplayInfo,
                         sizeof(struct DisplayInfo),
                         DTAG_DISP,
                         GetVPModeID(&Window -> WScreen -> ViewPort)))
	{
		BitMapHeader Header;

			/* Fill in the bitmap header. */

		Header . w			= Window -> Width;
		Header . h			= Window -> Height;
		Header . pageWidth		= Window /*-> WScreen*/ -> Width;
		Header . pageHeight		= Window /*-> WScreen*/ -> Height;
		Header . x			= Window -> LeftEdge;
		Header . y			= Window -> TopEdge;
		Header . nPlanes		= Window /*-> WScreen*/ -> RPort -> BitMap -> Depth;
		Header . masking		= mskNone;
		Header . compression		= Compression;
		Header . pad1			= 0;
		Header . transparentColor	= 0;
		Header . xAspect		= DisplayInfo . Resolution . x;
		Header . yAspect		= DisplayInfo . Resolution . y;

			/* Push the `BMHD' chunk on the stack. */

		if(!PushChunk(Handle,0,ID_BMHD,sizeof(BitMapHeader)))
		{
				/* Write the bitmap header. */

			if(WriteChunkBytes(Handle,&Header,sizeof(BitMapHeader)) == sizeof(BitMapHeader))
			{
					/* Pop the `BMHD' chunk. */

				if(!PopChunk(Handle))
					return(TRUE);
			}
		}
	}

	return(FALSE);
}

	/* PutCMAP(struct IFFHandle *Handle,struct ViewPort *VPort):
	 *
	 *	Output `CMAP' chunk, only 4-bit colour registers
	 *	are supported so far.
	 */

static BYTE
PutCMAP(struct IFFHandle *Handle,struct ViewPort *VPort)
{
		/* Push the `CMAP' chunk on the stack. */

	if(!PushChunk(Handle,0,ID_CMAP,3 * VPort -> ColorMap -> Count))
	{
		ColorRegister	Colour;
		LONG		i;
		ULONG		Value,
				R,G,B;

			/* Read and convert all the
			 * ColorMap entries (4 bit colour
			 * components only).
			 */

		for(i = 0 ; i < VPort -> ColorMap -> Count ; i++)
		{
				/* Read colour value. */

			Value = GetRGB4(VPort -> ColorMap,i);

				/* Split the value into components. */

			R = (Value >> 8) & 0xF;
			G = (Value >> 4) & 0xF;
			B = (Value     ) & 0xF;

				/* Store the colour components. */

			Colour . red	= (R << 4) | R;
			Colour . green	= (G << 4) | G;
			Colour . blue	= (B << 4) | B;

				/* Write the colours. */

			if(WriteChunkBytes(Handle,&Colour,3) != 3)
				return(FALSE);
		}

			/* Pop the `CMAP' chunk. */

		if(!PopChunk(Handle))
			return(TRUE);
	}

	return(FALSE);
}

	/* PutCAMG(struct IFFHandle *Handle,struct ViewPort *VPort):
	 *
	 *	Output `CAMG' chunk.
	 */

static BYTE
PutCAMG(struct IFFHandle *Handle,struct ViewPort *VPort)
{
	if(!PushChunk(Handle,0,ID_CAMG,sizeof(ULONG)))
	{
		ULONG ViewModes = GetVPModeID(VPort),ulongsize = sizeof(ULONG);

		if(WriteChunkBytes(Handle,&ViewModes,ulongsize) == ulongsize)
		{
			if(!PopChunk(Handle))
				return(TRUE);
		}
	}

	return(FALSE);
}

	/* PutBODY(struct IFFHandle *Handle)
	 *
	 *	Output `BODY' chunk.
	 */

static BYTE
PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap,UBYTE Compression)
{
	BYTE Success = FALSE;

	PLANEPTR *Planes;

		/* Allocate temporary bitplane pointers. */

	if(Planes = (PLANEPTR *)MyAllocVec(BitMap -> Depth * sizeof(PLANEPTR *),MEMF_ANY | MEMF_CLEAR, NO_KILL))
	{
		register LONG i;

			/* Copy the bitplane pointers. */

		for(i = 0 ; i < BitMap -> Depth ; i++)
			Planes[i] = BitMap -> Planes[i];

			/* Are we to compress the data? */

		if(Compression == cmpByteRun1)
		{
			PLANEPTR PackBuffer;

				/* Allocate line compression buffer. */

			if(PackBuffer = (PLANEPTR)MyAllocVec(BitMap -> BytesPerRow * 2,MEMF_ANY, NO_KILL))
			{
					/* Push the `BODY' chunk on the stack. */

				if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
				{
					register LONG	PackedBytes,
							j;

						/* So far, we are quite successful,
						 * any write access to fail will
						 * cause `Success' to drop to FALSE.
						 */

					Success = TRUE;

						/* Compress all the rows. */

					for(i = 0 ; Success && i < BitMap -> Rows ; i++)
					{
							/* Compress all the planes. */

						for(j = 0 ; Success && j < BitMap -> Depth ; j++)
						{
								/* Do the compression. */

							PackedBytes = PackRow(&Planes[j],PackBuffer,(LONG)BitMap -> BytesPerRow);

								/* Write the compressed data. */

							if(WriteChunkBytes(Handle,PackBuffer,PackedBytes) != PackedBytes)
								Success = FALSE;
						}
					}

						/* Pop the `BODY' chunk. */

					if(PopChunk(Handle))
						Success = FALSE;
				}

					/* Free the line compression buffer. */

				MyFreeVec(PackBuffer);
			}
		}
		else
		{
				/* Push the `BODY' chunk on the stack. */

			if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
			{
				register LONG j;

					/* So far, we are quite successful,
					 * any write access to fail will
					 * cause `Success' to drop to FALSE.
					 */

				Success = TRUE;

					/* Compress all the rows. */

				for(i = 0 ; Success && i < BitMap -> Rows ; i++)
				{
						/* Compress all the planes. */

					for(j = 0 ; Success && j < BitMap -> Depth ; j++)
					{
							/* Write the row. */

						if(WriteChunkBytes(Handle,Planes[j],(long)BitMap -> BytesPerRow) != BitMap -> BytesPerRow)
							Success = FALSE;
						else
							Planes[j] += BitMap -> BytesPerRow;
					}
				}

					/* Pop the `BODY' chunk. */

				if(PopChunk(Handle))
					Success = FALSE;
			}
		}

			/* Free the temporary bitplane pointers. */

		MyFreeVec(Planes);
	}

		/* Return the result. */

	return(Success);
}

	/* SaveWindow(STRPTR Name,struct Window *Window):
	 *
	 *	Save the contents of a window to a file.
	 */

static BYTE
SaveWindow(STRPTR Name,struct Window *Window)
{
	struct RastPort		*RPort;
	BYTE			 Success = FALSE,
				 NewFile = FALSE;

	if(IFFParseBase = OpenLibrary((STRPTR)"iffparse.library",0))
   {
   		/* Allocate a dummy rastport, we will need only
   		 * to copy the contents of the window into the
   		 * bitmap.
   		 */

   	if(RPort = (struct RastPort *)MyAllocVec(sizeof(struct RastPort),MEMF_ANY, NO_KILL))
   	{
   		struct BitMap *BitMap;

   			/* Initialize the rastport with defaults. */

   		InitRastPort(RPort);

   			/* Allocate a bitmap. */

   		if(BitMap = (struct BitMap *)MyAllocVec(sizeof(struct BitMap),MEMF_ANY, NO_KILL))
   		{
   			WORD i;

   				/* Put it into the rastport. */

   			RPort -> BitMap = BitMap;

   				/* Initialize it with the window dimensions. */

               /*
                * An dieser Stelle ist der RastPort des Fensters
                * zu nehmen, NICHT der des Screens, zu dem das
                * Fenster gehört!
                */
   			InitBitMap(BitMap,
/*                       (long)Window -> WScreen -> RastPort . BitMap -> Depth,*/
                       (long)Window -> RPort -> BitMap -> Depth,
                       (long)(Window -> Width),
                       (long)Window -> Height);

   				/* Flag success so any allocation
   				 * to fail in the bitplane allocation
   				 * loop will indicate failure.
   				 */

   			Success = TRUE;

   				/* Allocate all the bitplanes necessary. */

   			for(i = 0 ; Success && i < BitMap -> Depth ; i++)
   			{
   				if(!(BitMap -> Planes[i] = AllocRaster((long)Window -> Width,(long)Window -> Height)))
   					Success = FALSE;
   			}

   				/* Did we get all the planes we wanted? */

   			if(Success)
   			{
   				struct IFFHandle *Handle;

   					/* Copy the window contents to the
   					 * local bitmap.
   					 */
               if(NOT(Window->Flags & WFLG_BACKDROP))
                  WindowToFront(Window);

               Delay(10);

                  /*
                   * ClipBlit() arbeitet nicht korrekt! Ich habe
                   * die Routine durch BltBitMap() ersetzt
                   */
               /*
                * ClipBlit(Window -> RPort,0,0,RPort,0,0,(long)Window -> Width,(long)Window -> Height,0xC0);
                */

               BltBitMap(Window->RPort->BitMap,
                         (long)Window -> LeftEdge,(long)Window -> TopEdge,BitMap,
                         0,0,(long)Window -> Width,(long)Window -> Height,0xC0,0xFF,NULL);

   					/* Reset the success indicator. */

   				Success = FALSE;

   					/* Allocate an iff handle. */

   				if(Handle = AllocIFF())
   				{
   						/* Open a file for write access. */

   					if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
   					{
   							/* Remember that we succeeded
   							 * in creating a new file.
   							 */

   						NewFile = TRUE;

   							/* Tell iffparse.library that it's
   							 * a plain AmigaDOS file handle.
   							 */

   						InitIFFasDOS(Handle);

   							/* Open the file for writing. */

   						if(!OpenIFF(Handle,IFFF_WRITE))
   						{
   								/* Push parent chunk on the
   								 * stack.
   								 */

   							if(!PushChunk(Handle,ID_ILBM,ID_FORM,IFFSIZE_UNKNOWN))
   							{
   									/* Output all the chunk data. */

   								if(PutANNO(Handle))
   								{
   									UBYTE Compression;

   										/* Don't compress the bitmap if
   										 * isn't really worth it.
   										 */
   									if(BitMap -> BytesPerRow > 4)
   										Compression = cmpByteRun1;
   									else
   										Compression = cmpNone;

   									if(PutBMHD(Handle,Window,Compression))
   									{
   										if(PutCMAP(Handle,&Window -> WScreen -> ViewPort))
   										{
   											if(PutCAMG(Handle,&Window -> WScreen -> ViewPort))
   											{
   												if(PutBODY(Handle,BitMap,Compression))
   												{
   														/* Pop the parent chunk
   														 * from the stack.
   														 */

   													if(!PopChunk(Handle))
   														Success = TRUE;
   												}
   											}
   										}
   									}
   								}
   							}

   								/* Close the iff handle. */

   							CloseIFF(Handle);
   						}

   							/* Close the file. */

   						if(!Close(Handle -> iff_Stream))
   							Success = FALSE;
   					}

   						/* Free the iff handle. */

   					FreeIFF(Handle);
   				}
   			}

   				/* Free all bitplanes. */

   			for(i = 0 ; i < BitMap -> Depth ; i++)
   			{
   				if(BitMap -> Planes[i])
   					FreeRaster(BitMap -> Planes[i],(long)Window -> Width,(long)Window -> Height);
   			}

   				/* Free the bitmap. */

   			MyFreeVec(BitMap);
   		}

   			/* Free the rastport. */

   		MyFreeVec(RPort);
   	}

   		/* If successful, clear the `executable' bit. */

   	if(Success)
   		SetProtection(Name,FIBF_EXECUTE);
   	else
   	{
   			/* Delete the remains of the file. */

   		if(NewFile)
   			DeleteFile(Name);
   	}

      CloseLibrary(IFFParseBase);
   }
   else
      Success = FALSE;

		/* Return the result. */

	return(Success);
}

struct winlist
{
   struct Node node;
   struct Window *win;
   char name[MAXFULLNAME];
} *windows = NULL;

struct List WinList;

enum
{
   GD_WindowsLVGad,
   GD_SaveIFFGad,
   GD_ResetWinGad
};

#define SaveAWindow_CNT 3

static struct Window         *SaveAWindowWnd = NULL;
static struct Gadget         *SaveAWindowGList = NULL;
static struct Gadget         *SaveAWindowGadgets[3];
static UWORD                  SaveAWindowLeft = 178;
static UWORD                  SaveAWindowTop = 38;
static UWORD                  SaveAWindowWidth = 258;
static UWORD                  SaveAWindowHeight = 121;
static UBYTE                 *SaveAWindowWdt = (UBYTE *)NAME " " VERSION " - Save window";

static UWORD SaveAWindowGTypes[] = {
	LISTVIEW_KIND,
	BUTTON_KIND,
	BUTTON_KIND
};

static struct NewGadget SaveAWindowNGad[] = {
	8, 18, 241, 80, (UBYTE *)"Windows", NULL, GD_WindowsLVGad, PLACETEXT_ABOVE, NULL, NULL,
	8, 103, 113, 13, (UBYTE *)"IFF File", NULL, GD_SaveIFFGad, PLACETEXT_IN, NULL, NULL,
	128, 103, 121, 13, (UBYTE *)"Rescan windows", NULL, GD_ResetWinGad, PLACETEXT_IN, NULL, NULL
};

static ULONG *SaveAWindowGTags[] = {
	(ULONG *)(GTLV_ShowSelected), (ULONG *)NULL,(ULONG *)(GTLV_Labels), (ULONG *)&WinList, (ULONG *)(TAG_DONE),
	(ULONG *)(TAG_DONE),
	(ULONG *)(TAG_DONE)
};

   /*
    * OpenSaveAWindowWindow() öffnet ein Fenster mit einem
    * ListView und zwei Gadgets zu Auswahl eines zu speichernden
    * Fensters
    */
static int
OpenSaveAWindowWindow( void )
{
	struct NewGadget	ng;
	struct Gadget	*g;
	UWORD		lc, tc;
	UWORD		wleft = SaveAWindowLeft, wtop = SaveAWindowTop, ww, wh;
   int gl[] = {GD_WindowsLVGad};

	ComputeFont( Scr,SaveAWindowWidth, SaveAWindowHeight );

	ww = ComputeX( SaveAWindowWidth );
	wh = ComputeY( SaveAWindowHeight );

	if (( wleft + ww + OffX + Scr->WBorRight ) > Scr->Width )
      wleft = Scr->Width - ww;
	if (( wtop + wh + OffY + Scr->WBorBottom ) > Scr->Height )
      wtop = Scr->Height - wh;

   ww = compute((UWORD) (OffX + Scr->WBorRight), FontX, (int)SaveAWindowWidth);
   wh = compute((UWORD) (OffY + Scr->WBorBottom), FontY, (int)SaveAWindowHeight);

   CenterWindow(Scr, &wtop, &wleft, ww, wh);

	if ( ! ( g = CreateContext( &SaveAWindowGList )))
		return( 1L );

	for( lc = 0, tc = 0; lc < SaveAWindow_CNT; lc++ ) {

		CopyMem((char * )&SaveAWindowNGad[ lc ], (char * )&ng, (long)sizeof( struct NewGadget ));

		ng.ng_VisualInfo = VisualInfo;
		ng.ng_TextAttr   = Font;
		ng.ng_LeftEdge   = OffX + ComputeX( ng.ng_LeftEdge );
		ng.ng_TopEdge    = OffY + ComputeY( ng.ng_TopEdge );
		ng.ng_Width      = ComputeX( ng.ng_Width );
		ng.ng_Height     = ComputeY( ng.ng_Height);

		SaveAWindowGadgets[ lc ] = g = CreateGadgetA((ULONG)SaveAWindowGTypes[ lc ], g, &ng, ( struct TagItem * )&SaveAWindowGTags[ tc ] );

      makelabelvisible(SaveAWindowGadgets[lc]);

		while( SaveAWindowGTags[ tc ] ) tc += 2;
		tc++;

		if ( NOT g )
			return( 2L );
	}

	if ( ! ( SaveAWindowWnd = OpenWindowTags( NULL,
				WA_Left,	wleft,
				WA_Top,		wtop,
				WA_Width,	ww,
				WA_Height,	wh,
				WA_IDCMP,	LISTVIEWIDCMP|
            BUTTONIDCMP|
            IDCMP_CLOSEWINDOW|
            IDCMP_VANILLAKEY|
            IDCMP_REFRESHWINDOW,
				WA_Flags,	WFLG_DRAGBAR|
            WFLG_DEPTHGADGET|
            WFLG_CLOSEGADGET|
            WFLG_SMART_REFRESH|
            WFLG_ACTIVATE|
            WFLG_RMBTRAP,
				WA_Gadgets,	SaveAWindowGList,
				WA_Title,	SaveAWindowWdt,
            WA_PubScreenFallBack,TRUE,
            WA_PubScreen, Scr,
				TAG_DONE )))
	return( 4L );

   RefreshRastPort(SaveAWindowWnd,SaveAWindowGadgets,gl, 1);

   if(Flags.autofront)
   {
      WindowToFront(SaveAWindowWnd);
      ActivateWindow(SaveAWindowWnd);
   }

	return( 0L );
}

   /*
    * CreateWinList() erzeugt eine Liste von Fenstertiteln und
    * Adressen
    */
static void
CreateWinList(int count)
{
   ULONG lock;
   struct Window *win;
   struct Screen *scr;
   char help[MAXFULLNAME];
   int   i = 0;

   DPOS;
   MyFreeVec(windows);

   DPOS;
   windows = (struct winlist *) MyAllocVec(count * sizeof(struct winlist),
                                           MEMF_ANY | MEMF_CLEAR, KILL);

   DPOS;
   lock = LockIBase(NULL);

   for (scr = IntuitionBase->FirstScreen; scr && (i < count);
        scr = scr->NextScreen)
      for (win = scr->FirstWindow; win && (i < count);
           win = win->NextWindow)
      {
         windows[i].node.ln_Name = windows[i].name;
         windows[i].node.ln_Type = NT_USER;

         windows[i].win = win;

         if ((char *)win->Title)
            strncpy(help,(char *)win->Title, MAXFULLNAME - 1);
         else
            help[0] = STRINGEND;

         sprintf(windows[i].name,"0x%08lx %s",windows[i].win,help);

         i++;
      }

   UnlockIBase(lock);

   DPOS;
   for (i = 0; i < count; i++)
      AddTail(&WinList, &windows[i].node);

   return;
}

   /*
    * ResetWinList() erneuert die Window-Liste
    */
static void
ResetWinList(void)
{
   register int cntwin;

   DPOS;
   InitListView(SaveAWindowWnd,SaveAWindowGadgets[GD_WindowsLVGad],NULL,0);

   NewList(&WinList);

   cntwin = CountIntuiObjects((int)WINDOWS);
   DPOS;
   CreateWinList(cntwin);

   DPOS;
   InitListView(SaveAWindowWnd,SaveAWindowGadgets[GD_WindowsLVGad],&WinList,0);

   DPOS;
   EnableGadget(SaveAWindowWnd,SaveAWindowGadgets[GD_SaveIFFGad],FALSE);

   return;
}

   /*
    * SaveWindows() bietet eine Benutzeroberfläche an und
    * verwaltet die Benutzereingaben
    */
void
SaveWindows(void)
{
   struct IntuiMessage *message;
   ULONG class,
         code;
   APTR  object;
   struct Node *clickednode = NULL;
   struct Window *printwin;
   APTR  req;
   int id;

   DPOS;

   Flags.quit_sw = 0;

   NewList(&WinList);

   windows = NULL;

   if (OpenASysWindow(OpenSaveAWindowWindow,NO_KILL))
   {
      PrintInfo("Save windows", SPEAK, 0);

      if (SysWnd)
         req = LockWindow(SysWnd);

   DPOS;
      ResetWinList();

   DPOS;
      do
      {
         Wait(1L << SaveAWindowWnd->UserPort->mp_SigBit);

         while ((message = (struct IntuiMessage *)
                 GT_GetIMsg(SaveAWindowWnd->UserPort)) != NULL)
         {
            class = message->Class;
            code = message->Code;
            object = message->IAddress;

            GT_ReplyIMsg(message);

            switch(class)
            {
               case IDCMP_CLOSEWINDOW:
                  Flags.quit_sw = 1;
                  break;

               case IDCMP_GADGETUP:
                  id = ((struct Gadget *)object)->GadgetID;

                  switch(id)
                  {
                     case GD_WindowsLVGad:
                        if(clickednode = GetNode(&WinList,code))
                           EnableGadget(SaveAWindowWnd,SaveAWindowGadgets[GD_SaveIFFGad],
                                        TRUE);

                        printwin = ((struct winlist *)clickednode)->win;

                        if(NOT(CheckWindow(printwin)))
                        {
                           ErrorHandle(WINDOW_ERR, FIND_FAIL, NO_KILL);
                           clickednode = NULL;
                           ResetWinList();
                        }

                        break;

                     case GD_SaveIFFGad:
                        if(clickednode)
                        {
                           if (GetFile(SaveAWindowWnd,"RAM:",
                                       "RSys-Window.IFF","#?.IFF",
                                       "Select IFF-File for saving Window",
                                       "Save"))
                           {
                              printwin = ((struct winlist *)clickednode)->win;

                              if(CheckWindow(printwin))
                              {
                                 if(NOT(SaveWindow((STRPTR)_fullpath,
                                                   printwin)))
                                    ErrorHandle(FILE_ERR, WRITE_FAIL,NO_KILL);
                              }
                              else
                                 ErrorHandle(WINDOW_ERR, FIND_FAIL, NO_KILL);

                              ResetWinList();
                           }
                        }
                        break;

                     case GD_ResetWinGad:
                        clickednode = NULL;
                        ResetWinList();
                        break;
                  }
                  break;

               case IDCMP_VANILLAKEY:
                  if((char)code == ESC)
                     Flags.quit_sw = 1;
                  break;
            }
         }
      }
      while (NOT(Flags.quit_sw));

      CloseASysWindow(&SaveAWindowWnd, &SaveAWindowGList, NULL);

      MyFreeVec(windows);

      if (SysWnd)
      {
         UnlockWindow(req);
         RefreshMainWindowPattern();
         RefreshList(LastID);
      }
   }

   return;
}
