/*===========================================================================
  Copyright (C) 1986-2009 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

.TYPE		Module
.IDENTIFICATION twinit.c
.AUTHOR    	Francois Ochsenbein [ESO-IPG]
.LANGUAGE  	C
.KEYWORDS	Window Management
.ENVIRONMENT	TermWindows
.COMMENTS	This module contains routines to initialize, 
		open and close windows and set of windows.

.VERSION   1.0	14-Aug-1986:	Creation
.VERSION   1.1	10-Oct-1986:    At closing, keep track of the
			cursor position (don't clear screen)!

.VERSION   2.0	03-Dec-1986	New terminal-independant graphic characters
			with output buffering version.
.VERSION   2.1	25-Jun-1987: Version '2'
.VERSION   3.0	20-May-1988: Version '3'. Also option _BORDER2_ in Open.
.VERSION   3.1	20-Apr-1989: Screen Input stopped by arrows etc.
.VERSION   3.2	09-May-1989: Check terminal has minimal cap's to support windows
.VERSION   3.3	17-May-1989: Modified parameter of tw_close.
.VERSION   3.4	08-Jun-1989: Modified return value of tw_st = old flag.
.VERSION   3.5	06-Oct-1989: Issue message if terminal too primitive,
				and exit gracefully.
.VERSION   3.6	13-Feb-1990: Close the terminal if too primitive
.VERSION   3.7	28-May-1990: Allow primitive terminals...
.VERSION   3.8	29-Nov-1990: Added tw_gettw (Title Window)

 090901		last modif
----------------------------------------------------------------------------*/

#define	DEBUG		0	/* For debugging only		*/

#define PM_LEVEL 	LEVEL_TW

#include <midas_def.h>


#define  TW_import	0	/* Do not use macro window definitions	*/
#include <twset.h>

extern int tv_close(), tv_agoto(), tv_open();
extern int tv_range(), tv_rb(), tv_clear();

extern int tw_link(), tw_attr(), tw_box(), tw_r(), tw_goto(), tw_rule();
extern int tw_stopin(), tw_uflag(), tw_flags(), tw_cline();

extern int pm_enter(), pm_iexit(), pm_ed_tr2(), pm_ed_trace();
extern int pm_lfile(), eh_ed_as(), mm_bfree();


MID_GLOBAL 	WINDOW *Screen = NULL_WINDOW;
MID_EXTERN	TERM   *terms;

#if 	DEBUG
#define ed_level	3
#define ENTER_DEBUG(x)	ENTER(x)
#define EXIT_DEBUG(x)	EXIT(x)
#define DISPLAY(opt)	tw_ed(w,opt)
#else
#define DISPLAY(opt)
#define ENTER_DEBUG(x)	
#define EXIT_DEBUG(x)	return(x)
#endif

WINDOW *tw_alloc(), *tw_alw();


	MONITOR(TWINIT);


/*==========================================================================
 *			tw_close
 *==========================================================================*/
int tw_close (w, option)
/*+++
.PURPOSE Close an opened WINDOW.
.RETURNS OK / NOK
.REMARKS Allocated areas are freed, links between windows are reset.
---*/
	WINDOW *w;	/* MOD: Window to close	*/
	int	option;	/* IN: 0 for CloseWindow, 1 for DestroyWindow, \
			 * 2 for CloseSubWindow	*/
{ 	
	WINDOW	*wp;

  ENTER("tw_close");

  status = OK;
  if_not(w)		FINISH;

  TRACE_ED_STR2("Closing Window: ", w->id, 8);

  DISPLAY(1);

  wp = Parent(w);		/* Close Parent if necessary 	*/
  if (wp && ((option&2) == 0))	/* Perform operation on Parent 	*/
  {
  	tw_close(wp, option);
  	FINISH;
  }

  if ((option&1) && (!wp))	tw_r(w, 4, NULL_WINDOW); /* Remove if Parent */

  	/* Close first all subwindows 	*/
  while (Child(w))	tw_close(Child(w), 2);
	
	/* Remove window from stack	*/
  tw_link(w, NULL_WINDOW);

	/* Free allocated areas: */
  MEM_FREE(Command(w));			/* Command (with stack)	*/
  if (Fields(w))
  	BUF_Close(Fields(w)),
  	MEM_FREE(Fields(w));

  MEM_FREE(w);

  FIN:
  EXIT(status);
}

/*==========================================================================
 *			tw_end
 *==========================================================================*/
int tw_end ()
/*+++
.PURPOSE Close all windows. To be called at end of TermWindows application.
.RETURNS OK / NOK
.REMARKS All allocated areas are freed. Clear the screen below the
	last cursor position.
---*/
{ 	
  ENTER("tw_end");

  if (Screen == NULL_WINDOW)	EXIT(OK);

  while (Next(Screen) != Screen)	/* Close all opened windows	*/
	tw_close(Next(Screen), 0);

  SetPosition(Screen->pos);

#if DEBUG
  TRACE("Trying now to Close the Screen...");
#endif
  tw_close(Screen, 0);
  Screen = NULL_WINDOW;

  EXIT(CloseTerm());
}

/*==========================================================================
 *			tw_geth
 *==========================================================================*/
int tw_geth (w, home_pos)
/*+++
.PURPOSE Retrieve the (absolute) home position of a Window on the Screen.
.RETURNS OK
.REMARKS 
---*/
	WINDOW	*w;		/* IN: The Window concerned	*/
	short int home_pos[2];	/* OUT: Absolute Home position	*/
{ 	
	register short int *ph;
	MID_RSTATIC short int hh[2] = {0, 0};

  ENTER_DEBUG("tw_geth");
  CheckScreen(w);  

  if (Parent(w))	ph = Parent(w)->home;
  else			ph = hh;

  home_pos[0] = w->home[0] + ph[0];
  home_pos[1] = w->home[1] + ph[1];

  EXIT_DEBUG(OK);
}

/*==========================================================================
 *			tw_getw
 *==========================================================================*/
WINDOW *tw_getlw (wx,op)
/*+++
.PURPOSE Retrieve linked windows / subwindows.
.RETURNS The found window, or NULL_WINDOW.
.REMARKS 
---*/
	WINDOW	*wx;	/* IN: Window where search starts	*/
	int	op;	/* IN: 1 for Next, -1 for Previous, 0 for Child	*/
{ 	
	register WINDOW *w;

  ENTER("*tw_getlw");

  w = NULL_WINDOW;			/* The Returned window	*/
  if_not(wx)		wx = Screen;
  if_not(wx)		FINISH;		/* Not yet initialized... */

  if (op == 0)		w = Child(wx);
  else if (op > 0)	w = Next(wx);
  else 			w = Previous(wx);
  if (w == Screen)	w = NULL_WINDOW;

  FIN:
  EXIT_PTR(WINDOW, w);
}

/*=======================================================================*/
WINDOW *tw_gettw (wx)
/*+++
.PURPOSE Retrieve Title windows / subwindows.
.RETURNS The corresponding title window, or NULL_WINDOW.
.REMARKS 
---*/
	WINDOW	*wx;	/* IN: Window where search starts	*/
{ 	
	register WINDOW *w, *wp;

  ENTER("*tw_gettw");

  w = NULL_WINDOW;			/* The Returned window	*/
  if_not(wx)		FINISH;	
  wp = Parent(wx);	if (!wp) wp = wx;

  for (w = Child(wp); w; w = Next(w)) {
	if (w->id[0] == '`')	break;
  }

  FIN:
  EXIT_PTR(WINDOW, w);
}

/*==========================================================================
 *			tw_getw
 *==========================================================================*/
WINDOW *tw_getw (name)
/*+++
.PURPOSE Retrieve a named window; if no name is given, returns the
	Top Window.
.RETURNS The window structure, or NULL_WINDOW.
.REMARKS In case of duplicate names, the top window is returned.
---*/
	char	*name; 	/* IN: EOS-terminated window name	*/
{ 	
	register int len;
	register WINDOW *w, *wc;
	char idd[8];

  ENTER("*tw_getw");

  TRACE_ED_STRING("Retrieving window: ", name);

  w = NULL_WINDOW;
  if_not(Screen)	FINISH;
  if_not(name)		{ w = Previous(Screen); FINISH; }

  len = strlen(name);
  len = MIN(len, 8);
  oscfill(idd, 8, ' ');
  oscopy(idd, name, len);

  for (w = Previous(Screen); w != Screen; w = Previous(w))
  {	if(oscomp(idd, w->id,8) == 0)	FINISH;		/* Exact match	*/
	for (wc = Child(w); wc; wc = Next(wc))	
		if(oscomp(idd, wc->id, 8) == 0)
				{ w = wc; FINISH; }	/* Exact match	*/
  }

  w = NULL_WINDOW;

  FIN:
  EXIT_PTR(WINDOW, w);
}

/*==========================================================================
 *			tw_init
 *==========================================================================*/
int tw_init (device, term_file, env)
/*+++
.PURPOSE Initializes the window library
.RETURNS OK / NOK
.REMARKS To be called as initialisation. Fails if no minimal capabilities:
	"up" MUST exit.
---*/
	char	*device;    	/* IN: Name of terminal device --- \
				 	NULL for standard */
	char 	*term_file;	/* IN: Name of TERMCAP file ---  \
					NULL for standard */
	int	env;		/* IN: Choice of environment, as TW_cc_VMS, etc 	*/
{
	static unsigned char in_init = 0;
	char	*p;

  ENTER("tw_init");

  status = OK;
  if (in_init)		FINISH;
  if (Screen)		FINISH;		/* Was already done	*/
  
  if (terms->version == 0)
  	if_not(OpenTerm(device, term_file, env))	goto BAD;

	/* Check minimal capabilities exist	*/

#if 0	/* Changed to a Warning	*/
  if(terms->flags & TERM_hard)
  {
  	ERR_ED_STRING("This terminal is too primitive for windows: ", 
  		GetTerm());
	tv_close();
  	if (GetLog() > 2) /* There is a Log File. Issue also the message to 
  		the terminal, to let the user be aware of the problem... */
  	{  	p = ERR_LOC();			/* Retrieve Error ... */
  		ostwrite("**** ", 5);		/* and display	*/
  		ostwrite(p, strlen(p));		/* and display	*/
  		ostwrite("\r\n", 2);
  	}
  	ospexit();
  	goto BAD;
  }
#else		/* Mod. 23-May-1990	*/
  if(terms->flags & TERM_hard)
  {
  	ERR_ED_STRING("Next time, try to use a better terminal than this !? ", 
  		GetTerm());
  	if (GetLog())	/* There is a Log File. Issue also the message to 
  		the terminal, to let the user be aware of the problem... */
  	{  	p = ERR_LOC();			/* Retrieve Error ... */
  		ostwrite("**** ", 5);		/* and display	*/
  		ostwrite(p, strlen(p));		/* and display	*/
  		ostwrite("\r\n", 2);
  		ospwait(4);	/* Just wait, to give some time to read
	  			   the so important above message ...	*/
  	}
  }
#endif

	/* Allocate and initialize Screen	*/

  in_init = 1;
  Screen = tw_open(NULL_WINDOW, "<Screen>", 0, 0, terms->Ni, terms->Nj, 
  		_NORMAL_, 0, 0);
  in_init = 0;
  if_not(Screen)	goto BAD;

  Screen->wpos   	= Wu|Wd|Wr|Wl;		/* Whole screen		*/
  Screen->flags 	|= Echo;

  tw_stopin(Screen,_KEYPAD_,"*");
  tw_stopin(Screen,_PF_,"*");
  tw_stopin(Screen,_FK_,"*");
  tw_stopin(Screen,_ARROW_,"^UDLR");

	/* Look for useful hardware capabilities */

  if (terms->tt_clear)		Screen->hw |= Clear;
  if (SearchCap("cs"))		Screen->hw |= Scroll;
			  	/* cs indicate scrolling region */

  ClearScreen();
  tw_uflag(Screen, 0);		/* All modifications taken	*/

#if DEBUG
  tw_ed(Screen,1);
#endif

  FINISH;

  BAD:	status = NOK;
  FIN:
  EXIT(status);
}

/*==========================================================================
 *			tw_mark
 *==========================================================================*/
int tw_mark (w, l, c, len)
/*+++
.PURPOSE Install markers on the window (define a range)
.RETURNS The length (shorter than len if it would exceed the window size)
.REMARKS Markers are useful to define Range in a (sub)window.
	Subsequent move, clear and delete operations are limited in the 
	range. The cursor does not move.
---*/
	WINDOW *w;	/* IN: Concerned window				*/
	int l;		/* IN: Line where marker starts			*/
	int c;		/* IN: Column where marker starts		*/
	int len;	/* IN: Width (length) of marked range, 0 to \
			   	remove markers		*/
{ 	
	short int pos[2];
	register int size;
	
  ENTER("+tw_mark");
  CheckScreen(w);  
  
  size = w->Ni * w->Nj;
  w->flags &= ~_FULL_, w->marker[0] = 0, w->marker[1] = size;

  if (len > 0)
  {	pos[0] = l, pos[1] = c;
  	if_not(CheckCursor(pos, w->dim))	FINISH;
  	w->flags |=  _FULL_;
  	w->marker[0] = pos[1] + w->Nj * pos[0];	/* lower range	*/
  	w->marker[1] = w->marker[0] + len;	/* upper range 	*/
	w->marker[1] = MIN(w->marker[1], size);
  }  
  
  FIN:
  EXIT(w->marker[1] - w->marker[0]);
}
  
/*==========================================================================
 *			tw_amark
 *==========================================================================*/
int tw_amark (w, pos, len)
/*+++
.PURPOSE Install markers on the window (define a range)
.RETURNS The length (shorter than len if it would exceed the window size)
.REMARKS Markers are useful to define Range in a (sub)window.
	Subsequent move, clear and delete operations are limited in the 
	range. The cursor does not move.
---*/
	WINDOW *w;	/* IN: Concerned window				*/
	int pos;	/* IN: Position from top left corner 		*/
	int len;	/* IN: Width (length) of marked range, 0 to \
			   	remove markers		*/
{ 	
	register int size;
	
  ENTER_DEBUG("+tw_amark");
  CheckScreen(w);  
  
  size = w->Ni * w->Nj;
  w->flags &= ~_FULL_, w->marker[0] = 0, w->marker[1] = size;

  if ( (len > 0) && (pos >= 0) && (pos < size))
  {	w->marker[0] = pos;				/* lower range	*/
	w->marker[1] = MIN(w->marker[0] + len, size);	/* upper range 	*/
	w->flags |=  _FULL_;
  }  
  
  EXIT_DEBUG(w->marker[1] - w->marker[0]);
}
  
/*==========================================================================
 *			tw_open
 *==========================================================================*/
WINDOW *tw_open (wp, name, hl, hc, lines, cols, aw, scr, com)
/*+++
.PURPOSE Open a new WINDOW.
.RETURNS Address of the allocated WINDOW structure, or NULL_WINDOW on error.
.REMARKS --- If lines=0 or cols=0, use the remaininig lines/cols.
	--- The window will not be present UNTIL it is activated,
	and the Command Stacking (com != 0) is NOT enabled.
	--- A Window is cleared; but a SubWindow IS NOT cleared!
	--- Subwindow Commands Stacks are independent from Parent Window
---*/
	WINDOW *wp;	/* IN: Parent window (NULL if a window)		*/
	char *name;	/* IN: Name of window, EOS-terminated		*/
	int hl;		/* IN: Home position (line) of window, <0 from bottom */
	int hc;		/* IN: Home position (col.) of window, < from right */
	int lines;	/* IN: Number of lines of window, or zero	*/
	int cols;	/* IN: Number of columns of window, or zero	*/
	int aw;		/* IN: Default window attributes;\
			_ATTRIBUTE_ uses the home char attribute.	*/
	int scr;	/* IN: Option _SCROLL_ , _FULL_, _DISPLAY_,	\
				_BORDER_, _BORDER2_, _TITLE_ 	*/
	int com;	/* IN: Number of command lines to store		*/
{ 	
	short int	wh[2], wd[2], wl[2];
	WINDOW 		*w, *wt;
	LINE   		*l, *lp;
	int     	i, n, aw1;
	ACHAR		*b;
	COMMAND		*c, *cp;
	
char  *mm_alloc();


  ENTER("*tw_open");

  w = (WINDOW *) 0;

  if_not(Screen)  	/* Was not yet initialized */
	if_not(tw_init(NULL_PTR(char), NULL_PTR(char),TW_cc_default))
		goto BAD;

  TRACE_ED_STRING("Opening Window: ", name);
  if (wp)	TRACE_ED_STR2("Subwindow of: ",wp->id, 8);
#if DEBUG
	TRACE_ED_I("Asked lines:     ", lines);
	TRACE_ED_I("Asked cols :     ", cols);
	TRACE_ED_I("Asked home line: ", hl);
	TRACE_ED_I("Asked home col.: ", hc);
	TRACE_ED_I("Asked attributes:", aw);
	TRACE_ED_I("Asked commands:  ", com);
#endif

	/* Compute the correct window dimensions	*/

  wd[0] = lines;	wd[1] = cols;
  wh[0] = hl;		wh[1] = hc;
  wl[0] = 0;		wl[1] = 0;
  aw1	= aw & (_BOLD_|_UNDERSCORE_|_BLINK_|_REVERSE_);

  if_not(CheckBox(wh, wd, (wp ? wp->dim : terms->dim)))	goto BAD;

	/* If wp is a SubWindow, modify to use Parent Window */
  
  if ((wp) && (Parent(wp)))
  {	wh[0] += wp->home[0], wh[1] += wp->home[1];
  	wp = Parent(wp);
  }

	/* If Graphics or Title is asked for:
	 * - Be sure that limits wl are not reached
	 *	(Bordered Window: 2 lines, 4 if title; 1 line for title)
	 * - Create Parent window, name preceded with ^ via a recursive call
	 * - Create Subwindow if Title, name preceded by `	
	 */

  if (scr & _GRAPHICS_)	wl[0] = 2, wl[1] = 2;		
  if (scr & _TITLE_)	wl[0] = (wl[0] ? 4 : 1);
  if (scr & _BORDER2_)	wl[1] += 2;		/* Add 2 blank columns	*/
  
  if (wl[0] || wl[1])	/* Title and/or Bordered Window	*/
  {	
  	if ((wd[0] <= wl[0]) || (wd[1] <= wl[1]))
	{	ERR_ED_STRING("Bordered/Titled window requires space! ", name);
		FINISH;
   	}
		/* Create Parent Window	*/
	if_not(w = tw_open(wp, name, wh[0], wh[1], wd[0], wd[1], aw1, 
	(scr & ~(_GRAPHICS_|_TITLE_|_SCROLL_|_BORDER2_))|_DISPLAY_, 0))  FINISH;

	oscopy(&(w->id[1]), w->id, 7);	/* Add '^' before name	*/
	w->id[0] = '^';

	if (scr & _GRAPHICS_)		/* Draw Box	*/
	{	tw_attr(w, aw1);
		tw_box(w, 0, 0, 0, 0);
		if (scr & _TITLE_)	/* Add separator line   */
		{	tw_goto(w, 2, 0);
			tw_rule(w, _RIGHT_, w->dim[1]);	/* Add Rule */
			tw_goto(w, 0, 0);
		}
		tw_attr(w, _NORMAL_);
	}
			/* Create the Title Subwindow	*/
	if (scr & _TITLE_)
	{	if_not(wt = tw_open(w, name, wl[0]/4, wl[1]/2, 1, wd[1]-wl[1], 
			(scr & _GRAPHICS_ ? _NORMAL_ : _REVERSE_), 
			_DISPLAY_, 0))	FINISH;
		oscopy(&(wt->id[1]), wt->id, 7);     /* Add '`' before name */
		wt->id[0] = '`';
		tw_cline(wt, name, strlen(name));    /* Write centered title */
	}

	if_not(wp)	/* There was no parent. 
			 * The window just created is it! */
    		wp = w, wh[0] = 0, wh[1] = 0, aw1 = _NORMAL_;

	wh[0] += (wl[0] - (wl[0] > 1)), wh[1] += wl[1]/2;
	wd[0] -= wl[0], wd[1] -= wl[1];
				/* Change position */

  }

	/* Check if the com parameter is correct	*/

  if (scr & _DISPLAY_)	com = 0;
  if (com < 0)	com = 0;

	/* Allocate first WINDOW and LINE structures	*/

  n = sizeof(WINDOW1) + wd[0] * sizeof(LINE);
  if_not(wp) n += wd[0]*(2*sizeof(LINE) + wd[1]*sizeof(ACHAR));
  if_not(w = (WINDOW *)mm_alloc(n))	FINISH;
  ALine(w) = (LINE *)( (char *)w + sizeof(WINDOW1));

  oscfill(w->id, 8, ' ');		/* Copy Name	*/
  i = strlen(name);
  if (i > 8)	i = 8;
  oscopy(w->id, name, i);

	/* Initialize the parameters of WINDOW structure */

  if (wp)	aw1 ^= (wp->attr_init >> 8);		/* Attributes are 
  				relative to Parent Window*/

  w->version	= 0;		/* Unused */
  w->flags 	= (aw1 == terms->attr_init ? Clear : 0);
  w->wpos 	= 0;	
  w->hw 	= terms->flags & TERM_hard;
  w->Ni 	= wd[0];	
  w->Nj 	= wd[1];
  w->i0 	= wh[0];	/* Home relative to parent window... */
  w->j0 	= wh[1];
  w->pos 	= 0;
  w->marker[0] 	= 0;
  w->marker[1] 	= wd[0]*wd[1];
  w->attr_init	= (aw1<<8) | ' ';
  w->attr	= w->attr_init;
  w->help	= NULL_WINDOW;

  Previous(w)	= NULL_WINDOW;
  Next(w)	= NULL_WINDOW;
  Parent(w)	= wp;
  Child(w)	= NULL_WINDOW;

  l = ALine(w);	/* Head of LINE array	*/

		/* Link Windows */
  if (wp)
  {	if_not(Child(wp))	Child(wp) = w;	/* New child window */
  	tw_link(w, Child(wp));			/* List of subwindows */
	  			/* Use same buffer as parent window	*/
	Am0(w) = Am0(wp) + wh[0];
	Am1(w) = Am1(wp) + wh[0];
  	lp   = ALine(wp) + wh[0]; 
	if (aw & _ATTRIBUTE_)		/* Take attribute from current char */
		w->attr_init = (*(*lp + wh[1]) & 0xff00) | ' ';
	w->attr  = w->attr_init;
	w->flags = 0;
  	for (i=wd[0]; --i>=0; l++, lp++)
  	/******	Following Removed: Don't Clear Subwindow !!!! *************
	{	for (b = *lp + wh[1], *l = b, n = wd[1]; --n >= 0; b++)
			*b = w->attr_init;
	} ******************************************** Clear SubWindow	*/
		*l = *lp + wh[1];
  }
  else			/* There is no parent window. Set lines */
  {	tw_link(w, Screen);		/* Link to Other Windows */
				/* Initialize the LINEs structure	*/
	Am0(w) = l + wd[0];
	Am1(w) = Am0(w) + wd[0];
	b = (ACHAR *)(Am1(w) + wd[0]);
	for (i=wd[0]; --i>=0; l++)
		for (*l = b, n = wd[1]; --n >= 0; b++)
			*b = w->attr_init;	/* Clear Window		*/
  }
  Command(w) = NULL_PTR(COMMAND);
  Fields(w)  = NULL_PTR(BUFFER);
  
	/* If not a DISPLAY Window, install commands and other */

  if_not(scr & _DISPLAY_)
  {	n = com * CommandLength;
	if_not(c = (COMMAND *)mm_alloc(n + sizeof(COMMAND)))
		goto BAD;
	Command(w) = c;
	c->size		= n;
	c->used 	= 2;
	c->pointed 	= 0;
	c->pointed_no 	= 0;
	c->first_no 	= 1;
	c->last_no  	= 0;
	if (n)		/* The stack exists */
	{	c->text = (unsigned char *)(c+1);
		oscfill((char *)c->text, n, 0);	/* Fill with zeroes */
		w->flags |= Stacking;		/* Enable Automatic Stacking */
	}
	else	c->text	= NULL_PTR(unsigned char);
	
		/* Install the Input staff */

	if ((wp) && (cp = Command(wp)))	/* Inherits from Parent Window */
		c->exit_cc = cp->exit_cc, 
		c->exit_ar = cp->exit_ar, 
		c->exit_pf = cp->exit_pf;
	else	c->exit_cc = MASK('\r'),
		c->exit_ar = 0,
		c->exit_pf = 0;
	c->last_type = 0, c->last_char = 0;
  }

	/* Add the special options	*/

  w->flags |= scr & (_SCROLL_|_FULL_|_DISPLAY_);

	/* Modify wpos + hw flags	*/

  tw_flags(w);

	/* Nothing was yet output */

  tw_uflag(w, 1);	/* All is modified */

#if DEBUG
  tw_ed(w,1);
#endif
 
  FINISH;

  BAD:		w = NULL_WINDOW;
  FIN:
  EXIT_PTR(WINDOW, w);
}

/*==========================================================================
 *			tw_st
 *==========================================================================*/
int tw_st (w, f, op)
/*+++
.PURPOSE Set or delete flags
.RETURNS The previous flag status
.REMARKS 
---*/
	WINDOW *w;	/* IN: Concerned window			*/
	int f;		/* IN: Flag mask			*/
	int op;		/* IN: 0 to clear, 1 to set		*/
{ 	
	register WINDOW *wc;
	int fc, fm, old_flag;
	
  ENTER("tw_st");

  fm = f;
  if (w == NULL_WINDOW)			/* Can't change flags on Screen	*/
  {	old_flag = Screen->flags & fm;
  	FINISH;
  }  
  old_flag = w->flags & fm;

  if (op && (fm&Echo))	fm |= Present;

  	/* Install also for Parent and subwindows	*/
  if (Parent(w))	tw_st(Parent(w), fm, op);
  else		  	/* Install also Echo, Present for subwindows	*/
  {  	if (op)	w->flags |= fm;
	else	w->flags &= ~fm;
  	for (wc = Child(w), fc = fm & (Echo|Present); wc; wc = Next(wc))
	{  	if (op)	wc->flags |= fc;
		else	wc->flags &= ~fc;
	}
  }
  
  FIN:
  EXIT(old_flag);
}
