mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1239 lines
34 KiB
1239 lines
34 KiB
/* zmwin.c - windowing functions for ZM.c
|
|
*
|
|
* HISTORY:
|
|
* 09-Mar-87 danl Move GetAliases to KeyManager
|
|
* 09-Mar-87 danl Move DoScipt to first in KeyManager
|
|
* 11-Apr-1987 mz Use PASCAL/INTERNAL
|
|
* 15-Apr-1987 mz Fix up insufficient arguments
|
|
* 05-May-87 danl Add fCheckMail
|
|
* 15-Jun-87 danl KeyManager: always call GetAliases
|
|
* 19-Jun-87 danl CheckMail: output current time
|
|
* 29-Jun-87 danl Display current time at left of cmd title
|
|
* 01-Jul-87 danl test idoc, inote against -1 not ERROR
|
|
* 03-Jul-87 danl Make local string for time display: CheckMail
|
|
* 15-Jul-87 danl Use fNotifyTools flags
|
|
* 20-Jul-87 danl Use ReadKey instead of _getch
|
|
* 21-Aug-1987 mz Change references from MAXARG to MAXLINELEN
|
|
* Speed up BlankWindow
|
|
* 24-Aug-1987 mz Remove unneeded argument to DownloadMail
|
|
* 02-Sep-87 danl BlankWindow: more speed up
|
|
* 24-Sep-87 danl Add ySize to ClearScrn call
|
|
* 19-Nov-87 sz Add code for BeepOnMail
|
|
* 17-Mar-1988 mz Only do periodic mail stuff if allowed
|
|
* 12-Oct-1989 leefi v1.10.73, added inclusion of <io.h>
|
|
* 12-Oct-1989 leefi v1.10.73, added inclusion of <stdlib.h>
|
|
* 12-Oct-1989 leefi v1.10.73, added inclusion of <stdio.h>
|
|
* 12-Oct-1989 leefi v1.10.73, added inclusion of <string.h>
|
|
*
|
|
*/
|
|
|
|
#define INCL_DOSINFOSEG
|
|
|
|
#include <assert.h>
|
|
#include <malloc.h>
|
|
#include <time.h>
|
|
#include <io.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <memory.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
|
|
#include "wzport.h"
|
|
#include <tools.h>
|
|
#include "dh.h"
|
|
|
|
#include "zm.h"
|
|
|
|
extern BOOL screenWriteInProgress; /* if whole window write in progress */
|
|
extern PCHAR_INFO pLocalScreen; /* local screen buffer */
|
|
HW winList = NULL; /* head of window list, active on top */
|
|
|
|
|
|
/* SendMessage - address a message to a particular window
|
|
*
|
|
* hWnd window for message
|
|
* command command for message
|
|
*/
|
|
VOID SendMessage (HW hWnd, INT command, ...)
|
|
{
|
|
va_list vaPtr;
|
|
|
|
if ( hWnd != NULL ) {
|
|
va_start (vaPtr, command);
|
|
(*(hWnd->wndProc)) (hWnd, command, va_arg (vaPtr, WDATA));
|
|
va_end (vaPtr);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* SpacePad - pad out a line to a specific length with spaces.
|
|
*
|
|
* SpacePad is used to forcibly blank the remainder of a line during display.
|
|
* BlankLine is not useful here as we are displaying a significant portion
|
|
* of the line with other-than-white-space.
|
|
*
|
|
* p pointer to beginning of NUL-terminated line
|
|
* n length of line to pad out to.
|
|
*/
|
|
VOID PASCAL INTERNAL SpacePad (PSTR p, INT n)
|
|
{
|
|
register INT c = strlen (p);
|
|
|
|
if (c < n)
|
|
memset(p + c, ' ', n - c);
|
|
}
|
|
|
|
|
|
|
|
/* GenClip - generalized clipping/intersection of two boxes
|
|
*
|
|
* bgBox background box being obscured
|
|
* fgBox foreground box doing the obscuring
|
|
* pVisBox pointer to a subset of bgBox that will be visible
|
|
* pIntBox pointer to intersection box
|
|
*/
|
|
VOID PASCAL INTERNAL GenClip (BOX bgBox, BOX fgBox, PBOX pVisBox, PINT pcVis, PBOX pIntBox, PINT pcInt)
|
|
{
|
|
PBOX pBox = NULL;
|
|
|
|
if (pcVis != NULL)
|
|
*pcVis = 0;
|
|
if (pcInt != NULL)
|
|
*pcInt = 0;
|
|
|
|
/* test for absence of clipping */
|
|
if (bgBox.bottom < fgBox.top || bgBox.top > fgBox.bottom || bgBox.right <
|
|
fgBox.left || bgBox.left > fgBox.right) {
|
|
if (pVisBox != NULL) {
|
|
*pVisBox = bgBox;
|
|
(*pcVis)++;
|
|
}
|
|
return;
|
|
}
|
|
pBox = pVisBox;
|
|
/* clip the top portion of background box */
|
|
if (INRANGE (bgBox.top, fgBox.top, bgBox.bottom)) {
|
|
if (bgBox.top <= fgBox.top - 1 && pBox != NULL) {
|
|
*pBox = bgBox;
|
|
pBox->bottom = fgBox.top - 1;
|
|
pBox++;
|
|
(*pcVis)++;
|
|
}
|
|
bgBox.top = fgBox.top;
|
|
}
|
|
/* clip the bottom portion of background box */
|
|
if (INRANGE (bgBox.top, fgBox.bottom, bgBox.bottom)) {
|
|
if (fgBox.bottom + 1 <= bgBox.bottom && pBox != NULL) {
|
|
*pBox = bgBox;
|
|
pBox->top = fgBox.bottom + 1;
|
|
pBox++;
|
|
(*pcVis)++;
|
|
}
|
|
bgBox.bottom = fgBox.bottom;
|
|
}
|
|
/* clip the left portion of the background box */
|
|
if (INRANGE (bgBox.left, fgBox.left, bgBox.right)) {
|
|
if (bgBox.left <= fgBox.left - 1 && pBox != NULL) {
|
|
*pBox = bgBox;
|
|
pBox->right = fgBox.left - 1;
|
|
pBox++;
|
|
(*pcVis)++;
|
|
}
|
|
bgBox.left = fgBox.left;
|
|
}
|
|
/* clip the right portion of the background box */
|
|
if (INRANGE (bgBox.left, fgBox.right, bgBox.right)) {
|
|
if (fgBox.right + 1 <= bgBox.right && pBox != NULL) {
|
|
*pBox = bgBox;
|
|
pBox->left = fgBox.right + 1;
|
|
(*pcVis)++;
|
|
}
|
|
bgBox.right = fgBox.right;
|
|
}
|
|
if (pIntBox != NULL) {
|
|
*pIntBox = bgBox;
|
|
if (pcInt != NULL)
|
|
*pcInt = 1;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* ApplyVis - apply a procedure to all visible portions of a box that are
|
|
* obscured by all windows starting at a particular one and ending at another.
|
|
*
|
|
* box box that is being clipped
|
|
* hWndStart beginning window to start clipping on
|
|
* hWndStop window to terminate clipping
|
|
* proc procedure to call on each visible portion
|
|
* arg first of arguments to be passed to procedure
|
|
*/
|
|
VOID PASCAL INTERNAL ApplyVis (BOX box, HW hWndStart, HW hWndStop, PVISPROC proc, INT x, LPSTR p, INT a)
|
|
{
|
|
INT cBox, i;
|
|
BOX vis[4];
|
|
|
|
if (hWndStart == NULL || hWndStart == hWndStop)
|
|
(*proc) (hWndStop, box, x, p, a);
|
|
else {
|
|
GenClip (box, hWndStart->win, vis, &cBox, NULL, NULL);
|
|
for (i = 0; i < cBox; i++)
|
|
ApplyVis (vis[i], hWndStart->pNext, hWndStop, proc, x, p, a);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* TextBox - display text for a window.
|
|
*
|
|
* TextBox is called by WzTextOut to display known, visible text from a window.
|
|
* The regions displayed are enumerated by ApplyVis.
|
|
*
|
|
* hWnd handle of window being displayed
|
|
* box box being output relative to screen
|
|
* x leftmost point in original string
|
|
* p pointer to original string
|
|
* a attribute for screen
|
|
*/
|
|
VOID PASCAL INTERNAL TextBox (HW hWnd, BOX box, INT x, LPSTR p, INT a)
|
|
{
|
|
|
|
CHAR buf[MAXLINELEN];
|
|
INT cch = box.right - box.left + 1;
|
|
int i;
|
|
|
|
hWnd; /* unused parameter */
|
|
|
|
//
|
|
// write to local screen buffer - will also write line if minor update
|
|
//
|
|
for ( i = 0; i < cch; i++ ) {
|
|
pLocalScreen[xSize * box.top + box.left + i].Char.AsciiChar
|
|
= *(p + box.left - x + i);
|
|
pLocalScreen[xSize * box.top + box.left + i].Attributes = (WORD) a;
|
|
}
|
|
|
|
if ( ! screenWriteInProgress) {
|
|
Move (p + box.left - x, buf, cch);
|
|
LineOut (box.left, box.top, buf, cch, a);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/* WinOut - display window text mapping entire window.
|
|
*
|
|
* hWnd window handle to output
|
|
* x, y position relative to origin of entire window
|
|
* p pointer to character string to display
|
|
* c number of bytes to display
|
|
* a attribute to display
|
|
*/
|
|
VOID PASCAL INTERNAL WinOut (HW hWnd, INT x, INT y, LPSTR p, INT c, INT a)
|
|
{
|
|
BOX line;
|
|
INT i;
|
|
|
|
/* convert text output into a box */
|
|
line.top = line.bottom = y + hWnd->win.top;
|
|
line.left = x + hWnd->win.left;
|
|
line.right = line.left + c - 1;
|
|
|
|
/* clip text box into intersection of box with window */
|
|
GenClip (line, hWnd->win, NULL, NULL, &line, &i);
|
|
if (i == 0)
|
|
return;
|
|
|
|
/* apply textbox to all visible windows */
|
|
ApplyVis (line, winList, hWnd, TextBox, line.left, p, a );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* StreamOut - stream text out at the cursor location of hWnd. move text into
|
|
* content region if present. handle all CR's and LF's
|
|
*
|
|
* arguements:
|
|
* hWnd window handle to preform output in
|
|
* pStr pointer to string to output
|
|
* c number of chars to output
|
|
* style text style, attribute byte passed to winout
|
|
*
|
|
* returns:
|
|
* no return values
|
|
*
|
|
*/
|
|
VOID PASCAL INTERNAL StreamOut ( HW hWnd, PSTR pStr, INT c, INT style )
|
|
{
|
|
|
|
PSTR pEnd = NULL;
|
|
CHAR chEnd, chTmp;
|
|
INT width = TWINWIDTH ( hWnd );
|
|
INT height = TWINHEIGHT ( hWnd );
|
|
INT i, temp;
|
|
|
|
chEnd = *( pStr + c );
|
|
*( pStr + c ) = '\0';
|
|
|
|
while ( c-- != 0 ) {
|
|
if ( *pStr == '\r' ) {
|
|
hWnd->crsrX = 0;
|
|
pStr++;
|
|
} else if ( *pStr == '\n' ) {
|
|
( hWnd->crsrY )++;
|
|
if ( hWnd->crsrY >= height ) {
|
|
( hWnd->crsrY )--;
|
|
ScrollWindow ( hWnd, 1, FORWARD );
|
|
}
|
|
pStr++;
|
|
} else if ( *pStr == '\b' ) {
|
|
( hWnd->crsrX )--;
|
|
if ( hWnd->crsrX < 0 ) {
|
|
hWnd->crsrX = width - 1;
|
|
( hWnd->crsrY )--;
|
|
if ( hWnd->crsrY < 0 ) {
|
|
hWnd->crsrY = 0;
|
|
ScrollWindow ( hWnd, 1, BACKWRD );
|
|
}
|
|
}
|
|
WzTextOut ( hWnd, hWnd->crsrX, hWnd->crsrY, strBLANK, 1,
|
|
DefNorm);
|
|
pStr++;
|
|
} else
|
|
{
|
|
pEnd = strbscan ( pStr, strCRLF );
|
|
chTmp = *pEnd;
|
|
*pEnd = '\0';
|
|
i = strlen ( pStr );
|
|
while ( i > 0 ) {
|
|
temp = min ( width - hWnd->crsrX, i );
|
|
WzTextOut ( hWnd, hWnd->crsrX, hWnd->crsrY,
|
|
pStr, temp, style );
|
|
hWnd->crsrX += temp;
|
|
if ( hWnd->crsrX >= width ) {
|
|
hWnd->crsrX = 0;
|
|
( hWnd->crsrY )++;
|
|
if ( hWnd->crsrY >= height ) {
|
|
( hWnd->crsrY )--;
|
|
ScrollWindow ( hWnd, 1,
|
|
FORWARD );
|
|
}
|
|
}
|
|
pStr += temp;
|
|
i -= temp;
|
|
}
|
|
*pEnd = chTmp;
|
|
pStr = pEnd;
|
|
}
|
|
if ( winList == hWnd )
|
|
SetCursor ( hWnd, hWnd->crsrX, hWnd->crsrY );
|
|
}
|
|
*pStr = chEnd;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* WzTextOut - display text at a particular position in the window. Perform
|
|
* all clipping necessary. Perform the text output inside the
|
|
* border with specified style.
|
|
*
|
|
* hWnd window handle to output.
|
|
* x, y position relative to origin of text window to begin display
|
|
* p pointer to character string to output
|
|
* c number of bytes to display
|
|
* style text style, attribute byte passed to winOut
|
|
*/
|
|
VOID PASCAL INTERNAL WzTextOut (HW hWnd, INT x, INT y, LPSTR p, INT c, INT style )
|
|
{
|
|
BOX aBox;
|
|
INT w = TWINWIDTH (hWnd);
|
|
INT i;
|
|
|
|
if ( y >= 0 && y < TWINHEIGHT ( hWnd ) && x >= 0 && x < w ) {
|
|
x += hWnd->lLeft;
|
|
y += 1;
|
|
|
|
/* update window content region? */
|
|
if ( hWnd->pContent != NULL ) {
|
|
/* clip text to window content region, note off set from hWnd->win */
|
|
aBox.top = aBox.bottom = hWnd->win.top + y;
|
|
aBox.left = hWnd->win.left + x;
|
|
aBox.right = aBox.left + c;
|
|
GenClip ( aBox, hWnd->win, NULL, NULL, &aBox, &i );
|
|
|
|
/* translate resultant box to window content region coordinates */
|
|
aBox.top -= ( hWnd->win.top + 1 );
|
|
aBox.left -= ( hWnd->win.left + hWnd->lLeft );
|
|
aBox.right -= ( hWnd->win.left + hWnd->lLeft );
|
|
if ( i != 0 )
|
|
Move ( ( LPSTR ) p, ( LPSTR ) hWnd->pContent +
|
|
( ( aBox.top * w ) + aBox.left ) * sizeof ( CHAR
|
|
), aBox.right - aBox.left );
|
|
}
|
|
|
|
WinOut (hWnd, x, y, p, min(c, w - x + 1), style);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* ClearLine - draw a blank line
|
|
*
|
|
* hWnd handle of window to blank
|
|
* i index of line to blank
|
|
*/
|
|
VOID PASCAL INTERNAL ClearLine (HW hWnd, INT i)
|
|
{
|
|
INT w = TWINWIDTH (hWnd);
|
|
CHAR line[MAXLINELEN];
|
|
|
|
memset ( line, ' ', w);
|
|
WzTextOut (hWnd, 0, i, line, w, DefNorm);
|
|
}
|
|
|
|
|
|
|
|
/* DisplayTitle - display title line of a window
|
|
*
|
|
* hWnd handle of window
|
|
*/
|
|
VOID PASCAL INTERNAL DisplayTitle (HW hWnd)
|
|
{
|
|
INT len;
|
|
INT w = TWINWIDTH (hWnd);
|
|
CHAR line[MAXLINELEN];
|
|
PSTR p = line;
|
|
INT i = hWnd->lLeft + hWnd->lRight;
|
|
|
|
if ( hWnd->lLeft )
|
|
*p++ = (CHAR) C_TL;
|
|
memset ( p, C_H, w);
|
|
p += w;
|
|
if ( hWnd->lRight )
|
|
*p = (CHAR) C_TR;
|
|
if (hWnd->pTitle != NULL) {
|
|
len = min ( strlen (hWnd->pTitle), (size_t)w );
|
|
memmove ( & line[(w + i - len)/2], (hWnd->pTitle), len);
|
|
}
|
|
WinOut (hWnd, 0, 0, line, w + i, DefNorm);
|
|
CheckTimeDisplay ( -1L );
|
|
}
|
|
|
|
|
|
/* DisplayFooter - display footer in bottom border
|
|
*
|
|
* hWnd handle of window
|
|
*/
|
|
VOID PASCAL INTERNAL DisplayFooter (HW hWnd)
|
|
{
|
|
INT len;
|
|
INT w = TWINWIDTH (hWnd);
|
|
CHAR line[MAXLINELEN];
|
|
PSTR p = line;
|
|
INT y;
|
|
INT i = hWnd->lLeft + hWnd->lRight;
|
|
|
|
if ( !hWnd->lBottom )
|
|
return;
|
|
if ( hWnd->lLeft )
|
|
*p++ = (CHAR) C_BL;
|
|
memset (p, C_H, w);
|
|
p += w;
|
|
if ( hWnd->lRight )
|
|
*p = (CHAR) C_BR;
|
|
if (hWnd->pFooter != NULL) {
|
|
len = min ( strlen (hWnd->pFooter), (size_t)w - 2 );
|
|
memmove ( & line[ 2 ], (hWnd->pFooter), len);
|
|
}
|
|
if ( ( hWnd->pFooter !=NULL) && !strcmpis ( hWnd->pFooter, strMORE ) ) {
|
|
y = hWnd->win.bottom - hWnd->win.top;
|
|
WinOut (hWnd, 0, y, line, 2, DefNorm );
|
|
WinOut (hWnd, 2, y, line + 2, len, DefBold );
|
|
WinOut (hWnd, 2 + len, y, line + 2 + len, w - len -2 + i, DefNorm );
|
|
}
|
|
else
|
|
WinOut (hWnd, 0, hWnd->win.bottom - hWnd->win.top, line, w + i, DefNorm);
|
|
}
|
|
|
|
|
|
|
|
/* BlankWindow - draw a blank window.
|
|
*
|
|
* hWnd handle of window to blank
|
|
* fBorder TRUE => draw border, FALSE => erase border
|
|
*/
|
|
VOID PASCAL INTERNAL BlankWindow (HW hWnd, FLAG fBorder)
|
|
{
|
|
INT w = TWINWIDTH (hWnd);
|
|
INT iBorder = hWnd->lLeft + hWnd->lRight;
|
|
INT i;
|
|
CHAR line[MAXLINELEN];
|
|
PSTR p = line;
|
|
|
|
|
|
if (fBorder) {
|
|
/* generate upper border */
|
|
DisplayTitle (hWnd);
|
|
|
|
/* generate content line
|
|
* some code removed and optimized N.B. if fBorder then we only
|
|
* draw border, we do NOT blank content
|
|
*/
|
|
if ( iBorder ) {
|
|
*p = (CHAR) C_V;
|
|
for (i = 0; i < TWINHEIGHT (hWnd); i++) {
|
|
WinOut (hWnd, 0, i+1, p, 1, DefNorm);
|
|
WinOut (hWnd, w + iBorder - 1, i + 1, p, 1, DefNorm);
|
|
}
|
|
}
|
|
|
|
DisplayFooter (hWnd);
|
|
} else {
|
|
memset (line, ' ', w + iBorder);
|
|
for (i = 0; i < TWINHEIGHT (hWnd) + 2; i++)
|
|
WinOut (hWnd, 0, i, line, w + iBorder, DefNorm);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* ScrollWindow - scrolls a window which has a content region
|
|
*
|
|
* arguements:
|
|
* hWnd handle of window
|
|
* numLines number of lines to scroll it
|
|
* dir direction
|
|
* any +num scrolls window down (contents go up)
|
|
* any -num scrolls window up (contents go down)
|
|
* returns:
|
|
* no return value
|
|
*
|
|
*/
|
|
VOID PASCAL INTERNAL ScrollWindow ( HW hWnd, INT numLines, INT direction )
|
|
{
|
|
INT width = TWINWIDTH ( hWnd );
|
|
INT height = TWINHEIGHT ( hWnd );
|
|
INT cbContent;
|
|
INT cbBlank;
|
|
INT cbMove;
|
|
|
|
if ((hWnd->pContent == NULL) || (numLines <= 0) || (direction == 0))
|
|
return;
|
|
|
|
numLines = min (height, numLines);
|
|
cbContent = width * height * sizeof ( CHAR );
|
|
cbBlank = width * numLines * sizeof ( CHAR );
|
|
cbMove = cbContent - cbBlank;
|
|
|
|
/* cbContent number of bytes in total content region
|
|
* cbBlank number of bytes of blanking
|
|
* cbMove number of bytes to move
|
|
*/
|
|
if (direction > 0) {
|
|
if (cbMove > 0)
|
|
Move ((LPSTR) (hWnd->pContent + cbBlank),
|
|
(LPSTR) hWnd->pContent, cbMove);
|
|
Fill ((LPSTR) (hWnd->pContent + cbMove), ' ', cbBlank);
|
|
}
|
|
else {
|
|
if (cbMove > 0)
|
|
Move ((LPSTR) hWnd->pContent,
|
|
(LPSTR) (hWnd->pContent + cbBlank), cbMove);
|
|
Fill ((LPSTR) hWnd->pContent, ' ', cbBlank);
|
|
}
|
|
|
|
//
|
|
// If the window is on the top,
|
|
// or, if the command window is on top and this is the second window,
|
|
// use video scrolling. don't use video scrolling for command window.
|
|
//
|
|
|
|
if ( (hWnd != hCommand) &&
|
|
( (hWnd == winList) ||
|
|
( (winList == hCommand) && (hWnd == winList->pNext) ) ) ) {
|
|
|
|
if (direction > 0 && numLines > 0)
|
|
ScrollUp (hWnd->win.left+hWnd->lLeft, hWnd->win.top+1,
|
|
hWnd->win.right-hWnd->lRight, hWnd->win.bottom-hWnd->lBottom,
|
|
numLines, DefNorm);
|
|
else
|
|
if (direction < 0 && numLines > 0)
|
|
ScrollDn (hWnd->win.left+hWnd->lLeft, hWnd->win.top+1,
|
|
hWnd->win.right-hWnd->lRight, hWnd->win.bottom-hWnd->lBottom,
|
|
numLines, DefNorm);
|
|
else
|
|
DrawWindow ( hWnd, FALSE );
|
|
}
|
|
else
|
|
DrawWindow ( hWnd, FALSE );
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* DrawWindow - displays a window and border on the the screen
|
|
*
|
|
* hWnd handle of window
|
|
* fBorder TRUE => redraw border, FALSE => just repaint
|
|
*/
|
|
VOID PASCAL INTERNAL DrawWindow (HW hWnd, FLAG fBorder)
|
|
{
|
|
INT i;
|
|
#ifdef NT
|
|
SMALL_RECT screenArea;
|
|
|
|
//
|
|
// write whole screen as a block to the console for better performance
|
|
//
|
|
startScreenWrite ( );
|
|
#endif
|
|
|
|
if (fBorder)
|
|
BlankWindow (hWnd, TRUE);
|
|
|
|
/* display all content lines */
|
|
for (i = 0; i < TWINHEIGHT (hWnd); i++)
|
|
(*(hWnd->wndProc)) (hWnd, PAINT, i);
|
|
|
|
#ifdef NT
|
|
screenArea.Left = ( SHORT ) hWnd->win.left;
|
|
screenArea.Top = ( SHORT ) hWnd->win.top;
|
|
screenArea.Right = ( SHORT ) hWnd->win.right;
|
|
screenArea.Bottom = (SHORT ) hWnd->win.bottom;
|
|
|
|
endScreenWrite ( &screenArea );
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
/* FitWinToScrn - make sure a box can fit on the screen, shrink it if necessary.
|
|
*
|
|
* arguments:
|
|
* pBox pointer to box to check
|
|
*
|
|
* return value:
|
|
* none. box pointed to by pBox is set to fit on screen
|
|
*
|
|
* IMPORTANT:
|
|
* FitWinToScrn ( ) assumes all box coordinates are positive.
|
|
*/
|
|
VOID PASCAL INTERNAL FitWinToScrn ( PBOX pBox )
|
|
{
|
|
pBox->top = ( pBox->top >= ySize ) ? ySize - 1 : pBox->top;
|
|
pBox->left = ( pBox->left >= xSize ) ? xSize - 1 : pBox->left;
|
|
pBox->bottom = ( pBox->bottom >= ySize ) ? ySize - 1 : pBox->bottom;
|
|
pBox->right = ( pBox->right >= xSize ) ? xSize - 1 : pBox->right;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* CreateWindow - create a new window instance and put it on the top of the
|
|
* window pile on the screen. Display the window too.
|
|
*
|
|
* x, y location of upper left corner of window on screen
|
|
* xSize, ySize dimensions of the window
|
|
* if xSize < 0 then permissible to not show left/right
|
|
* border if they are at screen edge
|
|
* if ySize < 0 then do not show bottom border
|
|
* wndProc window procedure to call for input
|
|
* keyProc procedure to call for undefined keys
|
|
* data optional extra data to be passed to window procedure
|
|
*
|
|
* returns handle to window
|
|
*/
|
|
HW PASCAL INTERNAL CreateWindow (PSTR pTitle, INT x, INT y, INT width, INT height, PWNDPROC wndProc, PKEYPROC keyProc, WDATA data)
|
|
{
|
|
FLAG fNoVBorder = FALSE;
|
|
FLAG fNoHBorder = FALSE;
|
|
HW hTmp;
|
|
|
|
if ((hTmp = (HW ) ZMalloc (sizeof (*hTmp))) == NULL)
|
|
return NULL;
|
|
hTmp->pTitle = pTitle == NULL ? pTitle : ZMMakeStr (pTitle);
|
|
hTmp->pFooter = NULL;
|
|
/* default pContent to NULL */
|
|
hTmp->pContent = NULL;
|
|
hTmp->contSize = 0;
|
|
hTmp->crsrX = 0;
|
|
hTmp->crsrY = 0;
|
|
if ( width < 0 ) {
|
|
width = -width;
|
|
fNoVBorder = !fWinBorders;
|
|
}
|
|
if ( height < 0 ) {
|
|
height = - height;
|
|
fNoHBorder = !fWinBorders;
|
|
}
|
|
SetRect ( &( hTmp->win ), y, x, y + height - 1, x + width - 1 );
|
|
FitWinToScrn ( &( hTmp->win ) );
|
|
hTmp->lLeft = ( fNoVBorder && hTmp->win.left == 0 ? 0 : 1 );
|
|
hTmp->lRight = ( fNoVBorder && hTmp->win.right == xSize - 1 ? 0 : 1 );
|
|
hTmp->lBottom= ( fNoHBorder ? 0 : 1 );
|
|
hTmp->fsFlag = WF_BLINK;
|
|
hTmp->wndProc = wndProc;
|
|
hTmp->keyProc = keyProc;
|
|
hTmp->pNext = winList;
|
|
winList = hTmp;
|
|
|
|
(*wndProc) (hTmp, CREATE, data);
|
|
DrawWindow ( hTmp, TRUE );
|
|
SetCursor ( hTmp, hTmp->crsrX, hTmp->crsrY );
|
|
return hTmp;
|
|
}
|
|
|
|
|
|
/* defWndProc - default window proc
|
|
*
|
|
* Handles most common operations
|
|
*/
|
|
VOID PASCAL INTERNAL defWndProc (HW hWnd, INT command, WDATA data)
|
|
{
|
|
INT width = TWINWIDTH (hWnd);
|
|
INT height = TWINHEIGHT (hWnd);
|
|
|
|
switch (command) {
|
|
/* Paint a line on the screen. If there's a content area and
|
|
* the line to be painted is within the screen, output it
|
|
* from the content area
|
|
*/
|
|
case PAINT:
|
|
if (hWnd->pContent != NULL)
|
|
if ((INT)data < height)
|
|
WzTextOut (hWnd, 0, (INT)data, hWnd->pContent + data * width,
|
|
width, DefNorm);
|
|
break;
|
|
|
|
case CLOSE:
|
|
if (hWnd->pContent)
|
|
PoolFree (hWnd->pContent);
|
|
break;
|
|
|
|
case DISPLAY:
|
|
SendMessage (hWnd, DISPLAYSTR, data);
|
|
SendMessage (hWnd, DISPLAYSTR, strCRLF);
|
|
break;
|
|
|
|
case DISPLAYSTR:
|
|
StreamOut ( hWnd, (PSTR) data, strlen ((PSTR) data), DefNorm);
|
|
break;
|
|
|
|
case REGENCONT:
|
|
if (hWnd->pContent != NULL)
|
|
Fill (hWnd->pContent, ' ', height * width);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/* BringToTop - bring a background window to the top position. Draw it on
|
|
* the screen if requested. Place the cursor at crsrX, crsrY
|
|
*
|
|
* hWnd handle of window to be made top
|
|
* fDisplay TRUE => window is to be displayed
|
|
*/
|
|
VOID PASCAL INTERNAL BringToTop (HW hWnd, FLAG fDisplay)
|
|
{
|
|
HW hTmp, hPrev;
|
|
|
|
hTmp = winList;
|
|
hPrev = NULL;
|
|
|
|
while (hTmp != NULL)
|
|
if (hTmp == hWnd)
|
|
break;
|
|
else {
|
|
hPrev = hTmp;
|
|
hTmp = hTmp->pNext;
|
|
}
|
|
if (hPrev != NULL) {
|
|
hPrev->pNext = hTmp->pNext;
|
|
hTmp->pNext = winList;
|
|
winList = hTmp;
|
|
}
|
|
if (fDisplay)
|
|
DrawWindow (hWnd, TRUE);
|
|
|
|
SetCursor ( hWnd, hWnd->crsrX, hWnd->crsrY );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* CloseWindow - remove a window from display.
|
|
*
|
|
* The only difficult part is to get each obscured window to redraw
|
|
* themselves when the specified window is removed. We first blank the
|
|
* window by redrawing (via WinOut) the window, determine the
|
|
* intersections of all windows lower in the pile than the selected one, and
|
|
* then calling their window procedures to paint the specified intersections.
|
|
*
|
|
* hWnd handle of window to close
|
|
*/
|
|
VOID PASCAL INTERNAL CloseWindow (HW hWnd)
|
|
{
|
|
HW hTmp;
|
|
BOX box;
|
|
INT i;
|
|
#ifdef NT
|
|
SMALL_RECT screenArea;
|
|
#endif
|
|
|
|
hTmp = hWnd->pNext;
|
|
BringToTop (hWnd, FALSE);
|
|
winList = winList->pNext;
|
|
|
|
#ifdef NT
|
|
//
|
|
// write whole screen as a block to the console for better performance
|
|
//
|
|
startScreenWrite ( );
|
|
#endif
|
|
|
|
BlankWindow (hWnd, FALSE);
|
|
|
|
#ifdef NT
|
|
screenArea.Left = ( SHORT ) hWnd->win.left;
|
|
screenArea.Top = ( SHORT ) hWnd->win.top;
|
|
screenArea.Right = ( SHORT ) hWnd->win.right;
|
|
screenArea.Bottom = (SHORT ) hWnd->win.bottom;
|
|
|
|
endScreenWrite ( &screenArea );
|
|
#endif NT
|
|
|
|
(*(hWnd->wndProc)) (hWnd, CLOSE, 0);
|
|
while (hTmp != NULL) {
|
|
GenClip (hTmp->win, hWnd->win, NULL, NULL, &box, &i);
|
|
if (i != 0)
|
|
DrawWindow (hTmp, TRUE);
|
|
hTmp = hTmp->pNext;
|
|
}
|
|
if (hWnd->pTitle != NULL)
|
|
ZMfree (hWnd->pTitle);
|
|
if (hWnd->pFooter != NULL)
|
|
ZMfree (hWnd->pFooter);
|
|
ZMfree (hWnd);
|
|
|
|
|
|
if (winList != NULL)
|
|
SetCursor ( winList, winList->crsrX, winList->crsrY );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* CloseAllWindows - remove everything from the display
|
|
* returns with winList empty.
|
|
*
|
|
* arguements:
|
|
* none
|
|
*
|
|
* return value:
|
|
* none
|
|
*
|
|
*/
|
|
VOID PASCAL INTERNAL CloseAllWindows (VOID)
|
|
{
|
|
HW hNextWnd = winList;
|
|
HW hWnd;
|
|
|
|
while ( hNextWnd != NULL )
|
|
{
|
|
hWnd = hNextWnd;
|
|
hNextWnd = hNextWnd->pNext;
|
|
CloseWindow ( hWnd );
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* ResizeWindow - change the size of a window, update pContent.
|
|
*
|
|
* arguments:
|
|
* hWnd handle to window to resize
|
|
* pBox pointer to box to check
|
|
*
|
|
* return value:
|
|
* returns TRUE if window needs repainting
|
|
*
|
|
* IMPORTANT :
|
|
* ResizeWindow does not update the screen.
|
|
*/
|
|
FLAG PASCAL INTERNAL ResizeWindow ( HW hWnd, PBOX pBox )
|
|
{
|
|
INT windSize = 0;
|
|
|
|
FitWinToScrn ( pBox );
|
|
if (hWnd->win.left == pBox->left && hWnd->win.right == pBox->right &&
|
|
hWnd->win.top == pBox->top && hWnd->win.bottom == pBox->bottom)
|
|
return FALSE;
|
|
|
|
hWnd->win = *pBox;
|
|
if (hWnd->pContent != NULL) {
|
|
windSize = TWINWIDTH (hWnd) * TWINHEIGHT (hWnd) * sizeof(CHAR);
|
|
if ( (UINT)windSize > hWnd->contSize ) {
|
|
PoolFree ( hWnd->pContent );
|
|
hWnd->pContent = PoolAlloc ( windSize );
|
|
hWnd->contSize = windSize;
|
|
}
|
|
SendMessage ( hWnd, REGENCONT, NULL );
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/* SetWindowText - change the title of a window
|
|
*
|
|
* hWnd window whose title is to be changed
|
|
* pTitle new title to be changed
|
|
*/
|
|
VOID PASCAL INTERNAL SetWindowText (HW hWnd, PSTR pTitle)
|
|
{
|
|
if (hWnd->pTitle != NULL)
|
|
ZMfree (hWnd->pTitle);
|
|
if (pTitle != NULL)
|
|
hWnd->pTitle = ZMMakeStr (pTitle);
|
|
else
|
|
hWnd->pTitle = NULL;
|
|
DisplayTitle (hWnd);
|
|
}
|
|
|
|
|
|
/* SetWindowFooter - change the footer of a window
|
|
*
|
|
* hWnd window whose footer is to be changed
|
|
* pFooter new footer to be changed
|
|
*/
|
|
VOID PASCAL INTERNAL SetWindowFooter (HW hWnd, PSTR pFooter)
|
|
{
|
|
if (hWnd->pFooter != NULL)
|
|
ZMfree (hWnd->pFooter);
|
|
if (pFooter != NULL)
|
|
hWnd->pFooter = ZMMakeStr (pFooter);
|
|
else
|
|
hWnd->pFooter = NULL;
|
|
DisplayFooter (hWnd);
|
|
}
|
|
|
|
|
|
|
|
/* SetRect - set up the coordinates of the given box
|
|
*
|
|
* arguments :
|
|
* pBox pointer to box to set up.
|
|
* top top coordinate of box.
|
|
* left left coordinate of box.
|
|
* bottom bottom coordinate of box.
|
|
* right right coordinate of box.
|
|
*
|
|
* return value :
|
|
* none.
|
|
*/
|
|
VOID PASCAL INTERNAL SetRect (PBOX pBox, INT top, INT left, INT bottom, INT right)
|
|
{
|
|
pBox->top = top;
|
|
pBox->left = left;
|
|
pBox->bottom = bottom;
|
|
pBox->right = right;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* KeyManager - intercept keystrokes and hand them to the active window
|
|
*
|
|
* We use the top of winList as the current input focus. All input is handed
|
|
* to the window procedure EXCEPT for the tab key. The tab key is responsible
|
|
* for placing the top window on the bottom of the stack to cycle through the
|
|
* set of windows.
|
|
*
|
|
*/
|
|
VOID PASCAL INTERNAL KeyManager (VOID)
|
|
{
|
|
LONG now;
|
|
#if defined (HEAPCRAP)
|
|
INT fHeapChk;
|
|
#endif
|
|
|
|
/* do script first in case in contains a password command
|
|
*/
|
|
if ( pInitScript )
|
|
DoScript ( hCommand, pInitScript, 0 );
|
|
|
|
if (fMailAllowed) {
|
|
GetAliases ( fNotifyTools & F_LOADALIAS );
|
|
fNotifyTools &= ~(FLAG)F_LOADALIAS;
|
|
NotifyTools ( );
|
|
}
|
|
if ( fComposeOnBoot )
|
|
( *( winList->wndProc ) ) ( winList, KEY, 0 );
|
|
|
|
SendMessage ( hCommand, DISPPROMPT, TRUE );
|
|
|
|
while ( ( winList != NULL ) && ( !fQuit ) ) {
|
|
time ( &now );
|
|
CheckTimeDisplay ( now );
|
|
|
|
if ( pInitHdrCmd ) {
|
|
DoHeaders ( hCommand, pInitHdrCmd, TRUE );
|
|
SendMessage ( hCommand, DISPPROMPT, 0 );
|
|
ZMfree ( pInitHdrCmd );
|
|
pInitHdrCmd = NULL;
|
|
}
|
|
|
|
/* if system has not received a char for 10 sec then checkmail
|
|
*/
|
|
if (fMailAllowed)
|
|
CheckMail ( now );
|
|
|
|
/* time out password after (default) 6 hours in case user has
|
|
* left WZMAIL running and gone home
|
|
*/
|
|
if ( now > lTmPassword + lPasswordAge )
|
|
ResetPassword ( );
|
|
|
|
if ( now > lTmConnect + cSecConnect )
|
|
ZMDisconnect ( );
|
|
|
|
/* On multitasking systems, it is rude to go into polling loops.
|
|
*
|
|
* For OS/2, we have a separate thread dedicated to reading from the
|
|
* console. We clear a semaphore to let him read and then wait on
|
|
* a response semaphore with the specified timeout. This avoids
|
|
* polling.
|
|
*
|
|
* For real mode DOS, we presume that INT 16 (poll) will cause an
|
|
* explicit yield to other runnable threads.
|
|
*/
|
|
if (kbwait (60 * 1000)) {
|
|
|
|
fMailUnSeen = FALSE;
|
|
|
|
do {
|
|
(*winList->wndProc) ( winList, KEY, ReadKey() );
|
|
|
|
} while (!fQuit && kbwait (10000));
|
|
}
|
|
|
|
#if defined (HEAPCRAP)
|
|
if ( ( fHeapChk = heapchk ( ) ) != HEAPOK ) {
|
|
fprintf ( stderr, "%s\n",
|
|
( fHeapChk == HEAPBADBEGIN ? "Can't find heap" :
|
|
"Damaged heap" ) );
|
|
assert ( fHeapChk == HEAPOK );
|
|
}
|
|
#endif
|
|
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
VOID PASCAL INTERNAL CheckTimeDisplay ( LONG lNow )
|
|
{
|
|
static INT minLast;
|
|
struct tm *ptmLocal = NULL;
|
|
PSTR p = NULL;
|
|
|
|
if ( lNow == -1L ) {
|
|
time ( &lNow );
|
|
minLast = -1;
|
|
}
|
|
ptmLocal = localtime ( &lNow );
|
|
if ( (hCommand != NULL) && (ptmLocal->tm_min != minLast) ) {
|
|
minLast = ptmLocal->tm_min;
|
|
p = asctime ( localtime ( &lNow ) );
|
|
WinOut ( hCommand, 2, 0, p, 16, DefNorm );
|
|
}
|
|
}
|
|
|
|
VOID PASCAL INTERNAL CheckMail ( LONG lNow )
|
|
{
|
|
FLAG fFirstTime = lTmLastMail == 0L;
|
|
INT idoc;
|
|
INT cMsg;
|
|
LONG lTemp;
|
|
PSTR p = NULL;
|
|
|
|
/* Don't do auto new mail
|
|
* if current folder is not default folder
|
|
* if wzmail invoked to compose a single message
|
|
* if user is typing a command
|
|
* if current folder is readonly
|
|
*/
|
|
if ( !fCurFldIsDefFld || fDirectComp || WindLevel != 0 || fReadOnlyCur )
|
|
return;
|
|
/* Do automail if fCheckMail or first time or
|
|
* (periodic checking and enough time has elapsed)
|
|
* For perf reasons, order of test is inverted
|
|
* Return if not fCheckMail if NOT first time &&
|
|
* (if not requested by user ( cSecNewmail == 0 => don't check ) or
|
|
* if not enough time elapsed )
|
|
*/
|
|
if ( !fCheckMail && !fFirstTime &&
|
|
( !cSecNewmail || ( lNow < lTmLastMail + cSecNewmail ) ) )
|
|
return;
|
|
|
|
fCheckMail = FALSE;
|
|
|
|
#if (defined (OS2) | defined (NT))
|
|
if (ISFULLSCREEN && ISVISIBLE)
|
|
|
|
#endif
|
|
{
|
|
SendMessage ( hCommand, DISPLAYSTR, "Checking mailbox ... " );
|
|
p = ZMMakeStr ( asctime ( localtime ( &lNow ) ) );
|
|
strcpy ( p+16, strBLANK );
|
|
SendMessage ( hCommand, DISPLAYSTR, p );
|
|
ZMfree ( p );
|
|
}
|
|
|
|
/* Don't let connection made by auto newmail keep lazy connection open
|
|
* DownloadMail updates lTmLastMail
|
|
* BUT ... the first time, allow lazy connection to be made on startup
|
|
*/
|
|
idoc = ( inoteBold != -1 ? mpInoteIdoc [ inoteBold ] : -1 );
|
|
|
|
if ( !fFirstTime )
|
|
lTemp = lTmConnect;
|
|
cMsg = DownloadMail (FALSE);
|
|
if ( !fFirstTime )
|
|
lTmConnect = lTemp;
|
|
Disconnect ( );
|
|
|
|
|
|
#if (defined (OS2) | defined (NT))
|
|
if (cMsg || (ISFULLSCREEN && ISVISIBLE))
|
|
#endif
|
|
SendMessage ( hCommand, CLRCMDLN, 0 );
|
|
|
|
/* if first time, then find the first unread message
|
|
* else don't change the "current" message
|
|
*/
|
|
if ( fFirstTime ) {
|
|
if ( ( idoc = NextUnread ( -1 ) ) != -1 )
|
|
SendMessage ( hHeaders, GOTOIDOCALL, idoc );
|
|
}
|
|
else {
|
|
if ( idoc != -1 )
|
|
SendMessage ( hHeaders, GOTOIDOCALL, idoc );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Bell - make some noise
|
|
*/
|
|
VOID PASCAL INTERNAL Bell (VOID)
|
|
{
|
|
write (1, "\x07", 1);
|
|
}
|
|
|
|
|
|
|
|
/* SetCursor - place the visible cursor in some window
|
|
*
|
|
* hWnd window for cursor
|
|
* x, y location of cursor in window
|
|
*/
|
|
VOID PASCAL INTERNAL SetCursor (HW hWnd, INT x, INT y)
|
|
{
|
|
if (!TESTFLAG (hWnd->fsFlag, WF_BLINK))
|
|
/* move cursor off screen
|
|
*/
|
|
#ifdef NT
|
|
cursorInvisible ();
|
|
#else
|
|
cursor ( xSize + 1, ySize + 1 );
|
|
#endif
|
|
else
|
|
if (INRANGE (0, x, TWINWIDTH (hWnd)) && INRANGE (0, y, TWINHEIGHT (hWnd))) {
|
|
cursorVisible ();
|
|
cursor (x + hWnd->lLeft + hWnd->win.left, y + 1 + hWnd->win.top);
|
|
}
|
|
}
|
|
|
|
|
|
/* ShowCursor - place the visible cursor in some window
|
|
*
|
|
* hWnd window for cursor
|
|
* fBlink TRUE -> blinking cursor, FALSE no cursor
|
|
*/
|
|
VOID PASCAL INTERNAL ShowCursor (HW hWnd, FLAG fBlink )
|
|
{
|
|
|
|
RSETFLAG (hWnd->fsFlag, WF_BLINK);
|
|
if (fBlink)
|
|
SETFLAG (hWnd->fsFlag, WF_BLINK);
|
|
if ( winList == hWnd )
|
|
{
|
|
SetCursor ( hWnd, hWnd->crsrX, hWnd->crsrY );
|
|
#ifdef NT
|
|
if (fBlink)
|
|
{
|
|
cursorVisible ();
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* RedrawScreen - blank the screen and redraw all windows in the pile.
|
|
*/
|
|
VOID PASCAL INTERNAL RedrawScreen (VOID)
|
|
{
|
|
HW hWnd = winList;
|
|
|
|
// ClearScrn ( DefNorm, ySize );
|
|
do {
|
|
DrawWindow ( hWnd, TRUE );
|
|
hWnd = hWnd->pNext;
|
|
} while ( hWnd != NULL );
|
|
|
|
SetCursor ( winList, winList->crsrX, winList->crsrY );
|
|
return;
|
|
}
|
|
|
|
|
|
VOID PASCAL INTERNAL FreeContents (VOID)
|
|
{
|
|
HW hWnd;
|
|
|
|
for (hWnd = winList; hWnd != NULL; hWnd = hWnd->pNext)
|
|
if (!TESTFLAG (hWnd->fsFlag, WF_NODISCARD) && hWnd->pContent != NULL) {
|
|
PoolFree(hWnd->pContent);
|
|
hWnd->pContent = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
VOID PASCAL INTERNAL RestoreContents (VOID)
|
|
{
|
|
HW hWnd;
|
|
|
|
for (hWnd = winList; hWnd != NULL; hWnd = hWnd->pNext)
|
|
if ((hWnd->pContent == NULL) && (hWnd->contSize > 0))
|
|
if (hWnd->pContent = PoolAlloc(hWnd->contSize))
|
|
SendMessage ( hWnd, REGENCONT, NULL );
|
|
else {
|
|
ZMDisconnect();
|
|
ZMexit(-1, "Out of memory for window buffers\n");
|
|
}
|
|
}
|