Technical Notes
OverviewThe virtual screen system is fully compatible with the Spontaneous Assembly console I/O and windowing systems. In fact, separate screens may maintain and access distinct windowing systems simultaneously. Furthermore, the virtual screen system is fully modular, so unnecessary support functions (e.g., buffering or file I/O) are not linked into the application.
The virtual screen system must be initialized by calling _vscreen_init. If disk buffering is to be performed, _set_vsworkbuf must be called to initialize the file I/O portion of the virtual screen system.
Screens are referenced using the addresses of their respective screen descriptors as handles. Screen descriptors are structures of type vscrn, which is defined in VSCREEN.H.
When a screen is visible on its adapter it is said to be open. If two adapters are present in the system, then two screens may be open simultaneously (one on each adapter). Screens are opened by calling _vscreen_open. Unlike windows, screens may not be closed at will, but they are said to be closed if they are not currently visible on their adapter.
The active screen is the only screen which is affected when a console I/O or windowing function is called. Console I/O and windowing functions may be called at any time-even if the active screen is closed. Changes to closed screens are remembered and displayed when those screens are opened. The active screen is selected using _vscreen_select.
Interaction with Console I/O and Windowing Systems
When the virtual screen system is active, all console I/O and windowing functions are directed to the active screen, including changes to the video mode, video page, and screen dimensions. Since any screen may be active at any time, console I/O can be directed to screens whether or not they are visible on their adapter.
Only the active screen is affected when a new adapter, video mode, number of text rows, video page, or similar display characteristic is selected. All other console I/O functions affect only the active screen, including _console_init. The only exception to this rule applies to the documented loss of screen data on unbuffered screens (see Screen Buffering in this section).
There is no need to call _console_init before writing to a virtual screen since _console_init is automatically called by the virtual screen system whenever a screen is created.
These terms are synonymous only when the virtual screen system is NOT being used or when the active screen is also open. If the virtual screen system is being used, applications cannot assume that video BIOS calls will take effect on the active adapter unless the active screen is open.
Each time it is selected, STDSCR inherits the state and contents of the open screen on the display adapter of the active screen. The inherited screen contents are only a copy of the original if the previously-open screen is buffered. STDSCR is automatically selected on the primary display adapter when _vscreen_init is called.
Console I/O performed on STDSCR is temporary. Because STDSCR is unbuffered, text and attributes written to STDSCR are lost whenever another screen is opened on the same adapter. In addition, because STDSCR is re-created each time it is selected, STDSCR characteristics such as the current video mode, current screen dimensions, and current text attribute are all re-initialized whenever STDSCR is selected.
Windowing may be performed on STDSCR, but all windowing should be terminated normally before any other screen is selected or opened on the same adapter or all windowing information will be lost. _win_suspend and _win_resume cannot be used to preserve the state of the windowing system on STDSCR while another screen is selected.
STDSCR is a symbolic constant defined in VSCREEN.H with a value of -1. STDSCR may be used in place of the screen descriptor offset for any function which allows STDSCR as a screen descriptor.
Buffered screens may be buffered to a screen buffer address (in memory) or to a disk file. If a DOS file handle is provided in the screen descriptor, then the screen buffer address in the descriptor is interpreted as a file pointer position at which the screen contents should be buffered. Disk buffering is slower than buffering to memory, but its memory requirements are minimal.
When disk buffering is used, a single disk file is normally used for all buffered screens which are managed by the virtual screen system. The disk file is usually created (_create_h) and sized (_setfsize_h) before the virtual screen system is initialized to ensure that adequate disk space is available for the buffered screens. It is suggested that 16K be allocated within the disk file for each screen which may be buffered, since text screens commonly support resolutions as high as 132x60 (132x60x2=15840 bytes, plus approximately 32 bytes for saved state information). Alternatively, the exact disk buffer requirements for a screen may be determined by calling _vscreen_bufsize.
WARNING! If the screen dimensions change, the size of the required screen buffer also changes. Failure to provide an adequate screen buffer will cause the virtual screen to be treated as if it is unbuffered. The size and address of a screen buffer may only be changed immediately before or after calling _set_vmode, _set_dimens, _vscreen_create, or _console_init.
Screens are flushed to their buffers by the virtual screen system whenever the contents of those screens would otherwise be corrupted or lost. Buffered screens are flushed to their screen buffers without any loss of screen data. Unbuffered, windowed screens are flushed to their window buffers and only lose the contents of STDWIN. Unbuffered, unwindowed screens cannot be flushed to a buffer, so they are blanked in the default text attribute instead. Screens are flushed (or blanked) under the following circumstances:
_vscreen_create expects a screen descriptor of type vscrn to define the initial video adapter, video mode, and video page on which the screen resides as well as the initial screen dimensions, initial video refresh state, inheritance and auto-open status, buffer address, and disk buffer file handle. This descriptor is also used to maintain the screen's console I/O and windowing characteristics, as follows:
typedef struct {
char adapter; /* active adapter (-1=current) */
char vmode; /* active video mode (-1=current) */
char vpage; /* active video page (-1=current) */
char refresh; /* refresh state (1=on,0=off,-1=current) */
unsigned int dimens; /* screen dimensions (-1=current) */
char inherit; /* inherit contents (1=inherit,0=clear) */
char open; /* auto-open flag (1=open,0=not) */
int handle; /* DOS file handle (-1=not disk buffered) */
void far * buffer; /* buffer address */
unsigned int bufsize; /* buffer size (0=unbuffered) */
char reserved[?]; /* console I/O and windowing data */
} vscrn;
WARNING! The definition shown above is a simplified representation and is provided only to identify structure elements which are required for defining and creating screens. The actual VSCRN structure definition in VSCREEN.H should be used any time screen descriptors must be allocated or defined. The actual vscrn structure may be 200 or more bytes in size.
Each vscrn structure element shown above specifies a characteristic of the virtual screen when the screen is created. These fields are defined as follows:
adapter Adapter type of the adapter on which the virtual screen will initially reside. This field is specified using the same values described for the _set_adapter function in the reference section, including -1 for the primary adapter and -2 for the secondary adapter. _vscreen_create returns an error if an invalid adapter is specified. The default is -1 (primary adapter). (WARNING! Specifying -1 or -2 for this field after screens have been opened may produce unexpected results. See Primary Adapter vs. Active Adapter in this section for cautions regarding the primary adapter and the virtual screen system.)
screen.buffer = (void far *)(16*1024);
bufsize Buffer size. This value specifies the size of the screen buffer specified by buffer. The screen is not buffered if the buffer size is insufficient to hold the screen contents and video state or if buffer is -1. The default is 0 (unbuffered).
All other initial screen state information (current and default text attributes, video border state, video border color, cursor state, and cursor type) is inherited from the open screen on the specified display adapter exactly as it would be if _console_init were called on that adapter. If the specified adapter has no open screen, then this information is inherited from the current hardware state of the specified adapter.
The new screen is NOT automatically opened when it is created unless the open flag is set in the screen descriptor. Furthermore, the created screen is NOT automatically selected as the active screen unless it is automatically opened AND the newly-opened screen supersedes STDSCR. This behavior is consistent with the behavior of _vscreen_open.
There is no need to call _console_init on the newly-created screen-this is performed automatically when the screen is created. However, _win_init must be called on the new screen if windowing is to be performed.
The _get_adapters and _get_adaptinfo functions (in the console I/O unit) return the information required to properly initialize the screen descriptor fields explained above. _get_adapters indicates which adapters are present in the system as well as their attached monitors. _get_adaptinfo returnsthe characteristics of a specified adapter, including the number of supported video display pages as well as current and supported screen dimensions.
When disk buffering is used with virtual screens, the offset within the file to buffer to is specified in the buffer field of the VSCRN structure. When initializing this field with a long int (an offset into a file), the value must be type cast as a void far *, as follows:
screen.buffer = (void far *)(16*1024);
WARNING! Fields within a screen descriptor must not be modified after the screen has been created since this structure is modified dynamically by the console I/O and windowing systems. Modifications by the programmer after calling _vscreen_create will produce undefined results.
STDSCR is automatically created and opened each time it is selected as the active screen. STDSCR inherits the state and contents of the previously-open screen on the display adapter of the previously-active screen. The inherited screen contents are only a copy of the original if the previously-open screen is buffered.
Console I/O and windowing may be performed on the active screen whether or not it is open, although these operations are generally faster on screens which are not visible. _vscreen_open must be called to ensure that any given screen is actually visible.
If another screen is already open on the same video page of the same adapter before this function is called, then the state of the previous screen is saved and the contents of that screen are flushed to its buffer (if any) before the new screen is made visible.
If the specified screen is not already visible on its adapter, its adapter is reprogrammed as required to support the video mode, video page, screen dimensions, refresh state, border color, cursor shape, etc. of the newly-opened screen. The contents of the new screen are then copied to its video page if the screen is buffered and the screen is not already on its video page. The screen is blanked when it is opened only if the screen is unbuffered and it is not already present on its assigned video page. No change takes place if the screen is already visible on its adapter when this function is called.
Once _vscreen_remove has been called, the old screen descriptor may be reused or returned to its memory pool, if applicable.
_vscreen_suspend does NOT necessarily restore the video state to the state which was active when _vscreen_init was called. _save_vstate and _restore_vstate or their equivalents must be used for this purpose if this is required.
Once _vscreen_suspend has been called, _vscreen_resume may be called to restore the virtual screen system to its pre-_vscreen_suspend condition. _vscreen_resume accomplishes this by reselecting the active screen and open screens on both adapters. Text and attributes are only restored on buffered screens or screens which have active windowing systems. All unbuffered screens without active windowing systems are blanked in the screen's default text attribute. Unbuffered screens with active windowing systems lose only the contents of STDWIN when _vscreen_resume is called.
WARNING! Once _vscreen_suspend has been called, the results are unpredictable if virtual screen functions are called before _vscreen_resume.
#include
#include
#define VSWBUFSIZ 262 /* work buffer size */
#define FILBUFSIZ 16*1024 /* file buffer size */
vscrn primary = {-1,-1,-1,-1,1,1,0,-1,0,0}; /* PRIMARY screen (inherit, auto-open) */
vscrn secondary = {-2,-1,-1,-1,0,0,0,-1,0,0}; /* SECONDARY screen (noinherit, closed) */
saadapt adaptinfo; /* structure for adapter information */
char buffile[] = "{SCREEN}.BUF"; /* temp screen buffer filename */
char vswbuf[VSWBUFSIZ]; /* work buffer for disk buffering */
char dual = 1; /* 0=single monitor, 1=dual monitor */
void main()
{
...
if(mk_screens() == -1)
exit(1);
...
}
int mk_screens(void)
{
char dflags, pagecnt, cols, rows, vpage;
unsigned int handle;
_adapter_init(); /* init for dual adapters */
_vscreen_init(); /* init virtual screen system */
/* ------ check for secondary adapter */
if(!_get_adaptinfo(-2, &adaptinfo)); /* secondary adapter present? */
{
secondary.adapter = -1; /* n: use primary adapter */
dual = 0; /* clear dual monitor flag */
_get_adaptinfo(-1, &adaptinfo); /* get primary adapter info */
/* ------ no secondary adapter, try to use second page of primary adapter */
if(adaptinfo.pagecnt) /* if more than one video page */
{
primary.vpage = adaptinfo.vpage;
adaptinfo.vpage ^= 1; /* if page is even, use page 1 */
adaptinfo.vpage &= 1; /* if page is odd, use page 0 */
secondary.vpage = adaptinfo.vpage; /* SECONDARY = other page, unbuffered */
}
/* ------ only one page on one adapter, use disk buffering */
else /* if only one video page */
{
_set_vsworkbuf(vswbuf, VSWBUFSIZ); /* declare disk work buffer */
if((handle = _create_h("{SCREEN}.BUF", FA_NORM)) != 0)
return(1); /* return error */
else
{
if(_setfsize_h(handle, FILBUFSIZ) == -1) /* ensure adequate disk space */
return(1); /* return error */
else
{
secondary.handle = handle; /* indicate file handle */
secondary.bufsize = FILBUFSIZ; /* indicate buffer size */
/* (offset 0 is the default) */
}
}
}
}
/* ------ create and open screens */
if(_vscreen_create(&primary) == -1)
return(-1); /* return error */
if(dual != 0)
secondary.open = 1;
if(_vscreen_create(&secondary) != 0)
return(-1); /* return error */
else
return(0); /* return success */
}
After calling the _mk_screens function shown above, PRIMARY is the active screen and has inherited the contents and state of the primary display adapter. SECONDARY resides on the secondary display adapter and is open only if two adapters are present; otherwise it is defined on the primary display adapter and is not yet visible. The DUAL variable indicates whether or not the system is a dual monitor system. The program may select either screen for console I/O or windowing at any time by calling _vscreen_select. If DUAL=0, then _vscreen_open must be called with SECONDARY as the screen descriptor to view the secondary virtual screen.