/* @(#)twinit.c 17.1.1.1 (ES0-DMD) 01/25/02 17:48:07 */ /*=========================================================================== Copyright (C) 1995 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 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding 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) ----------------------------------------------------------------------------*/ #define DEBUG 0 /* For debugging only */ #define PM_LEVEL LEVEL_TW #define TW_import 0 /* Do not use macro window definitions */ #include 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, "", 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; ACHAR a; ENTER("*tw_open"); 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); }